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