blob: 74e944b636d358a58930eb97d5513f28c15d2250 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/time.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/spinlock.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/semaphore.h>
24#include <linux/uaccess.h>
25#include <linux/clk.h>
26#include <linux/platform_device.h>
27#include <asm/system.h>
28#include <asm/mach-types.h>
29#include <mach/hardware.h>
30#include <mach/gpio.h>
31#include <mach/clk.h>
32
33#include "msm_fb.h"
34#include "mipi_dsi.h"
35#include "mdp.h"
36#include "mdp4.h"
37
38u32 dsi_irq;
39
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +053040static boolean tlmm_settings = FALSE;
41
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042static int mipi_dsi_probe(struct platform_device *pdev);
43static int mipi_dsi_remove(struct platform_device *pdev);
44
45static int mipi_dsi_off(struct platform_device *pdev);
46static int mipi_dsi_on(struct platform_device *pdev);
47
48static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
49static int pdev_list_cnt;
50static struct mipi_dsi_platform_data *mipi_dsi_pdata;
51
52static int vsync_gpio = -1;
53
54static struct platform_driver mipi_dsi_driver = {
55 .probe = mipi_dsi_probe,
56 .remove = mipi_dsi_remove,
57 .shutdown = NULL,
58 .driver = {
59 .name = "mipi_dsi",
60 },
61};
62
63struct device dsi_dev;
64
65static int mipi_dsi_off(struct platform_device *pdev)
66{
67 int ret = 0;
68 struct msm_fb_data_type *mfd;
69 struct msm_panel_info *pinfo;
70
71 mfd = platform_get_drvdata(pdev);
72 pinfo = &mfd->panel_info;
73
74 if (mdp_rev >= MDP_REV_41)
75 mutex_lock(&mfd->dma->ov_mutex);
76 else
77 down(&mfd->dma->mutex);
78
79 mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND);
80
81 /*
82 * Description: dsi clock is need to perform shutdown.
83 * mdp4_dsi_cmd_dma_busy_wait() will enable dsi clock if disabled.
84 * also, wait until dma (overlay and dmap) finish.
85 */
86 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
87 if (mdp_rev >= MDP_REV_41) {
88 mdp4_dsi_cmd_dma_busy_wait(mfd);
89 mdp4_dsi_blt_dmap_busy_wait(mfd);
90 } else {
91 mdp3_dsi_cmd_dma_busy_wait(mfd);
92 }
93 }
94
95 /*
96 * Desctiption: change to DSI_CMD_MODE since it needed to
97 * tx DCS dsiplay off comamnd to panel
98 */
99 mipi_dsi_op_mode_config(DSI_CMD_MODE);
100
101 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
102 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700103 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530104 if (MDP_REV_303 != mdp_rev)
105 gpio_free(vsync_gpio);
106 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107 mipi_dsi_set_tear_off(mfd);
108 }
109 }
110
111 ret = panel_next_off(pdev);
112
113#ifdef CONFIG_MSM_BUS_SCALING
114 mdp_bus_scale_update_request(0);
115#endif
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700116
117 local_bh_disable();
118 mipi_dsi_clk_disable();
119 local_bh_enable();
120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 /* disbale dsi engine */
122 MIPI_OUTP(MIPI_DSI_BASE + 0x0000, 0);
123
124 mipi_dsi_phy_ctrl(0);
125
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 local_bh_disable();
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700128 mipi_dsi_ahb_ctrl(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 local_bh_enable();
130
131 if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
132 mipi_dsi_pdata->dsi_power_save(0);
133
134 if (mdp_rev >= MDP_REV_41)
135 mutex_unlock(&mfd->dma->ov_mutex);
136 else
137 up(&mfd->dma->mutex);
138
139 pr_debug("%s:\n", __func__);
140
141 return ret;
142}
143
144static int mipi_dsi_on(struct platform_device *pdev)
145{
146 int ret = 0;
147 u32 clk_rate;
148 struct msm_fb_data_type *mfd;
149 struct fb_info *fbi;
150 struct fb_var_screeninfo *var;
151 struct msm_panel_info *pinfo;
152 struct mipi_panel_info *mipi;
153 u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
154 u32 ystride, bpp, data;
155 u32 dummy_xres, dummy_yres;
156 int target_type = 0;
157
158 mfd = platform_get_drvdata(pdev);
159 fbi = mfd->fbi;
160 var = &fbi->var;
161 pinfo = &mfd->panel_info;
162
163 if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
164 mipi_dsi_pdata->dsi_power_save(1);
165
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700166 local_bh_disable();
167 mipi_dsi_ahb_ctrl(1);
168 local_bh_enable();
169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170 clk_rate = mfd->fbi->var.pixclock;
171 clk_rate = min(clk_rate, mfd->panel_info.clk_max);
172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173
174#ifndef CONFIG_FB_MSM_MDP303
175 mdp4_overlay_dsi_state_set(ST_DSI_RESUME);
176#endif
177
178 MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
179 MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
180
181 hbp = var->left_margin;
182 hfp = var->right_margin;
183 vbp = var->upper_margin;
184 vfp = var->lower_margin;
185 hspw = var->hsync_len;
186 vspw = var->vsync_len;
187 width = mfd->panel_info.xres;
188 height = mfd->panel_info.yres;
189
190 mipi_dsi_phy_ctrl(1);
191
192 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
193 target_type = mipi_dsi_pdata->target_type;
194
195 mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
196
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700197 local_bh_disable();
198 mipi_dsi_clk_enable();
199 local_bh_enable();
200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 mipi = &mfd->panel_info.mipi;
202 if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
203 dummy_xres = mfd->panel_info.mipi.xres_pad;
204 dummy_yres = mfd->panel_info.mipi.yres_pad;
205
206 if (mdp_rev >= MDP_REV_41) {
207 MIPI_OUTP(MIPI_DSI_BASE + 0x20,
208 ((hspw + hbp + width + dummy_xres) << 16 |
209 (hspw + hbp)));
210 MIPI_OUTP(MIPI_DSI_BASE + 0x24,
211 ((vspw + vbp + height + dummy_yres) << 16 |
212 (vspw + vbp)));
213 MIPI_OUTP(MIPI_DSI_BASE + 0x28,
214 (vspw + vbp + height + dummy_yres +
215 vfp - 1) << 16 | (hspw + hbp +
216 width + dummy_xres + hfp - 1));
217 } else {
218 /* DSI_LAN_SWAP_CTRL */
219 MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap);
220
221 MIPI_OUTP(MIPI_DSI_BASE + 0x20,
222 ((hbp + width + dummy_xres) << 16 | (hbp)));
223 MIPI_OUTP(MIPI_DSI_BASE + 0x24,
224 ((vbp + height + dummy_yres) << 16 | (vbp)));
225 MIPI_OUTP(MIPI_DSI_BASE + 0x28,
226 (vbp + height + dummy_yres + vfp) << 16 |
227 (hbp + width + dummy_xres + hfp));
228 }
229
230 MIPI_OUTP(MIPI_DSI_BASE + 0x2c, (hspw << 16));
231 MIPI_OUTP(MIPI_DSI_BASE + 0x30, 0);
232 MIPI_OUTP(MIPI_DSI_BASE + 0x34, (vspw << 16));
233
234 } else { /* command mode */
235 if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
236 bpp = 3;
237 else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666)
238 bpp = 3;
239 else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
240 bpp = 2;
241 else
242 bpp = 3; /* Default format set to RGB888 */
243
244 ystride = width * bpp + 1;
245
246 /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
247 data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE;
248 MIPI_OUTP(MIPI_DSI_BASE + 0x5c, data);
249 MIPI_OUTP(MIPI_DSI_BASE + 0x54, data);
250
251 /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
252 data = height << 16 | width;
253 MIPI_OUTP(MIPI_DSI_BASE + 0x60, data);
254 MIPI_OUTP(MIPI_DSI_BASE + 0x58, data);
255 }
256
257 mipi_dsi_host_init(mipi);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258
Amir Samuelovb84120b2011-09-03 17:49:43 +0300259 if (mipi->force_clk_lane_hs) {
260 u32 tmp;
261
262 tmp = MIPI_INP(MIPI_DSI_BASE + 0xA8);
263 tmp |= (1<<28);
264 MIPI_OUTP(MIPI_DSI_BASE + 0xA8, tmp);
265 wmb();
266 }
267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 ret = panel_next_on(pdev);
269
270 mipi_dsi_op_mode_config(mipi->mode);
271
272 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
273 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700274 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530275 if (mdp_rev >= MDP_REV_41) {
276 if (gpio_request(vsync_gpio,
277 "MDP_VSYNC") == 0)
278 gpio_direction_input(
279 vsync_gpio);
280 else
281 pr_err("%s: unable to \
282 request gpio=%d\n",
283 __func__, vsync_gpio);
284 } else if (mdp_rev == MDP_REV_303) {
285 if (!tlmm_settings && gpio_request(
286 vsync_gpio, "MDP_VSYNC") == 0) {
287 ret = gpio_tlmm_config(
288 GPIO_CFG(
289 vsync_gpio, 1,
290 GPIO_CFG_INPUT,
291 GPIO_CFG_PULL_DOWN,
292 GPIO_CFG_2MA),
293 GPIO_CFG_ENABLE);
294
295 if (ret) {
296 pr_err(
297 "%s: unable to config \
298 tlmm = %d\n",
299 __func__, vsync_gpio);
300 }
301 tlmm_settings = TRUE;
302
303 gpio_direction_input(
304 vsync_gpio);
305 } else {
306 if (!tlmm_settings) {
307 pr_err(
308 "%s: unable to request \
309 gpio=%d\n",
310 __func__, vsync_gpio);
311 }
312 }
313 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 }
315 mipi_dsi_set_tear_on(mfd);
316 }
317 }
318
319#ifdef CONFIG_MSM_BUS_SCALING
320 mdp_bus_scale_update_request(2);
321#endif
322 return ret;
323}
324
325
326static int mipi_dsi_resource_initialized;
327
328static int mipi_dsi_probe(struct platform_device *pdev)
329{
330 struct msm_fb_data_type *mfd;
331 struct fb_info *fbi;
332 struct msm_panel_info *pinfo;
333 struct mipi_panel_info *mipi;
334 struct platform_device *mdp_dev = NULL;
335 struct msm_fb_panel_data *pdata = NULL;
336 int rc;
337 uint8 lanes = 0, bpp;
338 uint32 h_period, v_period, dsi_pclk_rate;
339
340 resource_size_t size ;
341
342 if ((pdev->id == 1) && (pdev->num_resources >= 0)) {
343 mipi_dsi_pdata = pdev->dev.platform_data;
344
345 size = resource_size(&pdev->resource[0]);
346 mipi_dsi_base = ioremap(pdev->resource[0].start, size);
347
348 MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n",
349 pdev->resource[0].start, (int) mipi_dsi_base);
350
351 if (!mipi_dsi_base)
352 return -ENOMEM;
353
354 if (mdp_rev >= MDP_REV_41) {
355 mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100);
356 MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x,"
357 "virt = 0x%x\n", MMSS_SFPB_BASE_PHY,
358 (int) mmss_sfpb_base);
359
360 if (!mmss_sfpb_base)
361 return -ENOMEM;
362 }
363
364 dsi_irq = platform_get_irq(pdev, 0);
365 if (dsi_irq < 0) {
366 pr_err("mipi_dsi: can not get mdp irq\n");
367 return -ENOMEM;
368 }
369
370 rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED,
371 "MIPI_DSI", 0);
372 if (rc) {
373 pr_err("mipi_dsi_host request_irq() failed!\n");
374 return rc;
375 }
376
377 disable_irq(dsi_irq);
378
379 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata &&
380 mipi_dsi_pdata->target_type == 1) {
381 /* Target type is 1 for device with (De)serializer
382 * 0x4f00000 is the base for TV Encoder.
383 * Unused Offset 0x1000 is used for
384 * (de)serializer on emulation platform
385 */
386 periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100);
387
388 if (periph_base) {
389 pr_debug("periph_base %p\n", periph_base);
390 writel(0x4, periph_base + 0x28);
391 writel(0xc, periph_base + 0x28);
392 } else {
393 pr_err("periph_base is NULL\n");
394 free_irq(dsi_irq, 0);
395 return -ENOMEM;
396 }
397 }
398
399 if (mipi_dsi_pdata) {
400 vsync_gpio = mipi_dsi_pdata->vsync_gpio;
401 pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio);
402
403 if (mdp_rev == MDP_REV_303 &&
404 mipi_dsi_pdata->dsi_client_reset) {
405 if (mipi_dsi_pdata->dsi_client_reset())
406 pr_err("%s: DSI Client Reset failed!\n",
407 __func__);
408 else
409 pr_debug("%s: DSI Client Reset success\n",
410 __func__);
411 }
412 }
413
414 mipi_dsi_resource_initialized = 1;
415
416 return 0;
417 }
418
419 mipi_dsi_clk_init(&pdev->dev);
420
421 if (!mipi_dsi_resource_initialized)
422 return -EPERM;
423
424 mfd = platform_get_drvdata(pdev);
425
426 if (!mfd)
427 return -ENODEV;
428
429 if (mfd->key != MFD_KEY)
430 return -EINVAL;
431
432 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
433 return -ENOMEM;
434
435
436 mdp_dev = platform_device_alloc("mdp", pdev->id);
437 if (!mdp_dev)
438 return -ENOMEM;
439
440 /*
441 * link to the latest pdev
442 */
443 mfd->pdev = mdp_dev;
444 mfd->dest = DISPLAY_LCD;
445
446 /*
447 * alloc panel device data
448 */
449 if (platform_device_add_data
450 (mdp_dev, pdev->dev.platform_data,
451 sizeof(struct msm_fb_panel_data))) {
452 pr_err("mipi_dsi_probe: platform_device_add_data failed!\n");
453 platform_device_put(mdp_dev);
454 return -ENOMEM;
455 }
456 /*
457 * data chain
458 */
459 pdata = mdp_dev->dev.platform_data;
460 pdata->on = mipi_dsi_on;
461 pdata->off = mipi_dsi_off;
462 pdata->next = pdev;
463
464 /*
465 * get/set panel specific fb info
466 */
467 mfd->panel_info = pdata->panel_info;
468 pinfo = &mfd->panel_info;
469
470 if (mdp_rev == MDP_REV_303 &&
471 mipi_dsi_pdata->get_lane_config) {
472 if (mipi_dsi_pdata->get_lane_config() != 2) {
473 pr_info("Changing to DSI Single Mode Configuration\n");
474#ifdef CONFIG_FB_MSM_MDP303
475 update_lane_config(pinfo);
476#endif
477 }
478 }
479
480 if (mfd->index == 0)
481 mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
482 else
483 mfd->fb_imgType = MDP_RGB_565;
484
485 fbi = mfd->fbi;
486 fbi->var.pixclock = mfd->panel_info.clk_rate;
487 fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
488 fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
489 fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
490 fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
491 fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
492 fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
493
494 h_period = ((mfd->panel_info.lcdc.h_pulse_width)
495 + (mfd->panel_info.lcdc.h_back_porch)
496 + (mfd->panel_info.xres)
497 + (mfd->panel_info.lcdc.h_front_porch));
498
499 v_period = ((mfd->panel_info.lcdc.v_pulse_width)
500 + (mfd->panel_info.lcdc.v_back_porch)
501 + (mfd->panel_info.yres)
502 + (mfd->panel_info.lcdc.v_front_porch));
503
504 mipi = &mfd->panel_info.mipi;
505
506 if (mipi->data_lane3)
507 lanes += 1;
508 if (mipi->data_lane2)
509 lanes += 1;
510 if (mipi->data_lane1)
511 lanes += 1;
512 if (mipi->data_lane0)
513 lanes += 1;
514
515 if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
516 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
517 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
518 bpp = 3;
519 else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
520 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
521 bpp = 2;
522 else
523 bpp = 3; /* Default format set to RGB888 */
524
525 if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
526 !mfd->panel_info.clk_rate) {
527 h_period += mfd->panel_info.mipi.xres_pad;
528 v_period += mfd->panel_info.mipi.yres_pad;
529
530 if (lanes > 0) {
531 mfd->panel_info.clk_rate =
532 ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
533 / lanes);
534 } else {
535 pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__);
536 mfd->panel_info.clk_rate =
537 (h_period * v_period
538 * (mipi->frame_rate) * bpp * 8);
539 }
540 }
541 pll_divider_config.clk_rate = mfd->panel_info.clk_rate;
542
543 rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
544 if (rc)
545 goto mipi_dsi_probe_err;
546
547 if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
548 dsi_pclk_rate = 35000000;
549 mipi->dsi_pclk_rate = dsi_pclk_rate;
550
551 /*
552 * set driver data
553 */
554 platform_set_drvdata(mdp_dev, mfd);
555
556 /*
557 * register in mdp driver
558 */
559 rc = platform_device_add(mdp_dev);
560 if (rc)
561 goto mipi_dsi_probe_err;
562
563 pdev_list[pdev_list_cnt++] = pdev;
564
565return 0;
566
567mipi_dsi_probe_err:
568 platform_device_put(mdp_dev);
569 return rc;
570}
571
572static int mipi_dsi_remove(struct platform_device *pdev)
573{
574 struct msm_fb_data_type *mfd;
575
576 mfd = platform_get_drvdata(pdev);
577 iounmap(mipi_dsi_base);
578 return 0;
579}
580
581static int mipi_dsi_register_driver(void)
582{
583 return platform_driver_register(&mipi_dsi_driver);
584}
585
586static int __init mipi_dsi_driver_init(void)
587{
588 int ret;
589
590 mipi_dsi_init();
591
592 ret = mipi_dsi_register_driver();
593
594 device_initialize(&dsi_dev);
595
596 if (ret) {
597 pr_err("mipi_dsi_register_driver() failed!\n");
598 return ret;
599 }
600
601 return ret;
602}
603
604module_init(mipi_dsi_driver_init);