0001
0002
0003
0004
0005
0006
0007 #include <linux/export.h>
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/delay.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/io.h>
0014
0015 #include <video/imx-ipu-v3.h>
0016 #include "ipu-prv.h"
0017
0018 #define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
0019 #define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
0020
0021 #define DC_EVT_NF 0
0022 #define DC_EVT_NL 1
0023 #define DC_EVT_EOF 2
0024 #define DC_EVT_NFIELD 3
0025 #define DC_EVT_EOL 4
0026 #define DC_EVT_EOFIELD 5
0027 #define DC_EVT_NEW_ADDR 6
0028 #define DC_EVT_NEW_CHAN 7
0029 #define DC_EVT_NEW_DATA 8
0030
0031 #define DC_EVT_NEW_ADDR_W_0 0
0032 #define DC_EVT_NEW_ADDR_W_1 1
0033 #define DC_EVT_NEW_CHAN_W_0 2
0034 #define DC_EVT_NEW_CHAN_W_1 3
0035 #define DC_EVT_NEW_DATA_W_0 4
0036 #define DC_EVT_NEW_DATA_W_1 5
0037 #define DC_EVT_NEW_ADDR_R_0 6
0038 #define DC_EVT_NEW_ADDR_R_1 7
0039 #define DC_EVT_NEW_CHAN_R_0 8
0040 #define DC_EVT_NEW_CHAN_R_1 9
0041 #define DC_EVT_NEW_DATA_R_0 10
0042 #define DC_EVT_NEW_DATA_R_1 11
0043
0044 #define DC_WR_CH_CONF 0x0
0045 #define DC_WR_CH_ADDR 0x4
0046 #define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
0047
0048 #define DC_GEN 0xd4
0049 #define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
0050 #define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
0051 #define DC_STAT 0x1c8
0052
0053 #define WROD(lf) (0x18 | ((lf) << 1))
0054 #define WRG 0x01
0055 #define WCLK 0xc9
0056
0057 #define SYNC_WAVE 0
0058 #define NULL_WAVE (-1)
0059
0060 #define DC_GEN_SYNC_1_6_SYNC (2 << 1)
0061 #define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
0062
0063 #define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
0064 #define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
0065 #define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
0066 #define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
0067 #define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
0068 #define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
0069 #define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
0070 #define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
0071 #define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
0072 #define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
0073 #define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
0074 #define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
0075
0076 #define IPU_DC_NUM_CHANNELS 10
0077
0078 struct ipu_dc_priv;
0079
0080 enum ipu_dc_map {
0081 IPU_DC_MAP_RGB24,
0082 IPU_DC_MAP_RGB565,
0083 IPU_DC_MAP_GBR24,
0084 IPU_DC_MAP_BGR666,
0085 IPU_DC_MAP_LVDS666,
0086 IPU_DC_MAP_BGR24,
0087 };
0088
0089 struct ipu_dc {
0090
0091 unsigned int di;
0092 void __iomem *base;
0093 struct ipu_dc_priv *priv;
0094 int chno;
0095 bool in_use;
0096 };
0097
0098 struct ipu_dc_priv {
0099 void __iomem *dc_reg;
0100 void __iomem *dc_tmpl_reg;
0101 struct ipu_soc *ipu;
0102 struct device *dev;
0103 struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
0104 struct mutex mutex;
0105 struct completion comp;
0106 int use_count;
0107 };
0108
0109 static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
0110 {
0111 u32 reg;
0112
0113 reg = readl(dc->base + DC_RL_CH(event));
0114 reg &= ~(0xffff << (16 * (event & 0x1)));
0115 reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
0116 writel(reg, dc->base + DC_RL_CH(event));
0117 }
0118
0119 static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
0120 int map, int wave, int glue, int sync, int stop)
0121 {
0122 struct ipu_dc_priv *priv = dc->priv;
0123 u32 reg1, reg2;
0124
0125 if (opcode == WCLK) {
0126 reg1 = (operand << 20) & 0xfff00000;
0127 reg2 = operand >> 12 | opcode << 1 | stop << 9;
0128 } else if (opcode == WRG) {
0129 reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
0130 reg2 = operand >> 17 | opcode << 7 | stop << 9;
0131 } else {
0132 reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
0133 reg2 = operand >> 12 | opcode << 4 | stop << 9;
0134 }
0135 writel(reg1, priv->dc_tmpl_reg + word * 8);
0136 writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
0137 }
0138
0139 static int ipu_bus_format_to_map(u32 fmt)
0140 {
0141 switch (fmt) {
0142 default:
0143 WARN_ON(1);
0144 fallthrough;
0145 case MEDIA_BUS_FMT_RGB888_1X24:
0146 return IPU_DC_MAP_RGB24;
0147 case MEDIA_BUS_FMT_RGB565_1X16:
0148 return IPU_DC_MAP_RGB565;
0149 case MEDIA_BUS_FMT_GBR888_1X24:
0150 return IPU_DC_MAP_GBR24;
0151 case MEDIA_BUS_FMT_RGB666_1X18:
0152 return IPU_DC_MAP_BGR666;
0153 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
0154 return IPU_DC_MAP_LVDS666;
0155 case MEDIA_BUS_FMT_BGR888_1X24:
0156 return IPU_DC_MAP_BGR24;
0157 }
0158 }
0159
0160 int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
0161 u32 bus_format, u32 width)
0162 {
0163 struct ipu_dc_priv *priv = dc->priv;
0164 int addr, sync;
0165 u32 reg = 0;
0166 int map;
0167
0168 dc->di = ipu_di_get_num(di);
0169
0170 if (!IS_ALIGNED(width, 8)) {
0171 dev_warn(priv->dev,
0172 "%s: hactive does not align to 8 byte\n", __func__);
0173 }
0174
0175 map = ipu_bus_format_to_map(bus_format);
0176
0177
0178
0179
0180
0181
0182
0183 sync = interlaced ? 6 : 5;
0184
0185
0186 if (dc->di)
0187 addr = 5;
0188 else
0189 addr = 0;
0190
0191 if (interlaced) {
0192 dc_link_event(dc, DC_EVT_NL, addr, 3);
0193 dc_link_event(dc, DC_EVT_EOL, addr, 2);
0194 dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
0195
0196
0197 dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
0198 } else {
0199 dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
0200 dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
0201 dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
0202
0203
0204 dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
0205 dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
0206 dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
0207 dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
0208 }
0209
0210 dc_link_event(dc, DC_EVT_NF, 0, 0);
0211 dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
0212 dc_link_event(dc, DC_EVT_EOF, 0, 0);
0213 dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
0214 dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
0215 dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
0216
0217 reg = readl(dc->base + DC_WR_CH_CONF);
0218 if (interlaced)
0219 reg |= DC_WR_CH_CONF_FIELD_MODE;
0220 else
0221 reg &= ~DC_WR_CH_CONF_FIELD_MODE;
0222 writel(reg, dc->base + DC_WR_CH_CONF);
0223
0224 writel(0x0, dc->base + DC_WR_CH_ADDR);
0225 writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
0226
0227 return 0;
0228 }
0229 EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
0230
0231 void ipu_dc_enable(struct ipu_soc *ipu)
0232 {
0233 struct ipu_dc_priv *priv = ipu->dc_priv;
0234
0235 mutex_lock(&priv->mutex);
0236
0237 if (!priv->use_count)
0238 ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
0239
0240 priv->use_count++;
0241
0242 mutex_unlock(&priv->mutex);
0243 }
0244 EXPORT_SYMBOL_GPL(ipu_dc_enable);
0245
0246 void ipu_dc_enable_channel(struct ipu_dc *dc)
0247 {
0248 u32 reg;
0249
0250 reg = readl(dc->base + DC_WR_CH_CONF);
0251 reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
0252 writel(reg, dc->base + DC_WR_CH_CONF);
0253 }
0254 EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
0255
0256 void ipu_dc_disable_channel(struct ipu_dc *dc)
0257 {
0258 u32 val;
0259
0260 val = readl(dc->base + DC_WR_CH_CONF);
0261 val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
0262 writel(val, dc->base + DC_WR_CH_CONF);
0263 }
0264 EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
0265
0266 void ipu_dc_disable(struct ipu_soc *ipu)
0267 {
0268 struct ipu_dc_priv *priv = ipu->dc_priv;
0269
0270 mutex_lock(&priv->mutex);
0271
0272 priv->use_count--;
0273 if (!priv->use_count)
0274 ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
0275
0276 if (priv->use_count < 0)
0277 priv->use_count = 0;
0278
0279 mutex_unlock(&priv->mutex);
0280 }
0281 EXPORT_SYMBOL_GPL(ipu_dc_disable);
0282
0283 static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
0284 int byte_num, int offset, int mask)
0285 {
0286 int ptr = map * 3 + byte_num;
0287 u32 reg;
0288
0289 reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
0290 reg &= ~(0xffff << (16 * (ptr & 0x1)));
0291 reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
0292 writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
0293
0294 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
0295 reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
0296 reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
0297 writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
0298 }
0299
0300 static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
0301 {
0302 u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
0303
0304 writel(reg & ~(0xffff << (16 * (map & 0x1))),
0305 priv->dc_reg + DC_MAP_CONF_PTR(map));
0306 }
0307
0308 struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
0309 {
0310 struct ipu_dc_priv *priv = ipu->dc_priv;
0311 struct ipu_dc *dc;
0312
0313 if (channel >= IPU_DC_NUM_CHANNELS)
0314 return ERR_PTR(-ENODEV);
0315
0316 dc = &priv->channels[channel];
0317
0318 mutex_lock(&priv->mutex);
0319
0320 if (dc->in_use) {
0321 mutex_unlock(&priv->mutex);
0322 return ERR_PTR(-EBUSY);
0323 }
0324
0325 dc->in_use = true;
0326
0327 mutex_unlock(&priv->mutex);
0328
0329 return dc;
0330 }
0331 EXPORT_SYMBOL_GPL(ipu_dc_get);
0332
0333 void ipu_dc_put(struct ipu_dc *dc)
0334 {
0335 struct ipu_dc_priv *priv = dc->priv;
0336
0337 mutex_lock(&priv->mutex);
0338 dc->in_use = false;
0339 mutex_unlock(&priv->mutex);
0340 }
0341 EXPORT_SYMBOL_GPL(ipu_dc_put);
0342
0343 int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
0344 unsigned long base, unsigned long template_base)
0345 {
0346 struct ipu_dc_priv *priv;
0347 static const int channel_offsets[] = {
0348 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, 0x78, 0, 0x94, 0xb4
0349 };
0350 int i;
0351
0352 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0353 if (!priv)
0354 return -ENOMEM;
0355
0356 mutex_init(&priv->mutex);
0357
0358 priv->dev = dev;
0359 priv->ipu = ipu;
0360 priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
0361 priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
0362 if (!priv->dc_reg || !priv->dc_tmpl_reg)
0363 return -ENOMEM;
0364
0365 for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
0366 priv->channels[i].chno = i;
0367 priv->channels[i].priv = priv;
0368 priv->channels[i].base = priv->dc_reg + channel_offsets[i];
0369 }
0370
0371 writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
0372 DC_WR_CH_CONF_PROG_DI_ID,
0373 priv->channels[1].base + DC_WR_CH_CONF);
0374 writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
0375 priv->channels[5].base + DC_WR_CH_CONF);
0376
0377 writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
0378 priv->dc_reg + DC_GEN);
0379
0380 ipu->dc_priv = priv;
0381
0382 dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
0383 base, template_base);
0384
0385
0386 ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
0387 ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff);
0388 ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff);
0389 ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff);
0390
0391
0392 ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
0393 ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8);
0394 ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc);
0395 ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8);
0396
0397
0398 ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
0399 ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff);
0400 ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff);
0401 ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff);
0402
0403
0404 ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
0405 ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc);
0406 ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc);
0407 ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc);
0408
0409
0410 ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
0411 ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc);
0412 ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc);
0413 ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc);
0414
0415
0416 ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
0417 ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff);
0418 ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff);
0419 ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff);
0420
0421 return 0;
0422 }
0423
0424 void ipu_dc_exit(struct ipu_soc *ipu)
0425 {
0426 }