0001
0002
0003
0004
0005
0006 #include <linux/export.h>
0007 #include <linux/types.h>
0008 #include <linux/errno.h>
0009 #include <linux/io.h>
0010
0011 #include <video/imx-ipu-v3.h>
0012 #include "ipu-prv.h"
0013
0014 #define DMFC_RD_CHAN 0x0000
0015 #define DMFC_WR_CHAN 0x0004
0016 #define DMFC_WR_CHAN_DEF 0x0008
0017 #define DMFC_DP_CHAN 0x000c
0018 #define DMFC_DP_CHAN_DEF 0x0010
0019 #define DMFC_GENERAL1 0x0014
0020 #define DMFC_GENERAL2 0x0018
0021 #define DMFC_IC_CTRL 0x001c
0022 #define DMFC_WR_CHAN_ALT 0x0020
0023 #define DMFC_WR_CHAN_DEF_ALT 0x0024
0024 #define DMFC_DP_CHAN_ALT 0x0028
0025 #define DMFC_DP_CHAN_DEF_ALT 0x002c
0026 #define DMFC_GENERAL1_ALT 0x0030
0027 #define DMFC_STAT 0x0034
0028
0029 #define DMFC_WR_CHAN_1_28 0
0030 #define DMFC_WR_CHAN_2_41 8
0031 #define DMFC_WR_CHAN_1C_42 16
0032 #define DMFC_WR_CHAN_2C_43 24
0033
0034 #define DMFC_DP_CHAN_5B_23 0
0035 #define DMFC_DP_CHAN_5F_27 8
0036 #define DMFC_DP_CHAN_6B_24 16
0037 #define DMFC_DP_CHAN_6F_29 24
0038
0039 struct dmfc_channel_data {
0040 int ipu_channel;
0041 unsigned long channel_reg;
0042 unsigned long shift;
0043 unsigned eot_shift;
0044 unsigned max_fifo_lines;
0045 };
0046
0047 static const struct dmfc_channel_data dmfcdata[] = {
0048 {
0049 .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
0050 .channel_reg = DMFC_DP_CHAN,
0051 .shift = DMFC_DP_CHAN_5B_23,
0052 .eot_shift = 20,
0053 .max_fifo_lines = 3,
0054 }, {
0055 .ipu_channel = 24,
0056 .channel_reg = DMFC_DP_CHAN,
0057 .shift = DMFC_DP_CHAN_6B_24,
0058 .eot_shift = 22,
0059 .max_fifo_lines = 1,
0060 }, {
0061 .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
0062 .channel_reg = DMFC_DP_CHAN,
0063 .shift = DMFC_DP_CHAN_5F_27,
0064 .eot_shift = 21,
0065 .max_fifo_lines = 2,
0066 }, {
0067 .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
0068 .channel_reg = DMFC_WR_CHAN,
0069 .shift = DMFC_WR_CHAN_1_28,
0070 .eot_shift = 16,
0071 .max_fifo_lines = 2,
0072 }, {
0073 .ipu_channel = 29,
0074 .channel_reg = DMFC_DP_CHAN,
0075 .shift = DMFC_DP_CHAN_6F_29,
0076 .eot_shift = 23,
0077 .max_fifo_lines = 1,
0078 },
0079 };
0080
0081 #define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
0082
0083 struct ipu_dmfc_priv;
0084
0085 struct dmfc_channel {
0086 unsigned slots;
0087 struct ipu_soc *ipu;
0088 struct ipu_dmfc_priv *priv;
0089 const struct dmfc_channel_data *data;
0090 };
0091
0092 struct ipu_dmfc_priv {
0093 struct ipu_soc *ipu;
0094 struct device *dev;
0095 struct dmfc_channel channels[DMFC_NUM_CHANNELS];
0096 struct mutex mutex;
0097 void __iomem *base;
0098 int use_count;
0099 };
0100
0101 int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
0102 {
0103 struct ipu_dmfc_priv *priv = dmfc->priv;
0104 mutex_lock(&priv->mutex);
0105
0106 if (!priv->use_count)
0107 ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
0108
0109 priv->use_count++;
0110
0111 mutex_unlock(&priv->mutex);
0112
0113 return 0;
0114 }
0115 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
0116
0117 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
0118 {
0119 struct ipu_dmfc_priv *priv = dmfc->priv;
0120
0121 mutex_lock(&priv->mutex);
0122
0123 priv->use_count--;
0124
0125 if (!priv->use_count)
0126 ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
0127
0128 if (priv->use_count < 0)
0129 priv->use_count = 0;
0130
0131 mutex_unlock(&priv->mutex);
0132 }
0133 EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
0134
0135 void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
0136 {
0137 struct ipu_dmfc_priv *priv = dmfc->priv;
0138 u32 dmfc_gen1;
0139
0140 mutex_lock(&priv->mutex);
0141
0142 dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
0143
0144 if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
0145 dmfc_gen1 |= 1 << dmfc->data->eot_shift;
0146 else
0147 dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
0148
0149 writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
0150
0151 mutex_unlock(&priv->mutex);
0152 }
0153 EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
0154
0155 struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
0156 {
0157 struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
0158 int i;
0159
0160 for (i = 0; i < DMFC_NUM_CHANNELS; i++)
0161 if (dmfcdata[i].ipu_channel == ipu_channel)
0162 return &priv->channels[i];
0163 return ERR_PTR(-ENODEV);
0164 }
0165 EXPORT_SYMBOL_GPL(ipu_dmfc_get);
0166
0167 void ipu_dmfc_put(struct dmfc_channel *dmfc)
0168 {
0169 }
0170 EXPORT_SYMBOL_GPL(ipu_dmfc_put);
0171
0172 int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
0173 struct clk *ipu_clk)
0174 {
0175 struct ipu_dmfc_priv *priv;
0176 int i;
0177
0178 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0179 if (!priv)
0180 return -ENOMEM;
0181
0182 priv->base = devm_ioremap(dev, base, PAGE_SIZE);
0183 if (!priv->base)
0184 return -ENOMEM;
0185
0186 priv->dev = dev;
0187 priv->ipu = ipu;
0188 mutex_init(&priv->mutex);
0189
0190 ipu->dmfc_priv = priv;
0191
0192 for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
0193 priv->channels[i].priv = priv;
0194 priv->channels[i].ipu = ipu;
0195 priv->channels[i].data = &dmfcdata[i];
0196
0197 if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
0198 dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
0199 dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
0200 priv->channels[i].slots = 2;
0201 }
0202
0203 writel(0x00000050, priv->base + DMFC_WR_CHAN);
0204 writel(0x00005654, priv->base + DMFC_DP_CHAN);
0205 writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
0206 writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
0207 writel(0x00000003, priv->base + DMFC_GENERAL1);
0208
0209 return 0;
0210 }
0211
0212 void ipu_dmfc_exit(struct ipu_soc *ipu)
0213 {
0214 }