1 /* 2 * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> 3 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * for more details. 14 */ 15 #include <linux/export.h> 16 #include <linux/types.h> 17 #include <linux/errno.h> 18 #include <linux/io.h> 19 20 #include <video/imx-ipu-v3.h> 21 #include "ipu-prv.h" 22 23 #define DMFC_RD_CHAN 0x0000 24 #define DMFC_WR_CHAN 0x0004 25 #define DMFC_WR_CHAN_DEF 0x0008 26 #define DMFC_DP_CHAN 0x000c 27 #define DMFC_DP_CHAN_DEF 0x0010 28 #define DMFC_GENERAL1 0x0014 29 #define DMFC_GENERAL2 0x0018 30 #define DMFC_IC_CTRL 0x001c 31 #define DMFC_WR_CHAN_ALT 0x0020 32 #define DMFC_WR_CHAN_DEF_ALT 0x0024 33 #define DMFC_DP_CHAN_ALT 0x0028 34 #define DMFC_DP_CHAN_DEF_ALT 0x002c 35 #define DMFC_GENERAL1_ALT 0x0030 36 #define DMFC_STAT 0x0034 37 38 #define DMFC_WR_CHAN_1_28 0 39 #define DMFC_WR_CHAN_2_41 8 40 #define DMFC_WR_CHAN_1C_42 16 41 #define DMFC_WR_CHAN_2C_43 24 42 43 #define DMFC_DP_CHAN_5B_23 0 44 #define DMFC_DP_CHAN_5F_27 8 45 #define DMFC_DP_CHAN_6B_24 16 46 #define DMFC_DP_CHAN_6F_29 24 47 48 struct dmfc_channel_data { 49 int ipu_channel; 50 unsigned long channel_reg; 51 unsigned long shift; 52 unsigned eot_shift; 53 unsigned max_fifo_lines; 54 }; 55 56 static const struct dmfc_channel_data dmfcdata[] = { 57 { 58 .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC, 59 .channel_reg = DMFC_DP_CHAN, 60 .shift = DMFC_DP_CHAN_5B_23, 61 .eot_shift = 20, 62 .max_fifo_lines = 3, 63 }, { 64 .ipu_channel = 24, 65 .channel_reg = DMFC_DP_CHAN, 66 .shift = DMFC_DP_CHAN_6B_24, 67 .eot_shift = 22, 68 .max_fifo_lines = 1, 69 }, { 70 .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC, 71 .channel_reg = DMFC_DP_CHAN, 72 .shift = DMFC_DP_CHAN_5F_27, 73 .eot_shift = 21, 74 .max_fifo_lines = 2, 75 }, { 76 .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC, 77 .channel_reg = DMFC_WR_CHAN, 78 .shift = DMFC_WR_CHAN_1_28, 79 .eot_shift = 16, 80 .max_fifo_lines = 2, 81 }, { 82 .ipu_channel = 29, 83 .channel_reg = DMFC_DP_CHAN, 84 .shift = DMFC_DP_CHAN_6F_29, 85 .eot_shift = 23, 86 .max_fifo_lines = 1, 87 }, 88 }; 89 90 #define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata) 91 92 struct ipu_dmfc_priv; 93 94 struct dmfc_channel { 95 unsigned slots; 96 struct ipu_soc *ipu; 97 struct ipu_dmfc_priv *priv; 98 const struct dmfc_channel_data *data; 99 }; 100 101 struct ipu_dmfc_priv { 102 struct ipu_soc *ipu; 103 struct device *dev; 104 struct dmfc_channel channels[DMFC_NUM_CHANNELS]; 105 struct mutex mutex; 106 void __iomem *base; 107 int use_count; 108 }; 109 110 int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) 111 { 112 struct ipu_dmfc_priv *priv = dmfc->priv; 113 mutex_lock(&priv->mutex); 114 115 if (!priv->use_count) 116 ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN); 117 118 priv->use_count++; 119 120 mutex_unlock(&priv->mutex); 121 122 return 0; 123 } 124 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); 125 126 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) 127 { 128 struct ipu_dmfc_priv *priv = dmfc->priv; 129 130 mutex_lock(&priv->mutex); 131 132 priv->use_count--; 133 134 if (!priv->use_count) 135 ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); 136 137 if (priv->use_count < 0) 138 priv->use_count = 0; 139 140 mutex_unlock(&priv->mutex); 141 } 142 EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); 143 144 void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width) 145 { 146 struct ipu_dmfc_priv *priv = dmfc->priv; 147 u32 dmfc_gen1; 148 149 mutex_lock(&priv->mutex); 150 151 dmfc_gen1 = readl(priv->base + DMFC_GENERAL1); 152 153 if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines) 154 dmfc_gen1 |= 1 << dmfc->data->eot_shift; 155 else 156 dmfc_gen1 &= ~(1 << dmfc->data->eot_shift); 157 158 writel(dmfc_gen1, priv->base + DMFC_GENERAL1); 159 160 mutex_unlock(&priv->mutex); 161 } 162 EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot); 163 164 struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel) 165 { 166 struct ipu_dmfc_priv *priv = ipu->dmfc_priv; 167 int i; 168 169 for (i = 0; i < DMFC_NUM_CHANNELS; i++) 170 if (dmfcdata[i].ipu_channel == ipu_channel) 171 return &priv->channels[i]; 172 return ERR_PTR(-ENODEV); 173 } 174 EXPORT_SYMBOL_GPL(ipu_dmfc_get); 175 176 void ipu_dmfc_put(struct dmfc_channel *dmfc) 177 { 178 } 179 EXPORT_SYMBOL_GPL(ipu_dmfc_put); 180 181 int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, 182 struct clk *ipu_clk) 183 { 184 struct ipu_dmfc_priv *priv; 185 int i; 186 187 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 188 if (!priv) 189 return -ENOMEM; 190 191 priv->base = devm_ioremap(dev, base, PAGE_SIZE); 192 if (!priv->base) 193 return -ENOMEM; 194 195 priv->dev = dev; 196 priv->ipu = ipu; 197 mutex_init(&priv->mutex); 198 199 ipu->dmfc_priv = priv; 200 201 for (i = 0; i < DMFC_NUM_CHANNELS; i++) { 202 priv->channels[i].priv = priv; 203 priv->channels[i].ipu = ipu; 204 priv->channels[i].data = &dmfcdata[i]; 205 206 if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC || 207 dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC || 208 dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC) 209 priv->channels[i].slots = 2; 210 } 211 212 writel(0x00000050, priv->base + DMFC_WR_CHAN); 213 writel(0x00005654, priv->base + DMFC_DP_CHAN); 214 writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); 215 writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); 216 writel(0x00000003, priv->base + DMFC_GENERAL1); 217 218 return 0; 219 } 220 221 void ipu_dmfc_exit(struct ipu_soc *ipu) 222 { 223 } 224