Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
0004  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
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; /* display input clock */
0022     struct clk *clk_ipu;    /* IPU bus clock */
0023     struct clk *clk_di_pixel; /* resulting pixel clock */
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,   /* counter >= 2 only */
0067     DI_SYNC_CNT4 = 5,   /* counter >= 5 only */
0068     DI_SYNC_CNT5 = 6,   /* counter >= 6 only */
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         /* Enable auto reload */
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             /* 1: internal VSYNC for each frame */
0212             .run_count = v_total * 2 - 1,
0213             .run_src = 3,           /* == counter 7 */
0214         }, {
0215             /* PIN2: HSYNC waveform */
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             /* PIN3: VSYNC waveform */
0223             .run_count = v_total - 1,
0224             .run_src = 4,           /* == counter 7 */
0225             .cnt_polarity_gen_en = 1,
0226             .cnt_polarity_trigger_src = 4,  /* == counter 7 */
0227             .cnt_down = sig->mode.vsync_len * 2,
0228             .cnt_clr_src = DI_SYNC_CNT1,
0229         }, {
0230             /* 4: Field */
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             /* 5: Active lines */
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             /* 6: Active pixel, referenced by DC */
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             /* 7: Half line HSYNC */
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             /* 1: INT_HSYNC */
0275             .run_count = h_total - 1,
0276             .run_src = DI_SYNC_CLK,
0277         } , {
0278             /* PIN2: HSYNC */
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             /* PIN3: VSYNC */
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             /* 4: Line Active */
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             /* 5: Pixel Active, referenced by DC */
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, /* Line Active */
0309         } , {
0310             /* unused */
0311         } , {
0312             /* unused */
0313         },
0314     };
0315     /* can't use #7 and #8 for line active and pixel active counters */
0316     struct di_sync_config cfg_vga[] = {
0317         {
0318             /* 1: INT_HSYNC */
0319             .run_count = h_total - 1,
0320             .run_src = DI_SYNC_CLK,
0321         } , {
0322             /* 2: VSYNC */
0323             .run_count = v_total - 1,
0324             .run_src = DI_SYNC_INT_HSYNC,
0325         } , {
0326             /* 3: Line Active */
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 /* VSYNC */,
0333         } , {
0334             /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
0335             .run_count = h_total - 1,
0336             .run_src = DI_SYNC_CLK,
0337             .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
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             /* 5: Pixel Active signal to DC */
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, /* Line Active */
0350         } , {
0351             /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
0352             .run_count = v_total - 1,
0353             .run_src = DI_SYNC_INT_HSYNC,
0354             .offset_count = 1, /* magic value from Freescale TVE driver */
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             /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
0361             .run_count = h_total - 1,
0362             .run_src = DI_SYNC_CLK,
0363             .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
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             /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
0370             .run_count = v_total - 1,
0371             .run_src = DI_SYNC_INT_HSYNC,
0372             .offset_count = 1, /* magic value from Freescale TVE driver */
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             /* unused */
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          * CLKMODE_EXT means we must use the DI clock: this is
0399          * needed for things like LVDS which needs to feed the
0400          * DI and LDB with the same pixel clock.
0401          */
0402         clk = di->clk_di;
0403 
0404         if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
0405             /*
0406              * CLKMODE_SYNC means that we want the DI to be
0407              * clocked at the same rate as the parent clock.
0408              * This is needed (eg) for LDB which needs to be
0409              * fed with the same pixel clock.  We assume that
0410              * the LDB clock has already been set correctly.
0411              */
0412             clkgen0 = 1 << 4;
0413         } else {
0414             /*
0415              * We can use the divider.  We should really have
0416              * a flag here indicating whether the bridge can
0417              * cope with a fractional divider or not.  For the
0418              * time being, let's go for simplicitly and
0419              * reliability.
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          * For other interfaces, we can arbitarily select between
0435          * the DI specific clock and the internal IPU clock.  See
0436          * DI_GENERAL bit 20.  We select the IPU clock if it can
0437          * give us a clock rate within 1% of the requested frequency,
0438          * otherwise we use the DI clock.
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         /* Allow a 1% error */
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     /* Set the divider */
0478     ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
0479 
0480     /*
0481      * Set the high/low periods.  Bits 24:16 give us the falling edge,
0482      * and bits 8:0 give the rising edge.  LSB is fraction, and is
0483      * based on the divider above.  We want a 50% duty cycle, so set
0484      * the falling edge to be half the divider.
0485      */
0486     ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
0487 
0488     /* Finally select the input clock */
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  * This function is called to adjust a video mode to IPU restrictions.
0504  * It is meant to be called from drm crtc mode_fixup() methods.
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;     /* Now divider is integer portion */
0581 
0582     /* Setup pixel clock timing */
0583     /* Down time is half of period */
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         /* set y_sel = 1 */
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              * TODO: change only for TVEv2, parallel display
0606              * uses pin 2 / 3
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 }