aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2016-06-16 05:36:18 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2016-08-11 10:54:54 -0400
commit25348160e9a444d64f589a8106bc06549934223e (patch)
treefdb0e9f944d9af27075728c85e28b4250029d9c9 /drivers/video
parent1d3f0cbe0d3a537cbc8fb1a91f6d14407acece62 (diff)
video: ARM CLCD: add special panel hook for Versatiles
This adds a special panel init hook for the ARM reference designs Integrator (IM-PD1), Versatile and RealView, so we can configure a DPI panel from device tree and have it working without boardfiles for these machines. Basically this is the same code as from the board files, just moved over to look up the syscon DT node and manipulate the special CLCD register from their regmap. Tested on RealView PB11MPcore. Cc: Pawel Moll <pawel.moll@arm.com> Cc: Rob Herring <robh@kernel.org> Cc: Russell King <linux@arm.linux.org.uk> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/Kconfig2
-rw-r--r--drivers/video/fbdev/amba-clcd-versatile.c391
-rw-r--r--drivers/video/fbdev/amba-clcd-versatile.h17
-rw-r--r--drivers/video/fbdev/amba-clcd.c4
4 files changed, 413 insertions, 1 deletions
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 9b9a76b82c04..6c28ecc3958c 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -307,6 +307,8 @@ config PLAT_VERSATILE_CLCD
307 def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR 307 def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR
308 depends on ARM 308 depends on ARM
309 depends on FB_ARMCLCD && FB=y 309 depends on FB_ARMCLCD && FB=y
310 select REGMAP
311 select MFD_SYSCON
310 312
311config FB_ACORN 313config FB_ACORN
312 bool "Acorn VIDC support" 314 bool "Acorn VIDC support"
diff --git a/drivers/video/fbdev/amba-clcd-versatile.c b/drivers/video/fbdev/amba-clcd-versatile.c
index a8a22daa3f9d..9a90817b1550 100644
--- a/drivers/video/fbdev/amba-clcd-versatile.c
+++ b/drivers/video/fbdev/amba-clcd-versatile.c
@@ -3,6 +3,12 @@
3#include <linux/amba/bus.h> 3#include <linux/amba/bus.h>
4#include <linux/amba/clcd.h> 4#include <linux/amba/clcd.h>
5#include <linux/platform_data/video-clcd-versatile.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"
6 12
7static struct clcd_panel vga = { 13static struct clcd_panel vga = {
8 .mode = { 14 .mode = {
@@ -178,3 +184,388 @@ void versatile_clcd_remove_dma(struct clcd_fb *fb)
178 dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base, 184 dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base,
179 fb->fb.fix.smem_start); 185 fb->fb.fix.smem_start);
180} 186}
187
188#ifdef CONFIG_OF
189
190static struct regmap *versatile_syscon_map;
191static struct regmap *versatile_ib2_map;
192
193/*
194 * We detect the different syscon types from the compatible strings.
195 */
196enum 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
206static 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_LCDMUX_MASK | \
266 INTEGRATOR_CLCD_LCD0_EN | \
267 INTEGRATOR_CLCD_LCD1_EN | \
268 INTEGRATOR_CLCD_LCD_STATIC1 | \
269 INTEGRATOR_CLCD_LCD_STATIC2 | \
270 INTEGRATOR_CLCD_LCD_STATIC | \
271 INTEGRATOR_CLCD_LCD_N24BITEN)
272
273static void integrator_clcd_enable(struct clcd_fb *fb)
274{
275 struct fb_var_screeninfo *var = &fb->fb.var;
276 u32 val;
277
278 dev_info(&fb->dev->dev, "enable Integrator CLCD connectors\n");
279
280 val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
281 INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
282 if (var->bits_per_pixel <= 8 ||
283 (var->bits_per_pixel == 16 && var->green.length == 5))
284 /* Pseudocolor, RGB555, BGR555 */
285 val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
286 else if (fb->fb.var.bits_per_pixel <= 16)
287 /* truecolor RGB565 */
288 val |= INTEGRATOR_CLCD_LCDMUX_VGA565;
289 else
290 val = 0; /* no idea for this, don't trust the docs */
291
292 regmap_update_bits(versatile_syscon_map,
293 INTEGRATOR_HDR_CTRL_OFFSET,
294 0,
295 INTEGRATOR_CLCD_MASK);
296}
297
298/*
299 * This configuration register in the Versatile and RealView
300 * family is uniformly present but appears more and more
301 * unutilized starting with the RealView series.
302 */
303#define SYS_CLCD 0x50
304#define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1))
305#define SYS_CLCD_MODE_888 0
306#define SYS_CLCD_MODE_5551 BIT(0)
307#define SYS_CLCD_MODE_565_R_LSB BIT(1)
308#define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1))
309#define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5))
310#define SYS_CLCD_NLCDIOON BIT(2)
311#define SYS_CLCD_VDDPOSSWITCH BIT(3)
312#define SYS_CLCD_PWR3V5SWITCH BIT(4)
313#define SYS_CLCD_VDDNEGSWITCH BIT(5)
314#define SYS_CLCD_TSNSS BIT(6) /* touchscreen enable */
315#define SYS_CLCD_SSPEXP BIT(7) /* SSP expansion enable */
316
317/* The Versatile can detect the connected panel type */
318#define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12))
319#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
320#define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8)
321#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
322#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
323#define SYS_CLCD_ID_VGA (0x1f << 8)
324
325#define SYS_CLCD_TSNDAV BIT(13) /* data ready from TS */
326
327/* IB2 control register for the Versatile daughterboard */
328#define IB2_CTRL 0x00
329#define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */
330#define IB2_CTRL_LCD_BL_ON BIT(0)
331#define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1))
332
333static void versatile_clcd_disable(struct clcd_fb *fb)
334{
335 dev_info(&fb->dev->dev, "disable Versatile CLCD connectors\n");
336 regmap_update_bits(versatile_syscon_map,
337 SYS_CLCD,
338 SYS_CLCD_CONNECTOR_MASK,
339 0);
340
341 /* If we're on an IB2 daughterboard, turn off display */
342 if (versatile_ib2_map) {
343 dev_info(&fb->dev->dev, "disable IB2 display\n");
344 regmap_update_bits(versatile_ib2_map,
345 IB2_CTRL,
346 IB2_CTRL_LCD_MASK,
347 IB2_CTRL_LCD_SD);
348 }
349}
350
351static void versatile_clcd_enable(struct clcd_fb *fb)
352{
353 struct fb_var_screeninfo *var = &fb->fb.var;
354 u32 val = 0;
355
356 dev_info(&fb->dev->dev, "enable Versatile CLCD connectors\n");
357 switch (var->green.length) {
358 case 5:
359 val |= SYS_CLCD_MODE_5551;
360 break;
361 case 6:
362 if (var->red.offset == 0)
363 val |= SYS_CLCD_MODE_565_R_LSB;
364 else
365 val |= SYS_CLCD_MODE_565_B_LSB;
366 break;
367 case 8:
368 val |= SYS_CLCD_MODE_888;
369 break;
370 }
371
372 /* Set up the MUX */
373 regmap_update_bits(versatile_syscon_map,
374 SYS_CLCD,
375 SYS_CLCD_MODE_MASK,
376 val);
377
378 /* Then enable the display */
379 regmap_update_bits(versatile_syscon_map,
380 SYS_CLCD,
381 SYS_CLCD_CONNECTOR_MASK,
382 SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
383
384 /* If we're on an IB2 daughterboard, turn on display */
385 if (versatile_ib2_map) {
386 dev_info(&fb->dev->dev, "enable IB2 display\n");
387 regmap_update_bits(versatile_ib2_map,
388 IB2_CTRL,
389 IB2_CTRL_LCD_MASK,
390 IB2_CTRL_LCD_BL_ON);
391 }
392}
393
394static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
395{
396 clcdfb_decode(fb, regs);
397
398 /* Always clear BGR for RGB565: we do the routing externally */
399 if (fb->fb.var.green.length == 6)
400 regs->cntl &= ~CNTL_BGR;
401}
402
403static void realview_clcd_disable(struct clcd_fb *fb)
404{
405 dev_info(&fb->dev->dev, "disable RealView CLCD connectors\n");
406 regmap_update_bits(versatile_syscon_map,
407 SYS_CLCD,
408 SYS_CLCD_CONNECTOR_MASK,
409 0);
410}
411
412static void realview_clcd_enable(struct clcd_fb *fb)
413{
414 dev_info(&fb->dev->dev, "enable RealView CLCD connectors\n");
415 regmap_update_bits(versatile_syscon_map,
416 SYS_CLCD,
417 SYS_CLCD_CONNECTOR_MASK,
418 SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
419}
420
421struct versatile_panel {
422 u32 id;
423 char *compatible;
424 bool ib2;
425};
426
427static const struct versatile_panel versatile_panels[] = {
428 {
429 .id = SYS_CLCD_ID_VGA,
430 .compatible = "VGA",
431 },
432 {
433 .id = SYS_CLCD_ID_SANYO_3_8,
434 .compatible = "sanyo,tm38qv67a02a",
435 },
436 {
437 .id = SYS_CLCD_ID_SHARP_8_4,
438 .compatible = "sharp,lq084v1dg21",
439 },
440 {
441 .id = SYS_CLCD_ID_EPSON_2_2,
442 .compatible = "epson,l2f50113t00",
443 },
444 {
445 .id = SYS_CLCD_ID_SANYO_2_5,
446 .compatible = "sanyo,alr252rgt",
447 .ib2 = true,
448 },
449};
450
451static void versatile_panel_probe(struct device *dev,
452 struct device_node *endpoint)
453{
454 struct versatile_panel const *vpanel = NULL;
455 struct device_node *panel = NULL;
456 u32 val;
457 int ret;
458 int i;
459
460 /*
461 * The Versatile CLCD has a panel auto-detection mechanism.
462 * We use this and look for the compatible panel in the
463 * device tree.
464 */
465 ret = regmap_read(versatile_syscon_map, SYS_CLCD, &val);
466 if (ret) {
467 dev_err(dev, "cannot read CLCD syscon register\n");
468 return;
469 }
470 val &= SYS_CLCD_CLCDID_MASK;
471
472 /* First find corresponding panel information */
473 for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) {
474 vpanel = &versatile_panels[i];
475
476 if (val == vpanel->id) {
477 dev_err(dev, "autodetected panel \"%s\"\n",
478 vpanel->compatible);
479 break;
480 }
481 }
482 if (i == ARRAY_SIZE(versatile_panels)) {
483 dev_err(dev, "could not auto-detect panel\n");
484 return;
485 }
486
487 panel = of_graph_get_remote_port_parent(endpoint);
488 if (!panel) {
489 dev_err(dev, "could not locate panel in DT\n");
490 return;
491 }
492 if (!of_device_is_compatible(panel, vpanel->compatible))
493 dev_err(dev, "panel in DT is not compatible with the "
494 "auto-detected panel, continuing anyway\n");
495
496 /*
497 * If we have a Sanyo 2.5" port
498 * that we're running on an IB2 and proceed to look for the
499 * IB2 syscon regmap.
500 */
501 if (!vpanel->ib2)
502 return;
503
504 versatile_ib2_map = syscon_regmap_lookup_by_compatible(
505 "arm,versatile-ib2-syscon");
506 if (IS_ERR(versatile_ib2_map)) {
507 dev_err(dev, "could not locate IB2 control register\n");
508 versatile_ib2_map = NULL;
509 return;
510 }
511}
512
513int versatile_clcd_init_panel(struct clcd_fb *fb,
514 struct device_node *endpoint)
515{
516 const struct of_device_id *clcd_id;
517 enum versatile_clcd versatile_clcd_type;
518 struct device_node *np;
519 struct regmap *map;
520 struct device *dev = &fb->dev->dev;
521
522 np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
523 &clcd_id);
524 if (!np) {
525 dev_err(dev, "no Versatile syscon node\n");
526 return -ENODEV;
527 }
528 versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
529
530 map = syscon_node_to_regmap(np);
531 if (!map) {
532 dev_err(dev, "no Versatile syscon regmap\n");
533 return -ENODEV;
534 }
535
536 switch (versatile_clcd_type) {
537 case INTEGRATOR_CLCD_CM:
538 versatile_syscon_map = map;
539 fb->board->enable = integrator_clcd_enable;
540 /* Override the caps, we have only these */
541 fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 |
542 CLCD_CAP_888;
543 dev_info(dev, "set up callbacks for Integrator PL110\n");
544 break;
545 case VERSATILE_CLCD:
546 versatile_syscon_map = map;
547 fb->board->enable = versatile_clcd_enable;
548 fb->board->disable = versatile_clcd_disable;
549 fb->board->decode = versatile_clcd_decode;
550 versatile_panel_probe(dev, endpoint);
551 dev_info(dev, "set up callbacks for Versatile\n");
552 break;
553 case REALVIEW_CLCD_EB:
554 case REALVIEW_CLCD_PB1176:
555 case REALVIEW_CLCD_PB11MP:
556 case REALVIEW_CLCD_PBA8:
557 case REALVIEW_CLCD_PBX:
558 versatile_syscon_map = map;
559 fb->board->enable = realview_clcd_enable;
560 fb->board->disable = realview_clcd_disable;
561 dev_info(dev, "set up callbacks for RealView PL111\n");
562 break;
563 default:
564 dev_info(dev, "unknown Versatile system controller\n");
565 break;
566 }
567
568 return 0;
569}
570
571#endif
diff --git a/drivers/video/fbdev/amba-clcd-versatile.h b/drivers/video/fbdev/amba-clcd-versatile.h
new file mode 100644
index 000000000000..1b14359c2cf6
--- /dev/null
+++ b/drivers/video/fbdev/amba-clcd-versatile.h
@@ -0,0 +1,17 @@
1/*
2 * Special local versatile callbacks
3 */
4#include <linux/of.h>
5#include <linux/amba/bus.h>
6#include <linux/platform_data/video-clcd-versatile.h>
7
8#if defined(CONFIG_PLAT_VERSATILE_CLCD) && defined(CONFIG_OF)
9int versatile_clcd_init_panel(struct clcd_fb *fb,
10 struct device_node *endpoint);
11#else
12static inline int versatile_clcd_init_panel(struct clcd_fb *fb,
13 struct device_node *endpoint)
14{
15 return 0;
16}
17#endif
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 2b45c7be4815..c342ff370108 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -36,6 +36,7 @@
36#include <video/videomode.h> 36#include <video/videomode.h>
37 37
38#include "amba-clcd-nomadik.h" 38#include "amba-clcd-nomadik.h"
39#include "amba-clcd-versatile.h"
39 40
40#define to_clcd(info) container_of(info, struct clcd_fb, fb) 41#define to_clcd(info) container_of(info, struct clcd_fb, fb)
41 42
@@ -1036,7 +1037,8 @@ static int clcdfb_remove(struct amba_device *dev)
1036} 1037}
1037 1038
1038static struct clcd_vendor_data vendor_arm = { 1039static struct clcd_vendor_data vendor_arm = {
1039 /* No special business */ 1040 /* Sets up the versatile board displays */
1041 .init_panel = versatile_clcd_init_panel,
1040}; 1042};
1041 1043
1042static struct clcd_vendor_data vendor_nomadik = { 1044static struct clcd_vendor_data vendor_nomadik = {