at v4.20-rc2 567 lines 14 kB view raw
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 13static 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 37static 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 */ 62static 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 86static 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 */ 111static 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 135static struct clcd_panel *panels[] = { 136 &vga, 137 &xvga, 138 &sanyo_tm38qv67a02a, 139 &sanyo_2_5_in, 140 &epson_l2f50113t00, 141}; 142 143struct 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 159int 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 176int 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 182void 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 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_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 276static 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 337static 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 355static 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 398static 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 407static 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 416static 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 425struct versatile_panel { 426 u32 id; 427 char *compatible; 428 bool ib2; 429}; 430 431static 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 455static 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 510int 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} 566EXPORT_SYMBOL_GPL(versatile_clcd_init_panel); 567#endif