0001
0002
0003
0004
0005
0006 #include <linux/export.h>
0007 #include <linux/module.h>
0008 #include <linux/types.h>
0009 #include <linux/errno.h>
0010 #include <linux/io.h>
0011 #include <linux/err.h>
0012 #include <linux/platform_device.h>
0013
0014 #include <video/imx-ipu-v3.h>
0015 #include "ipu-prv.h"
0016
0017 struct ipu_di {
0018 void __iomem *base;
0019 int id;
0020 u32 module;
0021 struct clk *clk_di;
0022 struct clk *clk_ipu;
0023 struct clk *clk_di_pixel;
0024 bool inuse;
0025 struct ipu_soc *ipu;
0026 };
0027
0028 static DEFINE_MUTEX(di_mutex);
0029
0030 struct di_sync_config {
0031 int run_count;
0032 int run_src;
0033 int offset_count;
0034 int offset_src;
0035 int repeat_count;
0036 int cnt_clr_src;
0037 int cnt_polarity_gen_en;
0038 int cnt_polarity_clr_src;
0039 int cnt_polarity_trigger_src;
0040 int cnt_up;
0041 int cnt_down;
0042 };
0043
0044 enum di_pins {
0045 DI_PIN11 = 0,
0046 DI_PIN12 = 1,
0047 DI_PIN13 = 2,
0048 DI_PIN14 = 3,
0049 DI_PIN15 = 4,
0050 DI_PIN16 = 5,
0051 DI_PIN17 = 6,
0052 DI_PIN_CS = 7,
0053
0054 DI_PIN_SER_CLK = 0,
0055 DI_PIN_SER_RS = 1,
0056 };
0057
0058 enum di_sync_wave {
0059 DI_SYNC_NONE = 0,
0060 DI_SYNC_CLK = 1,
0061 DI_SYNC_INT_HSYNC = 2,
0062 DI_SYNC_HSYNC = 3,
0063 DI_SYNC_VSYNC = 4,
0064 DI_SYNC_DE = 6,
0065
0066 DI_SYNC_CNT1 = 2,
0067 DI_SYNC_CNT4 = 5,
0068 DI_SYNC_CNT5 = 6,
0069 };
0070
0071 #define SYNC_WAVE 0
0072
0073 #define DI_GENERAL 0x0000
0074 #define DI_BS_CLKGEN0 0x0004
0075 #define DI_BS_CLKGEN1 0x0008
0076 #define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
0077 #define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
0078 #define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
0079 #define DI_SYNC_AS_GEN 0x0054
0080 #define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
0081 #define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
0082 #define DI_SER_CONF 0x015c
0083 #define DI_SSC 0x0160
0084 #define DI_POL 0x0164
0085 #define DI_AW0 0x0168
0086 #define DI_AW1 0x016c
0087 #define DI_SCR_CONF 0x0170
0088 #define DI_STAT 0x0174
0089
0090 #define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
0091 #define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
0092 #define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
0093 #define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
0094
0095 #define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
0096 #define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
0097 #define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
0098 #define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
0099 #define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
0100 #define DI_SW_GEN1_CNT_UP(x) (x)
0101 #define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
0102
0103 #define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
0104 #define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
0105
0106 #define DI_GEN_POLARITY_1 (1 << 0)
0107 #define DI_GEN_POLARITY_2 (1 << 1)
0108 #define DI_GEN_POLARITY_3 (1 << 2)
0109 #define DI_GEN_POLARITY_4 (1 << 3)
0110 #define DI_GEN_POLARITY_5 (1 << 4)
0111 #define DI_GEN_POLARITY_6 (1 << 5)
0112 #define DI_GEN_POLARITY_7 (1 << 6)
0113 #define DI_GEN_POLARITY_8 (1 << 7)
0114 #define DI_GEN_POLARITY_DISP_CLK (1 << 17)
0115 #define DI_GEN_DI_CLK_EXT (1 << 20)
0116 #define DI_GEN_DI_VSYNC_EXT (1 << 21)
0117
0118 #define DI_POL_DRDY_DATA_POLARITY (1 << 7)
0119 #define DI_POL_DRDY_POLARITY_15 (1 << 4)
0120
0121 #define DI_VSYNC_SEL_OFFSET 13
0122
0123 static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
0124 {
0125 return readl(di->base + offset);
0126 }
0127
0128 static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
0129 {
0130 writel(value, di->base + offset);
0131 }
0132
0133 static void ipu_di_data_wave_config(struct ipu_di *di,
0134 int wave_gen,
0135 int access_size, int component_size)
0136 {
0137 u32 reg;
0138 reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
0139 (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
0140 ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
0141 }
0142
0143 static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
0144 int set, int up, int down)
0145 {
0146 u32 reg;
0147
0148 reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
0149 reg &= ~(0x3 << (di_pin * 2));
0150 reg |= set << (di_pin * 2);
0151 ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
0152
0153 ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
0154 }
0155
0156 static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
0157 int start, int count)
0158 {
0159 u32 reg;
0160 int i;
0161
0162 for (i = 0; i < count; i++) {
0163 struct di_sync_config *c = &config[i];
0164 int wave_gen = start + i + 1;
0165
0166 if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
0167 (c->repeat_count >= 0x1000) ||
0168 (c->cnt_up >= 0x400) ||
0169 (c->cnt_down >= 0x400)) {
0170 dev_err(di->ipu->dev, "DI%d counters out of range.\n",
0171 di->id);
0172 return;
0173 }
0174
0175 reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
0176 DI_SW_GEN0_RUN_SRC(c->run_src) |
0177 DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
0178 DI_SW_GEN0_OFFSET_SRC(c->offset_src);
0179 ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
0180
0181 reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
0182 DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
0183 DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
0184 c->cnt_polarity_trigger_src) |
0185 DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
0186 DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
0187 DI_SW_GEN1_CNT_UP(c->cnt_up);
0188
0189
0190 if (c->repeat_count == 0)
0191 reg |= DI_SW_GEN1_AUTO_RELOAD;
0192
0193 ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
0194
0195 reg = ipu_di_read(di, DI_STP_REP(wave_gen));
0196 reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
0197 reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
0198 ipu_di_write(di, reg, DI_STP_REP(wave_gen));
0199 }
0200 }
0201
0202 static void ipu_di_sync_config_interlaced(struct ipu_di *di,
0203 struct ipu_di_signal_cfg *sig)
0204 {
0205 u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
0206 sig->mode.hback_porch + sig->mode.hfront_porch;
0207 u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
0208 sig->mode.vback_porch + sig->mode.vfront_porch;
0209 struct di_sync_config cfg[] = {
0210 {
0211
0212 .run_count = v_total * 2 - 1,
0213 .run_src = 3,
0214 }, {
0215
0216 .run_count = h_total - 1,
0217 .run_src = DI_SYNC_CLK,
0218 .cnt_polarity_gen_en = 1,
0219 .cnt_polarity_trigger_src = DI_SYNC_CLK,
0220 .cnt_down = sig->mode.hsync_len * 2,
0221 }, {
0222
0223 .run_count = v_total - 1,
0224 .run_src = 4,
0225 .cnt_polarity_gen_en = 1,
0226 .cnt_polarity_trigger_src = 4,
0227 .cnt_down = sig->mode.vsync_len * 2,
0228 .cnt_clr_src = DI_SYNC_CNT1,
0229 }, {
0230
0231 .run_count = v_total / 2,
0232 .run_src = DI_SYNC_HSYNC,
0233 .offset_count = h_total / 2,
0234 .offset_src = DI_SYNC_CLK,
0235 .repeat_count = 2,
0236 .cnt_clr_src = DI_SYNC_CNT1,
0237 }, {
0238
0239 .run_src = DI_SYNC_HSYNC,
0240 .offset_count = (sig->mode.vsync_len +
0241 sig->mode.vback_porch) / 2,
0242 .offset_src = DI_SYNC_HSYNC,
0243 .repeat_count = sig->mode.vactive / 2,
0244 .cnt_clr_src = DI_SYNC_CNT4,
0245 }, {
0246
0247 .run_src = DI_SYNC_CLK,
0248 .offset_count = sig->mode.hsync_len +
0249 sig->mode.hback_porch,
0250 .offset_src = DI_SYNC_CLK,
0251 .repeat_count = sig->mode.hactive,
0252 .cnt_clr_src = DI_SYNC_CNT5,
0253 }, {
0254
0255 .run_count = h_total / 2 - 1,
0256 .run_src = DI_SYNC_CLK,
0257 }
0258 };
0259
0260 ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
0261
0262 ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
0263 }
0264
0265 static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
0266 struct ipu_di_signal_cfg *sig, int div)
0267 {
0268 u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
0269 sig->mode.hback_porch + sig->mode.hfront_porch;
0270 u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
0271 sig->mode.vback_porch + sig->mode.vfront_porch;
0272 struct di_sync_config cfg[] = {
0273 {
0274
0275 .run_count = h_total - 1,
0276 .run_src = DI_SYNC_CLK,
0277 } , {
0278
0279 .run_count = h_total - 1,
0280 .run_src = DI_SYNC_CLK,
0281 .offset_count = div * sig->v_to_h_sync,
0282 .offset_src = DI_SYNC_CLK,
0283 .cnt_polarity_gen_en = 1,
0284 .cnt_polarity_trigger_src = DI_SYNC_CLK,
0285 .cnt_down = sig->mode.hsync_len * 2,
0286 } , {
0287
0288 .run_count = v_total - 1,
0289 .run_src = DI_SYNC_INT_HSYNC,
0290 .cnt_polarity_gen_en = 1,
0291 .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
0292 .cnt_down = sig->mode.vsync_len * 2,
0293 } , {
0294
0295 .run_src = DI_SYNC_HSYNC,
0296 .offset_count = sig->mode.vsync_len +
0297 sig->mode.vback_porch,
0298 .offset_src = DI_SYNC_HSYNC,
0299 .repeat_count = sig->mode.vactive,
0300 .cnt_clr_src = DI_SYNC_VSYNC,
0301 } , {
0302
0303 .run_src = DI_SYNC_CLK,
0304 .offset_count = sig->mode.hsync_len +
0305 sig->mode.hback_porch,
0306 .offset_src = DI_SYNC_CLK,
0307 .repeat_count = sig->mode.hactive,
0308 .cnt_clr_src = 5,
0309 } , {
0310
0311 } , {
0312
0313 },
0314 };
0315
0316 struct di_sync_config cfg_vga[] = {
0317 {
0318
0319 .run_count = h_total - 1,
0320 .run_src = DI_SYNC_CLK,
0321 } , {
0322
0323 .run_count = v_total - 1,
0324 .run_src = DI_SYNC_INT_HSYNC,
0325 } , {
0326
0327 .run_src = DI_SYNC_INT_HSYNC,
0328 .offset_count = sig->mode.vsync_len +
0329 sig->mode.vback_porch,
0330 .offset_src = DI_SYNC_INT_HSYNC,
0331 .repeat_count = sig->mode.vactive,
0332 .cnt_clr_src = 3 ,
0333 } , {
0334
0335 .run_count = h_total - 1,
0336 .run_src = DI_SYNC_CLK,
0337 .offset_count = div * sig->v_to_h_sync + 18,
0338 .offset_src = DI_SYNC_CLK,
0339 .cnt_polarity_gen_en = 1,
0340 .cnt_polarity_trigger_src = DI_SYNC_CLK,
0341 .cnt_down = sig->mode.hsync_len * 2,
0342 } , {
0343
0344 .run_src = DI_SYNC_CLK,
0345 .offset_count = sig->mode.hsync_len +
0346 sig->mode.hback_porch,
0347 .offset_src = DI_SYNC_CLK,
0348 .repeat_count = sig->mode.hactive,
0349 .cnt_clr_src = 4,
0350 } , {
0351
0352 .run_count = v_total - 1,
0353 .run_src = DI_SYNC_INT_HSYNC,
0354 .offset_count = 1,
0355 .offset_src = DI_SYNC_INT_HSYNC,
0356 .cnt_polarity_gen_en = 1,
0357 .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
0358 .cnt_down = sig->mode.vsync_len * 2,
0359 } , {
0360
0361 .run_count = h_total - 1,
0362 .run_src = DI_SYNC_CLK,
0363 .offset_count = div * sig->v_to_h_sync + 18,
0364 .offset_src = DI_SYNC_CLK,
0365 .cnt_polarity_gen_en = 1,
0366 .cnt_polarity_trigger_src = DI_SYNC_CLK,
0367 .cnt_down = sig->mode.hsync_len * 2,
0368 } , {
0369
0370 .run_count = v_total - 1,
0371 .run_src = DI_SYNC_INT_HSYNC,
0372 .offset_count = 1,
0373 .offset_src = DI_SYNC_INT_HSYNC,
0374 .cnt_polarity_gen_en = 1,
0375 .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
0376 .cnt_down = sig->mode.vsync_len * 2,
0377 } , {
0378
0379 },
0380 };
0381
0382 ipu_di_write(di, v_total - 1, DI_SCR_CONF);
0383 if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
0384 ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
0385 else
0386 ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
0387 }
0388
0389 static void ipu_di_config_clock(struct ipu_di *di,
0390 const struct ipu_di_signal_cfg *sig)
0391 {
0392 struct clk *clk;
0393 unsigned clkgen0;
0394 uint32_t val;
0395
0396 if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
0397
0398
0399
0400
0401
0402 clk = di->clk_di;
0403
0404 if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
0405
0406
0407
0408
0409
0410
0411
0412 clkgen0 = 1 << 4;
0413 } else {
0414
0415
0416
0417
0418
0419
0420
0421 unsigned long in_rate;
0422 unsigned div;
0423
0424 clk_set_rate(clk, sig->mode.pixelclock);
0425
0426 in_rate = clk_get_rate(clk);
0427 div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
0428 div = clamp(div, 1U, 255U);
0429
0430 clkgen0 = div << 4;
0431 }
0432 } else {
0433
0434
0435
0436
0437
0438
0439
0440 unsigned long rate, clkrate;
0441 unsigned div, error;
0442
0443 clkrate = clk_get_rate(di->clk_ipu);
0444 div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
0445 div = clamp(div, 1U, 255U);
0446 rate = clkrate / div;
0447
0448 error = rate / (sig->mode.pixelclock / 1000);
0449
0450 dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %c%d.%d%%\n",
0451 rate, div, error < 1000 ? '-' : '+',
0452 abs(error - 1000) / 10, abs(error - 1000) % 10);
0453
0454
0455 if (error < 1010 && error >= 990) {
0456 clk = di->clk_ipu;
0457
0458 clkgen0 = div << 4;
0459 } else {
0460 unsigned long in_rate;
0461 unsigned div;
0462
0463 clk = di->clk_di;
0464
0465 clk_set_rate(clk, sig->mode.pixelclock);
0466
0467 in_rate = clk_get_rate(clk);
0468 div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
0469 div = clamp(div, 1U, 255U);
0470
0471 clkgen0 = div << 4;
0472 }
0473 }
0474
0475 di->clk_di_pixel = clk;
0476
0477
0478 ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
0479
0480
0481
0482
0483
0484
0485
0486 ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
0487
0488
0489 val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
0490 if (clk == di->clk_di)
0491 val |= DI_GEN_DI_CLK_EXT;
0492 ipu_di_write(di, val, DI_GENERAL);
0493
0494 dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
0495 sig->mode.pixelclock,
0496 clk_get_rate(di->clk_ipu),
0497 clk_get_rate(di->clk_di),
0498 clk == di->clk_di ? "DI" : "IPU",
0499 clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
0500 }
0501
0502
0503
0504
0505
0506 int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
0507 {
0508 u32 diff;
0509
0510 if (!IS_ALIGNED(mode->hactive, 8) &&
0511 mode->hfront_porch < ALIGN(mode->hactive, 8) - mode->hactive) {
0512 dev_err(di->ipu->dev, "hactive %d is not aligned to 8 and front porch is too small to compensate\n",
0513 mode->hactive);
0514 return -EINVAL;
0515 }
0516
0517 if (mode->vfront_porch >= 2)
0518 return 0;
0519
0520 diff = 2 - mode->vfront_porch;
0521
0522 if (mode->vback_porch >= diff) {
0523 mode->vfront_porch = 2;
0524 mode->vback_porch -= diff;
0525 } else if (mode->vsync_len > diff) {
0526 mode->vfront_porch = 2;
0527 mode->vsync_len = mode->vsync_len - diff;
0528 } else {
0529 dev_warn(di->ipu->dev, "failed to adjust videomode\n");
0530 return -EINVAL;
0531 }
0532
0533 dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
0534 return 0;
0535 }
0536 EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
0537
0538 static u32 ipu_di_gen_polarity(int pin)
0539 {
0540 switch (pin) {
0541 case 1:
0542 return DI_GEN_POLARITY_1;
0543 case 2:
0544 return DI_GEN_POLARITY_2;
0545 case 3:
0546 return DI_GEN_POLARITY_3;
0547 case 4:
0548 return DI_GEN_POLARITY_4;
0549 case 5:
0550 return DI_GEN_POLARITY_5;
0551 case 6:
0552 return DI_GEN_POLARITY_6;
0553 case 7:
0554 return DI_GEN_POLARITY_7;
0555 case 8:
0556 return DI_GEN_POLARITY_8;
0557 }
0558 return 0;
0559 }
0560
0561 int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
0562 {
0563 u32 reg;
0564 u32 di_gen, vsync_cnt;
0565 u32 div;
0566
0567 dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
0568 di->id, sig->mode.hactive, sig->mode.vactive);
0569
0570 dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
0571 clk_get_rate(di->clk_ipu),
0572 clk_get_rate(di->clk_di),
0573 sig->mode.pixelclock);
0574
0575 mutex_lock(&di_mutex);
0576
0577 ipu_di_config_clock(di, sig);
0578
0579 div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
0580 div = div / 16;
0581
0582
0583
0584 ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
0585
0586 ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
0587 ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
0588
0589 di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
0590 di_gen |= DI_GEN_DI_VSYNC_EXT;
0591
0592 if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
0593 ipu_di_sync_config_interlaced(di, sig);
0594
0595
0596 di_gen |= 0x10000000;
0597
0598 vsync_cnt = 3;
0599 } else {
0600 ipu_di_sync_config_noninterlaced(di, sig, div);
0601
0602 vsync_cnt = 3;
0603 if (di->id == 1)
0604
0605
0606
0607
0608 if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
0609 vsync_cnt = 6;
0610 }
0611
0612 if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
0613 di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
0614 if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
0615 di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
0616
0617 if (sig->clk_pol)
0618 di_gen |= DI_GEN_POLARITY_DISP_CLK;
0619
0620 ipu_di_write(di, di_gen, DI_GENERAL);
0621
0622 ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
0623 DI_SYNC_AS_GEN);
0624
0625 reg = ipu_di_read(di, DI_POL);
0626 reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
0627
0628 if (sig->enable_pol)
0629 reg |= DI_POL_DRDY_POLARITY_15;
0630 if (sig->data_pol)
0631 reg |= DI_POL_DRDY_DATA_POLARITY;
0632
0633 ipu_di_write(di, reg, DI_POL);
0634
0635 mutex_unlock(&di_mutex);
0636
0637 return 0;
0638 }
0639 EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
0640
0641 int ipu_di_enable(struct ipu_di *di)
0642 {
0643 int ret;
0644
0645 WARN_ON(IS_ERR(di->clk_di_pixel));
0646
0647 ret = clk_prepare_enable(di->clk_di_pixel);
0648 if (ret)
0649 return ret;
0650
0651 ipu_module_enable(di->ipu, di->module);
0652
0653 return 0;
0654 }
0655 EXPORT_SYMBOL_GPL(ipu_di_enable);
0656
0657 int ipu_di_disable(struct ipu_di *di)
0658 {
0659 WARN_ON(IS_ERR(di->clk_di_pixel));
0660
0661 ipu_module_disable(di->ipu, di->module);
0662
0663 clk_disable_unprepare(di->clk_di_pixel);
0664
0665 return 0;
0666 }
0667 EXPORT_SYMBOL_GPL(ipu_di_disable);
0668
0669 int ipu_di_get_num(struct ipu_di *di)
0670 {
0671 return di->id;
0672 }
0673 EXPORT_SYMBOL_GPL(ipu_di_get_num);
0674
0675 static DEFINE_MUTEX(ipu_di_lock);
0676
0677 struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
0678 {
0679 struct ipu_di *di;
0680
0681 if (disp > 1)
0682 return ERR_PTR(-EINVAL);
0683
0684 di = ipu->di_priv[disp];
0685
0686 mutex_lock(&ipu_di_lock);
0687
0688 if (di->inuse) {
0689 di = ERR_PTR(-EBUSY);
0690 goto out;
0691 }
0692
0693 di->inuse = true;
0694 out:
0695 mutex_unlock(&ipu_di_lock);
0696
0697 return di;
0698 }
0699 EXPORT_SYMBOL_GPL(ipu_di_get);
0700
0701 void ipu_di_put(struct ipu_di *di)
0702 {
0703 mutex_lock(&ipu_di_lock);
0704
0705 di->inuse = false;
0706
0707 mutex_unlock(&ipu_di_lock);
0708 }
0709 EXPORT_SYMBOL_GPL(ipu_di_put);
0710
0711 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
0712 unsigned long base,
0713 u32 module, struct clk *clk_ipu)
0714 {
0715 struct ipu_di *di;
0716
0717 if (id > 1)
0718 return -ENODEV;
0719
0720 di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
0721 if (!di)
0722 return -ENOMEM;
0723
0724 ipu->di_priv[id] = di;
0725
0726 di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
0727 if (IS_ERR(di->clk_di))
0728 return PTR_ERR(di->clk_di);
0729
0730 di->module = module;
0731 di->id = id;
0732 di->clk_ipu = clk_ipu;
0733 di->base = devm_ioremap(dev, base, PAGE_SIZE);
0734 if (!di->base)
0735 return -ENOMEM;
0736
0737 ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
0738
0739 dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
0740 id, base, di->base);
0741 di->inuse = false;
0742 di->ipu = ipu;
0743
0744 return 0;
0745 }
0746
0747 void ipu_di_exit(struct ipu_soc *ipu, int id)
0748 {
0749 }