]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/imx-drm/ipu-v3/ipu-di.c
Merge remote-tracking branch 'clk/clk-next'
[karo-tx-linux.git] / drivers / staging / imx-drm / ipu-v3 / ipu-di.c
1 /*
2  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
3  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  */
15 #include <linux/export.h>
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/io.h>
20 #include <linux/err.h>
21 #include <linux/platform_device.h>
22 #include <linux/clk.h>
23 #include <linux/clk-provider.h>
24 #include <linux/clkdev.h>
25
26 #include "imx-ipu-v3.h"
27 #include "ipu-prv.h"
28
29 struct ipu_di {
30         void __iomem *base;
31         int id;
32         u32 module;
33         struct clk *clk_di;     /* display input clock */
34         struct clk *clk_ipu;    /* IPU bus clock */
35         struct clk *clk_di_pixel; /* resulting pixel clock */
36         struct clk_hw clk_hw_out;
37         char *clk_name;
38         bool inuse;
39         unsigned long clkflags;
40         struct ipu_soc *ipu;
41 };
42
43 static DEFINE_MUTEX(di_mutex);
44
45 struct di_sync_config {
46         int run_count;
47         int run_src;
48         int offset_count;
49         int offset_src;
50         int repeat_count;
51         int cnt_clr_src;
52         int cnt_polarity_gen_en;
53         int cnt_polarity_clr_src;
54         int cnt_polarity_trigger_src;
55         int cnt_up;
56         int cnt_down;
57 };
58
59 enum di_pins {
60         DI_PIN11 = 0,
61         DI_PIN12 = 1,
62         DI_PIN13 = 2,
63         DI_PIN14 = 3,
64         DI_PIN15 = 4,
65         DI_PIN16 = 5,
66         DI_PIN17 = 6,
67         DI_PIN_CS = 7,
68
69         DI_PIN_SER_CLK = 0,
70         DI_PIN_SER_RS = 1,
71 };
72
73 enum di_sync_wave {
74         DI_SYNC_NONE = 0,
75         DI_SYNC_CLK = 1,
76         DI_SYNC_INT_HSYNC = 2,
77         DI_SYNC_HSYNC = 3,
78         DI_SYNC_VSYNC = 4,
79         DI_SYNC_DE = 6,
80 };
81
82 #define SYNC_WAVE 0
83
84 #define DI_GENERAL              0x0000
85 #define DI_BS_CLKGEN0           0x0004
86 #define DI_BS_CLKGEN1           0x0008
87 #define DI_SW_GEN0(gen)         (0x000c + 4 * ((gen) - 1))
88 #define DI_SW_GEN1(gen)         (0x0030 + 4 * ((gen) - 1))
89 #define DI_STP_REP(gen)         (0x0148 + 4 * (((gen) - 1)/2))
90 #define DI_SYNC_AS_GEN          0x0054
91 #define DI_DW_GEN(gen)          (0x0058 + 4 * (gen))
92 #define DI_DW_SET(gen, set)     (0x0088 + 4 * ((gen) + 0xc * (set)))
93 #define DI_SER_CONF             0x015c
94 #define DI_SSC                  0x0160
95 #define DI_POL                  0x0164
96 #define DI_AW0                  0x0168
97 #define DI_AW1                  0x016c
98 #define DI_SCR_CONF             0x0170
99 #define DI_STAT                 0x0174
100
101 #define DI_SW_GEN0_RUN_COUNT(x)                 ((x) << 19)
102 #define DI_SW_GEN0_RUN_SRC(x)                   ((x) << 16)
103 #define DI_SW_GEN0_OFFSET_COUNT(x)              ((x) << 3)
104 #define DI_SW_GEN0_OFFSET_SRC(x)                ((x) << 0)
105
106 #define DI_SW_GEN1_CNT_POL_GEN_EN(x)            ((x) << 29)
107 #define DI_SW_GEN1_CNT_CLR_SRC(x)               ((x) << 25)
108 #define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)       ((x) << 12)
109 #define DI_SW_GEN1_CNT_POL_CLR_SRC(x)           ((x) << 9)
110 #define DI_SW_GEN1_CNT_DOWN(x)                  ((x) << 16)
111 #define DI_SW_GEN1_CNT_UP(x)                    (x)
112 #define DI_SW_GEN1_AUTO_RELOAD                  (0x10000000)
113
114 #define DI_DW_GEN_ACCESS_SIZE_OFFSET            24
115 #define DI_DW_GEN_COMPONENT_SIZE_OFFSET         16
116
117 #define DI_GEN_POLARITY_1                       (1 << 0)
118 #define DI_GEN_POLARITY_2                       (1 << 1)
119 #define DI_GEN_POLARITY_3                       (1 << 2)
120 #define DI_GEN_POLARITY_4                       (1 << 3)
121 #define DI_GEN_POLARITY_5                       (1 << 4)
122 #define DI_GEN_POLARITY_6                       (1 << 5)
123 #define DI_GEN_POLARITY_7                       (1 << 6)
124 #define DI_GEN_POLARITY_8                       (1 << 7)
125 #define DI_GEN_POLARITY_DISP_CLK                (1 << 17)
126 #define DI_GEN_DI_CLK_EXT                       (1 << 20)
127 #define DI_GEN_DI_VSYNC_EXT                     (1 << 21)
128
129 #define DI_POL_DRDY_DATA_POLARITY               (1 << 7)
130 #define DI_POL_DRDY_POLARITY_15                 (1 << 4)
131
132 #define DI_VSYNC_SEL_OFFSET                     13
133
134 static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
135 {
136         return readl(di->base + offset);
137 }
138
139 static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
140 {
141         writel(value, di->base + offset);
142 }
143
144 static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
145 {
146         u64 tmp = inrate;
147         int div;
148
149         tmp *= 16;
150
151         do_div(tmp, outrate);
152
153         div = tmp;
154
155         if (div < 0x10)
156                 div = 0x10;
157
158 #ifdef WTF_IS_THIS
159         /*
160          * Freescale has this in their Kernel. It is neither clear what
161          * it does nor why it does it
162          */
163         if (div & 0x10)
164                 div &= ~0x7;
165         else {
166                 /* Round up divider if it gets us closer to desired pix clk */
167                 if ((div & 0xC) == 0xC) {
168                         div += 0x10;
169                         div &= ~0xF;
170                 }
171         }
172 #endif
173         return div;
174 }
175
176 static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
177                 unsigned long parent_rate)
178 {
179         struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
180         unsigned long outrate;
181         u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
182
183         if (div < 0x10)
184                 div = 0x10;
185
186         outrate = (parent_rate / div) * 16;
187
188         return outrate;
189 }
190
191 static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
192                                 unsigned long *prate)
193 {
194         struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
195         unsigned long outrate;
196         int div;
197         u32 val;
198
199         div = ipu_di_clk_calc_div(*prate, rate);
200
201         outrate = (*prate / div) * 16;
202
203         val = ipu_di_read(di, DI_GENERAL);
204
205         if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
206                 outrate = *prate / 2;
207
208         dev_dbg(di->ipu->dev,
209                 "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
210                         __func__, *prate, div, outrate, rate);
211
212         return outrate;
213 }
214
215 static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
216                                 unsigned long parent_rate)
217 {
218         struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
219         int div;
220         u32 clkgen0;
221
222         clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
223
224         div = ipu_di_clk_calc_div(parent_rate, rate);
225
226         ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
227
228         dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
229                         __func__, parent_rate, rate, div);
230         return 0;
231 }
232
233 static u8 clk_di_get_parent(struct clk_hw *hw)
234 {
235         struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
236         u32 val;
237
238         val = ipu_di_read(di, DI_GENERAL);
239
240         return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
241 }
242
243 static int clk_di_set_parent(struct clk_hw *hw, u8 index)
244 {
245         struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
246         u32 val;
247
248         val = ipu_di_read(di, DI_GENERAL);
249
250         if (index)
251                 val |= DI_GEN_DI_CLK_EXT;
252         else
253                 val &= ~DI_GEN_DI_CLK_EXT;
254
255         ipu_di_write(di, val, DI_GENERAL);
256
257         return 0;
258 }
259
260 static struct clk_ops clk_di_ops = {
261         .round_rate = clk_di_round_rate,
262         .set_rate = clk_di_set_rate,
263         .recalc_rate = clk_di_recalc_rate,
264         .set_parent = clk_di_set_parent,
265         .get_parent = clk_di_get_parent,
266 };
267
268 static void ipu_di_data_wave_config(struct ipu_di *di,
269                                      int wave_gen,
270                                      int access_size, int component_size)
271 {
272         u32 reg;
273         reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
274             (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
275         ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
276 }
277
278 static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
279                 int set, int up, int down)
280 {
281         u32 reg;
282
283         reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
284         reg &= ~(0x3 << (di_pin * 2));
285         reg |= set << (di_pin * 2);
286         ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
287
288         ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
289 }
290
291 static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
292                 int start, int count)
293 {
294         u32 reg;
295         int i;
296
297         for (i = 0; i < count; i++) {
298                 struct di_sync_config *c = &config[i];
299                 int wave_gen = start + i + 1;
300
301                 if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
302                                 (c->repeat_count >= 0x1000) ||
303                                 (c->cnt_up >= 0x400) ||
304                                 (c->cnt_down >= 0x400)) {
305                         dev_err(di->ipu->dev, "DI%d counters out of range.\n",
306                                         di->id);
307                         return;
308                 }
309
310                 reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
311                         DI_SW_GEN0_RUN_SRC(c->run_src) |
312                         DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
313                         DI_SW_GEN0_OFFSET_SRC(c->offset_src);
314                 ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
315
316                 reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
317                         DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
318                         DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
319                                         c->cnt_polarity_trigger_src) |
320                         DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
321                         DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
322                         DI_SW_GEN1_CNT_UP(c->cnt_up);
323
324                 /* Enable auto reload */
325                 if (c->repeat_count == 0)
326                         reg |= DI_SW_GEN1_AUTO_RELOAD;
327
328                 ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
329
330                 reg = ipu_di_read(di, DI_STP_REP(wave_gen));
331                 reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
332                 reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
333                 ipu_di_write(di, reg, DI_STP_REP(wave_gen));
334         }
335 }
336
337 static void ipu_di_sync_config_interlaced(struct ipu_di *di,
338                 struct ipu_di_signal_cfg *sig)
339 {
340         u32 h_total = sig->width + sig->h_sync_width +
341                 sig->h_start_width + sig->h_end_width;
342         u32 v_total = sig->height + sig->v_sync_width +
343                 sig->v_start_width + sig->v_end_width;
344         u32 reg;
345         struct di_sync_config cfg[] = {
346                 {
347                         .run_count = h_total / 2 - 1,
348                         .run_src = DI_SYNC_CLK,
349                 }, {
350                         .run_count = h_total - 11,
351                         .run_src = DI_SYNC_CLK,
352                         .cnt_down = 4,
353                 }, {
354                         .run_count = v_total * 2 - 1,
355                         .run_src = DI_SYNC_INT_HSYNC,
356                         .offset_count = 1,
357                         .offset_src = DI_SYNC_INT_HSYNC,
358                         .cnt_down = 4,
359                 }, {
360                         .run_count = v_total / 2 - 1,
361                         .run_src = DI_SYNC_HSYNC,
362                         .offset_count = sig->v_start_width,
363                         .offset_src = DI_SYNC_HSYNC,
364                         .repeat_count = 2,
365                         .cnt_clr_src = DI_SYNC_VSYNC,
366                 }, {
367                         .run_src = DI_SYNC_HSYNC,
368                         .repeat_count = sig->height / 2,
369                         .cnt_clr_src = 4,
370                 }, {
371                         .run_count = v_total - 1,
372                         .run_src = DI_SYNC_HSYNC,
373                 }, {
374                         .run_count = v_total / 2 - 1,
375                         .run_src = DI_SYNC_HSYNC,
376                         .offset_count = 9,
377                         .offset_src = DI_SYNC_HSYNC,
378                         .repeat_count = 2,
379                         .cnt_clr_src = DI_SYNC_VSYNC,
380                 }, {
381                         .run_src = DI_SYNC_CLK,
382                         .offset_count = sig->h_start_width,
383                         .offset_src = DI_SYNC_CLK,
384                         .repeat_count = sig->width,
385                         .cnt_clr_src = 5,
386                 }, {
387                         .run_count = v_total - 1,
388                         .run_src = DI_SYNC_INT_HSYNC,
389                         .offset_count = v_total / 2,
390                         .offset_src = DI_SYNC_INT_HSYNC,
391                         .cnt_clr_src = DI_SYNC_HSYNC,
392                         .cnt_down = 4,
393                 }
394         };
395
396         ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
397
398         /* set gentime select and tag sel */
399         reg = ipu_di_read(di, DI_SW_GEN1(9));
400         reg &= 0x1FFFFFFF;
401         reg |= (3 - 1) << 29 | 0x00008000;
402         ipu_di_write(di, reg, DI_SW_GEN1(9));
403
404         ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
405 }
406
407 static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
408                 struct ipu_di_signal_cfg *sig, int div)
409 {
410         u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
411                 sig->h_end_width;
412         u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
413                 sig->v_end_width;
414         struct di_sync_config cfg[] = {
415                 {
416                         /* 1: INT_HSYNC */
417                         .run_count = h_total - 1,
418                         .run_src = DI_SYNC_CLK,
419                 } , {
420                         /* PIN2: HSYNC */
421                         .run_count = h_total - 1,
422                         .run_src = DI_SYNC_CLK,
423                         .offset_count = div * sig->v_to_h_sync,
424                         .offset_src = DI_SYNC_CLK,
425                         .cnt_polarity_gen_en = 1,
426                         .cnt_polarity_trigger_src = DI_SYNC_CLK,
427                         .cnt_down = sig->h_sync_width * 2,
428                 } , {
429                         /* PIN3: VSYNC */
430                         .run_count = v_total - 1,
431                         .run_src = DI_SYNC_INT_HSYNC,
432                         .cnt_polarity_gen_en = 1,
433                         .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
434                         .cnt_down = sig->v_sync_width * 2,
435                 } , {
436                         /* 4: Line Active */
437                         .run_src = DI_SYNC_HSYNC,
438                         .offset_count = sig->v_sync_width + sig->v_start_width,
439                         .offset_src = DI_SYNC_HSYNC,
440                         .repeat_count = sig->height,
441                         .cnt_clr_src = DI_SYNC_VSYNC,
442                 } , {
443                         /* 5: Pixel Active, referenced by DC */
444                         .run_src = DI_SYNC_CLK,
445                         .offset_count = sig->h_sync_width + sig->h_start_width,
446                         .offset_src = DI_SYNC_CLK,
447                         .repeat_count = sig->width,
448                         .cnt_clr_src = 5, /* Line Active */
449                 } , {
450                         /* unused */
451                 } , {
452                         /* unused */
453                 } , {
454                         /* unused */
455                 } , {
456                         /* unused */
457                 },
458         };
459         /* can't use #7 and #8 for line active and pixel active counters */
460         struct di_sync_config cfg_vga[] = {
461                 {
462                         /* 1: INT_HSYNC */
463                         .run_count = h_total - 1,
464                         .run_src = DI_SYNC_CLK,
465                 } , {
466                         /* 2: VSYNC */
467                         .run_count = v_total - 1,
468                         .run_src = DI_SYNC_INT_HSYNC,
469                 } , {
470                         /* 3: Line Active */
471                         .run_src = DI_SYNC_INT_HSYNC,
472                         .offset_count = sig->v_sync_width + sig->v_start_width,
473                         .offset_src = DI_SYNC_INT_HSYNC,
474                         .repeat_count = sig->height,
475                         .cnt_clr_src = 3 /* VSYNC */,
476                 } , {
477                         /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
478                         .run_count = h_total - 1,
479                         .run_src = DI_SYNC_CLK,
480                         .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
481                         .offset_src = DI_SYNC_CLK,
482                         .cnt_polarity_gen_en = 1,
483                         .cnt_polarity_trigger_src = DI_SYNC_CLK,
484                         .cnt_down = sig->h_sync_width * 2,
485                 } , {
486                         /* 5: Pixel Active signal to DC */
487                         .run_src = DI_SYNC_CLK,
488                         .offset_count = sig->h_sync_width + sig->h_start_width,
489                         .offset_src = DI_SYNC_CLK,
490                         .repeat_count = sig->width,
491                         .cnt_clr_src = 4, /* Line Active */
492                 } , {
493                         /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
494                         .run_count = v_total - 1,
495                         .run_src = DI_SYNC_INT_HSYNC,
496                         .offset_count = 1, /* magic value from Freescale TVE driver */
497                         .offset_src = DI_SYNC_INT_HSYNC,
498                         .cnt_polarity_gen_en = 1,
499                         .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
500                         .cnt_down = sig->v_sync_width * 2,
501                 } , {
502                         /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
503                         .run_count = h_total - 1,
504                         .run_src = DI_SYNC_CLK,
505                         .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
506                         .offset_src = DI_SYNC_CLK,
507                         .cnt_polarity_gen_en = 1,
508                         .cnt_polarity_trigger_src = DI_SYNC_CLK,
509                         .cnt_down = sig->h_sync_width * 2,
510                 } , {
511                         /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
512                         .run_count = v_total - 1,
513                         .run_src = DI_SYNC_INT_HSYNC,
514                         .offset_count = 1, /* magic value from Freescale TVE driver */
515                         .offset_src = DI_SYNC_INT_HSYNC,
516                         .cnt_polarity_gen_en = 1,
517                         .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
518                         .cnt_down = sig->v_sync_width * 2,
519                 } , {
520                         /* unused */
521                 },
522         };
523
524         ipu_di_write(di, v_total - 1, DI_SCR_CONF);
525         if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
526                 ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
527         else
528                 ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
529 }
530
531 int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
532 {
533         u32 reg;
534         u32 di_gen, vsync_cnt;
535         u32 div;
536         u32 h_total, v_total;
537         int ret;
538         unsigned long round;
539         struct clk *parent;
540
541         dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
542                 di->id, sig->width, sig->height);
543
544         if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
545                 return -EINVAL;
546
547         if (sig->clkflags & IPU_DI_CLKMODE_EXT)
548                 parent = di->clk_di;
549         else
550                 parent = di->clk_ipu;
551
552         ret = clk_set_parent(di->clk_di_pixel, parent);
553         if (ret) {
554                 dev_err(di->ipu->dev,
555                         "setting pixel clock to parent %s failed with %d\n",
556                                 __clk_get_name(parent), ret);
557                 return ret;
558         }
559
560         if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
561                 round = clk_get_rate(parent);
562         else
563                 round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
564
565         ret = clk_set_rate(di->clk_di_pixel, round);
566
567         h_total = sig->width + sig->h_sync_width + sig->h_start_width +
568                 sig->h_end_width;
569         v_total = sig->height + sig->v_sync_width + sig->v_start_width +
570                 sig->v_end_width;
571
572         mutex_lock(&di_mutex);
573
574         div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
575         div = div / 16;         /* Now divider is integer portion */
576
577         /* Setup pixel clock timing */
578         /* Down time is half of period */
579         ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
580
581         ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
582         ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
583
584         di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
585         di_gen |= DI_GEN_DI_VSYNC_EXT;
586
587         if (sig->interlaced) {
588                 ipu_di_sync_config_interlaced(di, sig);
589
590                 /* set y_sel = 1 */
591                 di_gen |= 0x10000000;
592                 di_gen |= DI_GEN_POLARITY_5;
593                 di_gen |= DI_GEN_POLARITY_8;
594
595                 vsync_cnt = 7;
596
597                 if (sig->Hsync_pol)
598                         di_gen |= DI_GEN_POLARITY_3;
599                 if (sig->Vsync_pol)
600                         di_gen |= DI_GEN_POLARITY_2;
601         } else {
602                 ipu_di_sync_config_noninterlaced(di, sig, div);
603
604                 vsync_cnt = 3;
605                 if (di->id == 1)
606                         /*
607                          * TODO: change only for TVEv2, parallel display
608                          * uses pin 2 / 3
609                          */
610                         if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
611                                 vsync_cnt = 6;
612
613                 if (sig->Hsync_pol) {
614                         if (sig->hsync_pin == 2)
615                                 di_gen |= DI_GEN_POLARITY_2;
616                         else if (sig->hsync_pin == 4)
617                                 di_gen |= DI_GEN_POLARITY_4;
618                         else if (sig->hsync_pin == 7)
619                                 di_gen |= DI_GEN_POLARITY_7;
620                 }
621                 if (sig->Vsync_pol) {
622                         if (sig->vsync_pin == 3)
623                                 di_gen |= DI_GEN_POLARITY_3;
624                         else if (sig->vsync_pin == 6)
625                                 di_gen |= DI_GEN_POLARITY_6;
626                         else if (sig->vsync_pin == 8)
627                                 di_gen |= DI_GEN_POLARITY_8;
628                 }
629         }
630
631         if (!sig->clk_pol)
632                 di_gen |= DI_GEN_POLARITY_DISP_CLK;
633
634         ipu_di_write(di, di_gen, DI_GENERAL);
635
636         ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
637                      DI_SYNC_AS_GEN);
638
639         reg = ipu_di_read(di, DI_POL);
640         reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
641
642         if (sig->enable_pol)
643                 reg |= DI_POL_DRDY_POLARITY_15;
644         if (sig->data_pol)
645                 reg |= DI_POL_DRDY_DATA_POLARITY;
646
647         ipu_di_write(di, reg, DI_POL);
648
649         mutex_unlock(&di_mutex);
650
651         return 0;
652 }
653 EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
654
655 int ipu_di_enable(struct ipu_di *di)
656 {
657         int ret = clk_prepare_enable(di->clk_di_pixel);
658         if (ret)
659                 return ret;
660
661         ipu_module_enable(di->ipu, di->module);
662
663         return 0;
664 }
665 EXPORT_SYMBOL_GPL(ipu_di_enable);
666
667 int ipu_di_disable(struct ipu_di *di)
668 {
669         ipu_module_disable(di->ipu, di->module);
670
671         clk_disable_unprepare(di->clk_di_pixel);
672
673         return 0;
674 }
675 EXPORT_SYMBOL_GPL(ipu_di_disable);
676
677 int ipu_di_get_num(struct ipu_di *di)
678 {
679         return di->id;
680 }
681 EXPORT_SYMBOL_GPL(ipu_di_get_num);
682
683 static DEFINE_MUTEX(ipu_di_lock);
684
685 struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
686 {
687         struct ipu_di *di;
688
689         if (disp > 1)
690                 return ERR_PTR(-EINVAL);
691
692         di = ipu->di_priv[disp];
693
694         mutex_lock(&ipu_di_lock);
695
696         if (di->inuse) {
697                 di = ERR_PTR(-EBUSY);
698                 goto out;
699         }
700
701         di->inuse = true;
702 out:
703         mutex_unlock(&ipu_di_lock);
704
705         return di;
706 }
707 EXPORT_SYMBOL_GPL(ipu_di_get);
708
709 void ipu_di_put(struct ipu_di *di)
710 {
711         mutex_lock(&ipu_di_lock);
712
713         di->inuse = false;
714
715         mutex_unlock(&ipu_di_lock);
716 }
717 EXPORT_SYMBOL_GPL(ipu_di_put);
718
719 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
720                 unsigned long base,
721                 u32 module, struct clk *clk_ipu)
722 {
723         struct ipu_di *di;
724         int ret;
725         const char *di_parent[2];
726         struct clk_init_data init = {
727                 .ops = &clk_di_ops,
728                 .num_parents = 2,
729                 .flags = 0,
730         };
731
732         if (id > 1)
733                 return -ENODEV;
734
735         di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
736         if (!di)
737                 return -ENOMEM;
738
739         ipu->di_priv[id] = di;
740
741         di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
742         if (IS_ERR(di->clk_di))
743                 return PTR_ERR(di->clk_di);
744
745         di->module = module;
746         di->id = id;
747         di->clk_ipu = clk_ipu;
748         di->base = devm_ioremap(dev, base, PAGE_SIZE);
749         if (!di->base)
750                 return -ENOMEM;
751
752         di_parent[0] = __clk_get_name(di->clk_ipu);
753         di_parent[1] = __clk_get_name(di->clk_di);
754
755         ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
756
757         init.parent_names = (const char **)&di_parent;
758         di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
759                         dev_name(dev), id);
760         if (!di->clk_name)
761                 return -ENOMEM;
762
763         init.name = di->clk_name;
764
765         di->clk_hw_out.init = &init;
766         di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
767
768         if (IS_ERR(di->clk_di_pixel)) {
769                 ret = PTR_ERR(di->clk_di_pixel);
770                 goto failed_clk_register;
771         }
772
773         dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
774                         id, base, di->base);
775         di->inuse = false;
776         di->ipu = ipu;
777
778         return 0;
779
780 failed_clk_register:
781
782         kfree(di->clk_name);
783
784         return ret;
785 }
786
787 void ipu_di_exit(struct ipu_soc *ipu, int id)
788 {
789         struct ipu_di *di = ipu->di_priv[id];
790
791         clk_unregister(di->clk_di_pixel);
792         kfree(di->clk_name);
793 }