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