Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[sfrench/cifs-2.6.git] / drivers / video / fbdev / amba-clcd-versatile.c
1 #include <linux/device.h>
2 #include <linux/dma-mapping.h>
3 #include <linux/amba/bus.h>
4 #include <linux/amba/clcd.h>
5 #include <linux/platform_data/video-clcd-versatile.h>
6 #include <linux/of.h>
7 #include <linux/of_graph.h>
8 #include <linux/regmap.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/bitops.h>
11 #include "amba-clcd-versatile.h"
12
13 static struct clcd_panel vga = {
14         .mode           = {
15                 .name           = "VGA",
16                 .refresh        = 60,
17                 .xres           = 640,
18                 .yres           = 480,
19                 .pixclock       = 39721,
20                 .left_margin    = 40,
21                 .right_margin   = 24,
22                 .upper_margin   = 32,
23                 .lower_margin   = 11,
24                 .hsync_len      = 96,
25                 .vsync_len      = 2,
26                 .sync           = 0,
27                 .vmode          = FB_VMODE_NONINTERLACED,
28         },
29         .width          = -1,
30         .height         = -1,
31         .tim2           = TIM2_BCD | TIM2_IPC,
32         .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
33         .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
34         .bpp            = 16,
35 };
36
37 static struct clcd_panel xvga = {
38         .mode           = {
39                 .name           = "XVGA",
40                 .refresh        = 60,
41                 .xres           = 1024,
42                 .yres           = 768,
43                 .pixclock       = 15748,
44                 .left_margin    = 152,
45                 .right_margin   = 48,
46                 .upper_margin   = 23,
47                 .lower_margin   = 3,
48                 .hsync_len      = 104,
49                 .vsync_len      = 4,
50                 .sync           = 0,
51                 .vmode          = FB_VMODE_NONINTERLACED,
52         },
53         .width          = -1,
54         .height         = -1,
55         .tim2           = TIM2_BCD | TIM2_IPC,
56         .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
57         .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
58         .bpp            = 16,
59 };
60
61 /* Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT */
62 static struct clcd_panel sanyo_tm38qv67a02a = {
63         .mode           = {
64                 .name           = "Sanyo TM38QV67A02A",
65                 .refresh        = 116,
66                 .xres           = 320,
67                 .yres           = 240,
68                 .pixclock       = 100000,
69                 .left_margin    = 6,
70                 .right_margin   = 6,
71                 .upper_margin   = 5,
72                 .lower_margin   = 5,
73                 .hsync_len      = 6,
74                 .vsync_len      = 6,
75                 .sync           = 0,
76                 .vmode          = FB_VMODE_NONINTERLACED,
77         },
78         .width          = -1,
79         .height         = -1,
80         .tim2           = TIM2_BCD,
81         .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
82         .caps           = CLCD_CAP_5551,
83         .bpp            = 16,
84 };
85
86 static struct clcd_panel sanyo_2_5_in = {
87         .mode           = {
88                 .name           = "Sanyo QVGA Portrait",
89                 .refresh        = 116,
90                 .xres           = 240,
91                 .yres           = 320,
92                 .pixclock       = 100000,
93                 .left_margin    = 20,
94                 .right_margin   = 10,
95                 .upper_margin   = 2,
96                 .lower_margin   = 2,
97                 .hsync_len      = 10,
98                 .vsync_len      = 2,
99                 .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
100                 .vmode          = FB_VMODE_NONINTERLACED,
101         },
102         .width          = -1,
103         .height         = -1,
104         .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
105         .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
106         .caps           = CLCD_CAP_5551,
107         .bpp            = 16,
108 };
109
110 /* Epson L2F50113T00 - 2.2 inch 176x220 Color TFT */
111 static struct clcd_panel epson_l2f50113t00 = {
112         .mode           = {
113                 .name           = "Epson L2F50113T00",
114                 .refresh        = 390,
115                 .xres           = 176,
116                 .yres           = 220,
117                 .pixclock       = 62500,
118                 .left_margin    = 3,
119                 .right_margin   = 2,
120                 .upper_margin   = 1,
121                 .lower_margin   = 0,
122                 .hsync_len      = 3,
123                 .vsync_len      = 2,
124                 .sync           = 0,
125                 .vmode          = FB_VMODE_NONINTERLACED,
126         },
127         .width          = -1,
128         .height         = -1,
129         .tim2           = TIM2_BCD | TIM2_IPC,
130         .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
131         .caps           = CLCD_CAP_5551,
132         .bpp            = 16,
133 };
134
135 static struct clcd_panel *panels[] = {
136         &vga,
137         &xvga,
138         &sanyo_tm38qv67a02a,
139         &sanyo_2_5_in,
140         &epson_l2f50113t00,
141 };
142
143 struct clcd_panel *versatile_clcd_get_panel(const char *name)
144 {
145         int i;
146
147         for (i = 0; i < ARRAY_SIZE(panels); i++)
148                 if (strcmp(panels[i]->mode.name, name) == 0)
149                         break;
150
151         if (i < ARRAY_SIZE(panels))
152                 return panels[i];
153
154         pr_err("CLCD: couldn't get parameters for panel %s\n", name);
155
156         return NULL;
157 }
158
159 int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
160 {
161         dma_addr_t dma;
162
163         fb->fb.screen_base = dma_alloc_wc(&fb->dev->dev, framesize, &dma,
164                                           GFP_KERNEL);
165         if (!fb->fb.screen_base) {
166                 pr_err("CLCD: unable to map framebuffer\n");
167                 return -ENOMEM;
168         }
169
170         fb->fb.fix.smem_start   = dma;
171         fb->fb.fix.smem_len     = framesize;
172
173         return 0;
174 }
175
176 int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
177 {
178         return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
179                            fb->fb.fix.smem_start, fb->fb.fix.smem_len);
180 }
181
182 void versatile_clcd_remove_dma(struct clcd_fb *fb)
183 {
184         dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base,
185                     fb->fb.fix.smem_start);
186 }
187
188 #ifdef CONFIG_OF
189
190 static struct regmap *versatile_syscon_map;
191 static struct regmap *versatile_ib2_map;
192
193 /*
194  * We detect the different syscon types from the compatible strings.
195  */
196 enum versatile_clcd {
197         INTEGRATOR_CLCD_CM,
198         VERSATILE_CLCD,
199         REALVIEW_CLCD_EB,
200         REALVIEW_CLCD_PB1176,
201         REALVIEW_CLCD_PB11MP,
202         REALVIEW_CLCD_PBA8,
203         REALVIEW_CLCD_PBX,
204 };
205
206 static const struct of_device_id versatile_clcd_of_match[] = {
207         {
208                 .compatible = "arm,core-module-integrator",
209                 .data = (void *)INTEGRATOR_CLCD_CM,
210         },
211         {
212                 .compatible = "arm,versatile-sysreg",
213                 .data = (void *)VERSATILE_CLCD,
214         },
215         {
216                 .compatible = "arm,realview-eb-syscon",
217                 .data = (void *)REALVIEW_CLCD_EB,
218         },
219         {
220                 .compatible = "arm,realview-pb1176-syscon",
221                 .data = (void *)REALVIEW_CLCD_PB1176,
222         },
223         {
224                 .compatible = "arm,realview-pb11mp-syscon",
225                 .data = (void *)REALVIEW_CLCD_PB11MP,
226         },
227         {
228                 .compatible = "arm,realview-pba8-syscon",
229                 .data = (void *)REALVIEW_CLCD_PBA8,
230         },
231         {
232                 .compatible = "arm,realview-pbx-syscon",
233                 .data = (void *)REALVIEW_CLCD_PBX,
234         },
235         {},
236 };
237
238 /*
239  * Core module CLCD control on the Integrator/CP, bits
240  * 8 thru 19 of the CM_CONTROL register controls a bunch
241  * of CLCD settings.
242  */
243 #define INTEGRATOR_HDR_CTRL_OFFSET      0x0C
244 #define INTEGRATOR_CLCD_LCDBIASEN       BIT(8)
245 #define INTEGRATOR_CLCD_LCDBIASUP       BIT(9)
246 #define INTEGRATOR_CLCD_LCDBIASDN       BIT(10)
247 /* Bits 11,12,13 controls the LCD type */
248 #define INTEGRATOR_CLCD_LCDMUX_MASK     (BIT(11)|BIT(12)|BIT(13))
249 #define INTEGRATOR_CLCD_LCDMUX_LCD24    BIT(11)
250 #define INTEGRATOR_CLCD_LCDMUX_VGA565   BIT(12)
251 #define INTEGRATOR_CLCD_LCDMUX_SHARP    (BIT(11)|BIT(12))
252 #define INTEGRATOR_CLCD_LCDMUX_VGA555   BIT(13)
253 #define INTEGRATOR_CLCD_LCDMUX_VGA24    (BIT(11)|BIT(12)|BIT(13))
254 #define INTEGRATOR_CLCD_LCD0_EN         BIT(14)
255 #define INTEGRATOR_CLCD_LCD1_EN         BIT(15)
256 /* R/L flip on Sharp */
257 #define INTEGRATOR_CLCD_LCD_STATIC1     BIT(16)
258 /* U/D flip on Sharp */
259 #define INTEGRATOR_CLCD_LCD_STATIC2     BIT(17)
260 /* No connection on Sharp */
261 #define INTEGRATOR_CLCD_LCD_STATIC      BIT(18)
262 /* 0 = 24bit VGA, 1 = 18bit VGA */
263 #define INTEGRATOR_CLCD_LCD_N24BITEN    BIT(19)
264
265 #define INTEGRATOR_CLCD_MASK            (INTEGRATOR_CLCD_LCDBIASEN | \
266                                          INTEGRATOR_CLCD_LCDBIASUP | \
267                                          INTEGRATOR_CLCD_LCDBIASDN | \
268                                          INTEGRATOR_CLCD_LCDMUX_MASK | \
269                                          INTEGRATOR_CLCD_LCD0_EN | \
270                                          INTEGRATOR_CLCD_LCD1_EN | \
271                                          INTEGRATOR_CLCD_LCD_STATIC1 | \
272                                          INTEGRATOR_CLCD_LCD_STATIC2 | \
273                                          INTEGRATOR_CLCD_LCD_STATIC | \
274                                          INTEGRATOR_CLCD_LCD_N24BITEN)
275
276 static void integrator_clcd_enable(struct clcd_fb *fb)
277 {
278         struct fb_var_screeninfo *var = &fb->fb.var;
279         u32 val;
280
281         dev_info(&fb->dev->dev, "enable Integrator CLCD connectors\n");
282
283         /* FIXME: really needed? */
284         val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
285                 INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
286         if (var->bits_per_pixel <= 8 ||
287             (var->bits_per_pixel == 16 && var->green.length == 5))
288                 /* Pseudocolor, RGB555, BGR555 */
289                 val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
290         else if (fb->fb.var.bits_per_pixel <= 16)
291                 /* truecolor RGB565 */
292                 val |= INTEGRATOR_CLCD_LCDMUX_VGA565;
293         else
294                 val = 0; /* no idea for this, don't trust the docs */
295
296         regmap_update_bits(versatile_syscon_map,
297                            INTEGRATOR_HDR_CTRL_OFFSET,
298                            INTEGRATOR_CLCD_MASK,
299                            val);
300 }
301
302 /*
303  * This configuration register in the Versatile and RealView
304  * family is uniformly present but appears more and more
305  * unutilized starting with the RealView series.
306  */
307 #define SYS_CLCD                        0x50
308 #define SYS_CLCD_MODE_MASK              (BIT(0)|BIT(1))
309 #define SYS_CLCD_MODE_888               0
310 #define SYS_CLCD_MODE_5551              BIT(0)
311 #define SYS_CLCD_MODE_565_R_LSB         BIT(1)
312 #define SYS_CLCD_MODE_565_B_LSB         (BIT(0)|BIT(1))
313 #define SYS_CLCD_CONNECTOR_MASK         (BIT(2)|BIT(3)|BIT(4)|BIT(5))
314 #define SYS_CLCD_NLCDIOON               BIT(2)
315 #define SYS_CLCD_VDDPOSSWITCH           BIT(3)
316 #define SYS_CLCD_PWR3V5SWITCH           BIT(4)
317 #define SYS_CLCD_VDDNEGSWITCH           BIT(5)
318 #define SYS_CLCD_TSNSS                  BIT(6) /* touchscreen enable */
319 #define SYS_CLCD_SSPEXP                 BIT(7) /* SSP expansion enable */
320
321 /* The Versatile can detect the connected panel type */
322 #define SYS_CLCD_CLCDID_MASK            (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12))
323 #define SYS_CLCD_ID_SANYO_3_8           (0x00 << 8)
324 #define SYS_CLCD_ID_SHARP_8_4           (0x01 << 8)
325 #define SYS_CLCD_ID_EPSON_2_2           (0x02 << 8)
326 #define SYS_CLCD_ID_SANYO_2_5           (0x07 << 8)
327 #define SYS_CLCD_ID_VGA                 (0x1f << 8)
328
329 #define SYS_CLCD_TSNDAV                 BIT(13) /* data ready from TS */
330
331 /* IB2 control register for the Versatile daughterboard */
332 #define IB2_CTRL                        0x00
333 #define IB2_CTRL_LCD_SD                 BIT(1) /* 1 = shut down LCD */
334 #define IB2_CTRL_LCD_BL_ON              BIT(0)
335 #define IB2_CTRL_LCD_MASK               (BIT(0)|BIT(1))
336
337 static void versatile_clcd_disable(struct clcd_fb *fb)
338 {
339         dev_info(&fb->dev->dev, "disable Versatile CLCD connectors\n");
340         regmap_update_bits(versatile_syscon_map,
341                            SYS_CLCD,
342                            SYS_CLCD_CONNECTOR_MASK,
343                            0);
344
345         /* If we're on an IB2 daughterboard, turn off display */
346         if (versatile_ib2_map) {
347                 dev_info(&fb->dev->dev, "disable IB2 display\n");
348                 regmap_update_bits(versatile_ib2_map,
349                                    IB2_CTRL,
350                                    IB2_CTRL_LCD_MASK,
351                                    IB2_CTRL_LCD_SD);
352         }
353 }
354
355 static void versatile_clcd_enable(struct clcd_fb *fb)
356 {
357         struct fb_var_screeninfo *var = &fb->fb.var;
358         u32 val = 0;
359
360         dev_info(&fb->dev->dev, "enable Versatile CLCD connectors\n");
361         switch (var->green.length) {
362         case 5:
363                 val |= SYS_CLCD_MODE_5551;
364                 break;
365         case 6:
366                 if (var->red.offset == 0)
367                         val |= SYS_CLCD_MODE_565_R_LSB;
368                 else
369                         val |= SYS_CLCD_MODE_565_B_LSB;
370                 break;
371         case 8:
372                 val |= SYS_CLCD_MODE_888;
373                 break;
374         }
375
376         /* Set up the MUX */
377         regmap_update_bits(versatile_syscon_map,
378                            SYS_CLCD,
379                            SYS_CLCD_MODE_MASK,
380                            val);
381
382         /* Then enable the display */
383         regmap_update_bits(versatile_syscon_map,
384                            SYS_CLCD,
385                            SYS_CLCD_CONNECTOR_MASK,
386                            SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
387
388         /* If we're on an IB2 daughterboard, turn on display */
389         if (versatile_ib2_map) {
390                 dev_info(&fb->dev->dev, "enable IB2 display\n");
391                 regmap_update_bits(versatile_ib2_map,
392                                    IB2_CTRL,
393                                    IB2_CTRL_LCD_MASK,
394                                    IB2_CTRL_LCD_BL_ON);
395         }
396 }
397
398 static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
399 {
400         clcdfb_decode(fb, regs);
401
402         /* Always clear BGR for RGB565: we do the routing externally */
403         if (fb->fb.var.green.length == 6)
404                 regs->cntl &= ~CNTL_BGR;
405 }
406
407 static void realview_clcd_disable(struct clcd_fb *fb)
408 {
409         dev_info(&fb->dev->dev, "disable RealView CLCD connectors\n");
410         regmap_update_bits(versatile_syscon_map,
411                            SYS_CLCD,
412                            SYS_CLCD_CONNECTOR_MASK,
413                            0);
414 }
415
416 static void realview_clcd_enable(struct clcd_fb *fb)
417 {
418         dev_info(&fb->dev->dev, "enable RealView CLCD connectors\n");
419         regmap_update_bits(versatile_syscon_map,
420                            SYS_CLCD,
421                            SYS_CLCD_CONNECTOR_MASK,
422                            SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
423 }
424
425 struct versatile_panel {
426         u32 id;
427         char *compatible;
428         bool ib2;
429 };
430
431 static const struct versatile_panel versatile_panels[] = {
432         {
433                 .id = SYS_CLCD_ID_VGA,
434                 .compatible = "VGA",
435         },
436         {
437                 .id = SYS_CLCD_ID_SANYO_3_8,
438                 .compatible = "sanyo,tm38qv67a02a",
439         },
440         {
441                 .id = SYS_CLCD_ID_SHARP_8_4,
442                 .compatible = "sharp,lq084v1dg21",
443         },
444         {
445                 .id = SYS_CLCD_ID_EPSON_2_2,
446                 .compatible = "epson,l2f50113t00",
447         },
448         {
449                 .id = SYS_CLCD_ID_SANYO_2_5,
450                 .compatible = "sanyo,alr252rgt",
451                 .ib2 = true,
452         },
453 };
454
455 static void versatile_panel_probe(struct device *dev, struct device_node *panel)
456 {
457         struct versatile_panel const *vpanel = NULL;
458         u32 val;
459         int ret;
460         int i;
461
462         /*
463          * The Versatile CLCD has a panel auto-detection mechanism.
464          * We use this and look for the compatible panel in the
465          * device tree.
466          */
467         ret = regmap_read(versatile_syscon_map, SYS_CLCD, &val);
468         if (ret) {
469                 dev_err(dev, "cannot read CLCD syscon register\n");
470                 return;
471         }
472         val &= SYS_CLCD_CLCDID_MASK;
473
474         /* First find corresponding panel information */
475         for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) {
476                 vpanel = &versatile_panels[i];
477
478                 if (val == vpanel->id) {
479                         dev_err(dev, "autodetected panel \"%s\"\n",
480                                 vpanel->compatible);
481                         break;
482                 }
483         }
484         if (i == ARRAY_SIZE(versatile_panels)) {
485                 dev_err(dev, "could not auto-detect panel\n");
486                 return;
487         }
488
489         if (!of_device_is_compatible(panel, vpanel->compatible))
490                 dev_err(dev, "panel in DT is not compatible with the "
491                         "auto-detected panel, continuing anyway\n");
492
493         /*
494          * If we have a Sanyo 2.5" port
495          * that we're running on an IB2 and proceed to look for the
496          * IB2 syscon regmap.
497          */
498         if (!vpanel->ib2)
499                 return;
500
501         versatile_ib2_map = syscon_regmap_lookup_by_compatible(
502                 "arm,versatile-ib2-syscon");
503         if (IS_ERR(versatile_ib2_map)) {
504                 dev_err(dev, "could not locate IB2 control register\n");
505                 versatile_ib2_map = NULL;
506                 return;
507         }
508 }
509
510 int versatile_clcd_init_panel(struct clcd_fb *fb, struct device_node *panel)
511 {
512         const struct of_device_id *clcd_id;
513         enum versatile_clcd versatile_clcd_type;
514         struct device_node *np;
515         struct regmap *map;
516         struct device *dev = &fb->dev->dev;
517
518         np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
519                                              &clcd_id);
520         if (!np) {
521                 /* Vexpress does not have this */
522                 return 0;
523         }
524         versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
525
526         map = syscon_node_to_regmap(np);
527         if (IS_ERR(map)) {
528                 dev_err(dev, "no Versatile syscon regmap\n");
529                 return PTR_ERR(map);
530         }
531
532         switch (versatile_clcd_type) {
533         case INTEGRATOR_CLCD_CM:
534                 versatile_syscon_map = map;
535                 fb->board->enable = integrator_clcd_enable;
536                 /* Override the caps, we have only these */
537                 fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 |
538                         CLCD_CAP_888;
539                 dev_info(dev, "set up callbacks for Integrator PL110\n");
540                 break;
541         case VERSATILE_CLCD:
542                 versatile_syscon_map = map;
543                 fb->board->enable = versatile_clcd_enable;
544                 fb->board->disable = versatile_clcd_disable;
545                 fb->board->decode = versatile_clcd_decode;
546                 versatile_panel_probe(dev, panel);
547                 dev_info(dev, "set up callbacks for Versatile\n");
548                 break;
549         case REALVIEW_CLCD_EB:
550         case REALVIEW_CLCD_PB1176:
551         case REALVIEW_CLCD_PB11MP:
552         case REALVIEW_CLCD_PBA8:
553         case REALVIEW_CLCD_PBX:
554                 versatile_syscon_map = map;
555                 fb->board->enable = realview_clcd_enable;
556                 fb->board->disable = realview_clcd_disable;
557                 dev_info(dev, "set up callbacks for RealView PL111\n");
558                 break;
559         default:
560                 dev_info(dev, "unknown Versatile system controller\n");
561                 break;
562         }
563
564         return 0;
565 }
566 EXPORT_SYMBOL_GPL(versatile_clcd_init_panel);
567 #endif