]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/video/sh_mipi_dsi.c
ipv6: AF_INET6 link address family
[net-next-2.6.git] / drivers / video / sh_mipi_dsi.c
1 /*
2  * Renesas SH-mobile MIPI DSI support
3  *
4  * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of version 2 of the GNU General Public License as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/clk.h>
12 #include <linux/delay.h>
13 #include <linux/init.h>
14 #include <linux/io.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17 #include <linux/string.h>
18 #include <linux/types.h>
19
20 #include <video/mipi_display.h>
21 #include <video/sh_mipi_dsi.h>
22 #include <video/sh_mobile_lcdc.h>
23
24 #define CMTSRTCTR       0x80d0
25 #define CMTSRTREQ       0x8070
26
27 #define DSIINTE         0x0060
28
29 /* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
30 #define MAX_SH_MIPI_DSI 2
31
32 struct sh_mipi {
33         void __iomem    *base;
34         struct clk      *dsit_clk;
35         struct clk      *dsip_clk;
36 };
37
38 static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
39
40 /* Protect the above array */
41 static DEFINE_MUTEX(array_lock);
42
43 static struct sh_mipi *sh_mipi_by_handle(int handle)
44 {
45         if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0)
46                 return NULL;
47
48         return mipi_dsi[handle];
49 }
50
51 static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
52                               u8 cmd, u8 param)
53 {
54         u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8);
55         int cnt = 100;
56
57         /* transmit a short packet to LCD panel */
58         iowrite32(1 | data, mipi->base + 0x80d0); /* CMTSRTCTR */
59         iowrite32(1, mipi->base + 0x8070); /* CMTSRTREQ */
60
61         while ((ioread32(mipi->base + 0x8070) & 1) && --cnt)
62                 udelay(1);
63
64         return cnt ? 0 : -ETIMEDOUT;
65 }
66
67 #define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \
68                                 -EINVAL : (c) - 1)
69
70 static int sh_mipi_dcs(int handle, u8 cmd)
71 {
72         struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
73         if (!mipi)
74                 return -ENODEV;
75         return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);
76 }
77
78 static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param)
79 {
80         struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
81         if (!mipi)
82                 return -ENODEV;
83         return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd,
84                                   param);
85 }
86
87 static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
88 {
89         /*
90          * enable LCDC data tx, transition to LPS after completion of each HS
91          * packet
92          */
93         iowrite32(0x00000002 | enable, mipi->base + 0x8000); /* DTCTR */
94 }
95
96 static void sh_mipi_shutdown(struct platform_device *pdev)
97 {
98         struct sh_mipi *mipi = platform_get_drvdata(pdev);
99
100         sh_mipi_dsi_enable(mipi, false);
101 }
102
103 static void mipi_display_on(void *arg, struct fb_info *info)
104 {
105         struct sh_mipi *mipi = arg;
106
107         sh_mipi_dsi_enable(mipi, true);
108 }
109
110 static void mipi_display_off(void *arg)
111 {
112         struct sh_mipi *mipi = arg;
113
114         sh_mipi_dsi_enable(mipi, false);
115 }
116
117 static int __init sh_mipi_setup(struct sh_mipi *mipi,
118                                 struct sh_mipi_dsi_info *pdata)
119 {
120         void __iomem *base = mipi->base;
121         struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
122         u32 pctype, datatype, pixfmt;
123         u32 linelength;
124         bool yuv;
125
126         /*
127          * Select data format. MIPI DSI is not hot-pluggable, so, we just use
128          * the default videomode. If this ever becomes a problem, We'll have to
129          * move this to mipi_display_on() above and use info->var.xres
130          */
131         switch (pdata->data_format) {
132         case MIPI_RGB888:
133                 pctype = 0;
134                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
135                 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
136                 linelength = ch->lcd_cfg[0].xres * 3;
137                 yuv = false;
138                 break;
139         case MIPI_RGB565:
140                 pctype = 1;
141                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
142                 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
143                 linelength = ch->lcd_cfg[0].xres * 2;
144                 yuv = false;
145                 break;
146         case MIPI_RGB666_LP:
147                 pctype = 2;
148                 datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
149                 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
150                 linelength = ch->lcd_cfg[0].xres * 3;
151                 yuv = false;
152                 break;
153         case MIPI_RGB666:
154                 pctype = 3;
155                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
156                 pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
157                 linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
158                 yuv = false;
159                 break;
160         case MIPI_BGR888:
161                 pctype = 8;
162                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
163                 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
164                 linelength = ch->lcd_cfg[0].xres * 3;
165                 yuv = false;
166                 break;
167         case MIPI_BGR565:
168                 pctype = 9;
169                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
170                 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
171                 linelength = ch->lcd_cfg[0].xres * 2;
172                 yuv = false;
173                 break;
174         case MIPI_BGR666_LP:
175                 pctype = 0xa;
176                 datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
177                 pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
178                 linelength = ch->lcd_cfg[0].xres * 3;
179                 yuv = false;
180                 break;
181         case MIPI_BGR666:
182                 pctype = 0xb;
183                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
184                 pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
185                 linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
186                 yuv = false;
187                 break;
188         case MIPI_YUYV:
189                 pctype = 4;
190                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
191                 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
192                 linelength = ch->lcd_cfg[0].xres * 2;
193                 yuv = true;
194                 break;
195         case MIPI_UYVY:
196                 pctype = 5;
197                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
198                 pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
199                 linelength = ch->lcd_cfg[0].xres * 2;
200                 yuv = true;
201                 break;
202         case MIPI_YUV420_L:
203                 pctype = 6;
204                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
205                 pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
206                 linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8;
207                 yuv = true;
208                 break;
209         case MIPI_YUV420:
210                 pctype = 7;
211                 datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
212                 pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
213                 /* Length of U/V line */
214                 linelength = (ch->lcd_cfg[0].xres + 1) / 2;
215                 yuv = true;
216                 break;
217         default:
218                 return -EINVAL;
219         }
220
221         if ((yuv && ch->interface_type != YUV422) ||
222             (!yuv && ch->interface_type != RGB24))
223                 return -EINVAL;
224
225         /* reset DSI link */
226         iowrite32(0x00000001, base); /* SYSCTRL */
227         /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
228         udelay(50);
229         iowrite32(0x00000000, base); /* SYSCTRL */
230
231         /* setup DSI link */
232
233         /*
234          * Default = ULPS enable |
235          *      Contention detection enabled |
236          *      EoT packet transmission enable |
237          *      CRC check enable |
238          *      ECC check enable
239          * additionally enable first two lanes
240          */
241         iowrite32(0x00003703, base + 0x04); /* SYSCONF */
242         /*
243          * T_wakeup = 0x7000
244          * T_hs-trail = 3
245          * T_hs-prepare = 3
246          * T_clk-trail = 3
247          * T_clk-prepare = 2
248          */
249         iowrite32(0x70003332, base + 0x08); /* TIMSET */
250         /* no responses requested */
251         iowrite32(0x00000000, base + 0x18); /* RESREQSET0 */
252         /* request response to packets of type 0x28 */
253         iowrite32(0x00000100, base + 0x1c); /* RESREQSET1 */
254         /* High-speed transmission timeout, default 0xffffffff */
255         iowrite32(0x0fffffff, base + 0x20); /* HSTTOVSET */
256         /* LP reception timeout, default 0xffffffff */
257         iowrite32(0x0fffffff, base + 0x24); /* LPRTOVSET */
258         /* Turn-around timeout, default 0xffffffff */
259         iowrite32(0x0fffffff, base + 0x28); /* TATOVSET */
260         /* Peripheral reset timeout, default 0xffffffff */
261         iowrite32(0x0fffffff, base + 0x2c); /* PRTOVSET */
262         /* Enable timeout counters */
263         iowrite32(0x00000f00, base + 0x30); /* DSICTRL */
264         /* Interrupts not used, disable all */
265         iowrite32(0, base + DSIINTE);
266         /* DSI-Tx bias on */
267         iowrite32(0x00000001, base + 0x70); /* PHYCTRL */
268         udelay(200);
269         /* Deassert resets, power on, set multiplier */
270         iowrite32(0x03070b01, base + 0x70); /* PHYCTRL */
271
272         /* setup l-bridge */
273
274         /*
275          * Enable transmission of all packets,
276          * transmit LPS after each HS packet completion
277          */
278         iowrite32(0x00000006, base + 0x8000); /* DTCTR */
279         /* VSYNC width = 2 (<< 17) */
280         iowrite32(0x00040000 | (pctype << 12) | datatype, base + 0x8020); /* VMCTR1 */
281         /*
282          * Non-burst mode with sync pulses: VSE and HSE are output,
283          * HSA period allowed, no commands in LP
284          */
285         iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */
286         /*
287          * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see
288          * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default
289          * (unused, since VMCTR2[HSABM] = 0)
290          */
291         iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */
292
293         msleep(5);
294
295         /* setup LCD panel */
296
297         /* cf. drivers/video/omap/lcd_mipid.c */
298         sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE);
299         msleep(120);
300         /*
301          * [7] - Page Address Mode
302          * [6] - Column Address Mode
303          * [5] - Page / Column Address Mode
304          * [4] - Display Device Line Refresh Order
305          * [3] - RGB/BGR Order
306          * [2] - Display Data Latch Data Order
307          * [1] - Flip Horizontal
308          * [0] - Flip Vertical
309          */
310         sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
311         /* cf. set_data_lines() */
312         sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT,
313                           pixfmt << 4);
314         sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
315
316         return 0;
317 }
318
319 static int __init sh_mipi_probe(struct platform_device *pdev)
320 {
321         struct sh_mipi *mipi;
322         struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
323         struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
324         unsigned long rate, f_current;
325         int idx = pdev->id, ret;
326         char dsip_clk[] = "dsi.p_clk";
327
328         if (!res || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
329                 return -ENODEV;
330
331         mutex_lock(&array_lock);
332         if (idx < 0)
333                 for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
334                         ;
335
336         if (idx == ARRAY_SIZE(mipi_dsi)) {
337                 ret = -EBUSY;
338                 goto efindslot;
339         }
340
341         mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
342         if (!mipi) {
343                 ret = -ENOMEM;
344                 goto ealloc;
345         }
346
347         if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
348                 dev_err(&pdev->dev, "MIPI register region already claimed\n");
349                 ret = -EBUSY;
350                 goto ereqreg;
351         }
352
353         mipi->base = ioremap(res->start, resource_size(res));
354         if (!mipi->base) {
355                 ret = -ENOMEM;
356                 goto emap;
357         }
358
359         mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
360         if (IS_ERR(mipi->dsit_clk)) {
361                 ret = PTR_ERR(mipi->dsit_clk);
362                 goto eclktget;
363         }
364
365         f_current = clk_get_rate(mipi->dsit_clk);
366         /* 80MHz required by the datasheet */
367         rate = clk_round_rate(mipi->dsit_clk, 80000000);
368         if (rate > 0 && rate != f_current)
369                 ret = clk_set_rate(mipi->dsit_clk, rate);
370         else
371                 ret = rate;
372         if (ret < 0)
373                 goto esettrate;
374
375         dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate);
376
377         sprintf(dsip_clk, "dsi%1.1dp_clk", idx);
378         mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk);
379         if (IS_ERR(mipi->dsip_clk)) {
380                 ret = PTR_ERR(mipi->dsip_clk);
381                 goto eclkpget;
382         }
383
384         f_current = clk_get_rate(mipi->dsip_clk);
385         /* Between 10 and 50MHz */
386         rate = clk_round_rate(mipi->dsip_clk, 24000000);
387         if (rate > 0 && rate != f_current)
388                 ret = clk_set_rate(mipi->dsip_clk, rate);
389         else
390                 ret = rate;
391         if (ret < 0)
392                 goto esetprate;
393
394         dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate);
395
396         msleep(10);
397
398         ret = clk_enable(mipi->dsit_clk);
399         if (ret < 0)
400                 goto eclkton;
401
402         ret = clk_enable(mipi->dsip_clk);
403         if (ret < 0)
404                 goto eclkpon;
405
406         mipi_dsi[idx] = mipi;
407
408         ret = sh_mipi_setup(mipi, pdata);
409         if (ret < 0)
410                 goto emipisetup;
411
412         mutex_unlock(&array_lock);
413         platform_set_drvdata(pdev, mipi);
414
415         /* Set up LCDC callbacks */
416         pdata->lcd_chan->board_cfg.board_data = mipi;
417         pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
418         pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
419
420         return 0;
421
422 emipisetup:
423         mipi_dsi[idx] = NULL;
424         clk_disable(mipi->dsip_clk);
425 eclkpon:
426         clk_disable(mipi->dsit_clk);
427 eclkton:
428 esetprate:
429         clk_put(mipi->dsip_clk);
430 eclkpget:
431 esettrate:
432         clk_put(mipi->dsit_clk);
433 eclktget:
434         iounmap(mipi->base);
435 emap:
436         release_mem_region(res->start, resource_size(res));
437 ereqreg:
438         kfree(mipi);
439 ealloc:
440 efindslot:
441         mutex_unlock(&array_lock);
442
443         return ret;
444 }
445
446 static int __exit sh_mipi_remove(struct platform_device *pdev)
447 {
448         struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
449         struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
450         struct sh_mipi *mipi = platform_get_drvdata(pdev);
451         int i, ret;
452
453         mutex_lock(&array_lock);
454
455         for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++)
456                 ;
457
458         if (i == ARRAY_SIZE(mipi_dsi)) {
459                 ret = -EINVAL;
460         } else {
461                 ret = 0;
462                 mipi_dsi[i] = NULL;
463         }
464
465         mutex_unlock(&array_lock);
466
467         if (ret < 0)
468                 return ret;
469
470         pdata->lcd_chan->board_cfg.display_on = NULL;
471         pdata->lcd_chan->board_cfg.display_off = NULL;
472         pdata->lcd_chan->board_cfg.board_data = NULL;
473
474         clk_disable(mipi->dsip_clk);
475         clk_disable(mipi->dsit_clk);
476         clk_put(mipi->dsit_clk);
477         clk_put(mipi->dsip_clk);
478         iounmap(mipi->base);
479         if (res)
480                 release_mem_region(res->start, resource_size(res));
481         platform_set_drvdata(pdev, NULL);
482         kfree(mipi);
483
484         return 0;
485 }
486
487 static struct platform_driver sh_mipi_driver = {
488         .remove         = __exit_p(sh_mipi_remove),
489         .shutdown       = sh_mipi_shutdown,
490         .driver = {
491                 .name   = "sh-mipi-dsi",
492         },
493 };
494
495 static int __init sh_mipi_init(void)
496 {
497         return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
498 }
499 module_init(sh_mipi_init);
500
501 static void __exit sh_mipi_exit(void)
502 {
503         platform_driver_unregister(&sh_mipi_driver);
504 }
505 module_exit(sh_mipi_exit);
506
507 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
508 MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
509 MODULE_LICENSE("GPL v2");