blob: b8963e478514e9d4ece20f7f4b8bdb55a30821bc [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
259 ret = panel_next_on(pdev);
260
261 mipi_dsi_op_mode_config(mipi->mode);
262
263 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
264 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700265 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530266 if (mdp_rev >= MDP_REV_41) {
267 if (gpio_request(vsync_gpio,
268 "MDP_VSYNC") == 0)
269 gpio_direction_input(
270 vsync_gpio);
271 else
272 pr_err("%s: unable to \
273 request gpio=%d\n",
274 __func__, vsync_gpio);
275 } else if (mdp_rev == MDP_REV_303) {
276 if (!tlmm_settings && gpio_request(
277 vsync_gpio, "MDP_VSYNC") == 0) {
278 ret = gpio_tlmm_config(
279 GPIO_CFG(
280 vsync_gpio, 1,
281 GPIO_CFG_INPUT,
282 GPIO_CFG_PULL_DOWN,
283 GPIO_CFG_2MA),
284 GPIO_CFG_ENABLE);
285
286 if (ret) {
287 pr_err(
288 "%s: unable to config \
289 tlmm = %d\n",
290 __func__, vsync_gpio);
291 }
292 tlmm_settings = TRUE;
293
294 gpio_direction_input(
295 vsync_gpio);
296 } else {
297 if (!tlmm_settings) {
298 pr_err(
299 "%s: unable to request \
300 gpio=%d\n",
301 __func__, vsync_gpio);
302 }
303 }
304 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 }
306 mipi_dsi_set_tear_on(mfd);
307 }
308 }
309
310#ifdef CONFIG_MSM_BUS_SCALING
311 mdp_bus_scale_update_request(2);
312#endif
313 return ret;
314}
315
316
317static int mipi_dsi_resource_initialized;
318
319static int mipi_dsi_probe(struct platform_device *pdev)
320{
321 struct msm_fb_data_type *mfd;
322 struct fb_info *fbi;
323 struct msm_panel_info *pinfo;
324 struct mipi_panel_info *mipi;
325 struct platform_device *mdp_dev = NULL;
326 struct msm_fb_panel_data *pdata = NULL;
327 int rc;
328 uint8 lanes = 0, bpp;
329 uint32 h_period, v_period, dsi_pclk_rate;
330
331 resource_size_t size ;
332
333 if ((pdev->id == 1) && (pdev->num_resources >= 0)) {
334 mipi_dsi_pdata = pdev->dev.platform_data;
335
336 size = resource_size(&pdev->resource[0]);
337 mipi_dsi_base = ioremap(pdev->resource[0].start, size);
338
339 MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n",
340 pdev->resource[0].start, (int) mipi_dsi_base);
341
342 if (!mipi_dsi_base)
343 return -ENOMEM;
344
345 if (mdp_rev >= MDP_REV_41) {
346 mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100);
347 MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x,"
348 "virt = 0x%x\n", MMSS_SFPB_BASE_PHY,
349 (int) mmss_sfpb_base);
350
351 if (!mmss_sfpb_base)
352 return -ENOMEM;
353 }
354
355 dsi_irq = platform_get_irq(pdev, 0);
356 if (dsi_irq < 0) {
357 pr_err("mipi_dsi: can not get mdp irq\n");
358 return -ENOMEM;
359 }
360
361 rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED,
362 "MIPI_DSI", 0);
363 if (rc) {
364 pr_err("mipi_dsi_host request_irq() failed!\n");
365 return rc;
366 }
367
368 disable_irq(dsi_irq);
369
370 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata &&
371 mipi_dsi_pdata->target_type == 1) {
372 /* Target type is 1 for device with (De)serializer
373 * 0x4f00000 is the base for TV Encoder.
374 * Unused Offset 0x1000 is used for
375 * (de)serializer on emulation platform
376 */
377 periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100);
378
379 if (periph_base) {
380 pr_debug("periph_base %p\n", periph_base);
381 writel(0x4, periph_base + 0x28);
382 writel(0xc, periph_base + 0x28);
383 } else {
384 pr_err("periph_base is NULL\n");
385 free_irq(dsi_irq, 0);
386 return -ENOMEM;
387 }
388 }
389
390 if (mipi_dsi_pdata) {
391 vsync_gpio = mipi_dsi_pdata->vsync_gpio;
392 pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio);
393
394 if (mdp_rev == MDP_REV_303 &&
395 mipi_dsi_pdata->dsi_client_reset) {
396 if (mipi_dsi_pdata->dsi_client_reset())
397 pr_err("%s: DSI Client Reset failed!\n",
398 __func__);
399 else
400 pr_debug("%s: DSI Client Reset success\n",
401 __func__);
402 }
403 }
404
405 mipi_dsi_resource_initialized = 1;
406
407 return 0;
408 }
409
410 mipi_dsi_clk_init(&pdev->dev);
411
412 if (!mipi_dsi_resource_initialized)
413 return -EPERM;
414
415 mfd = platform_get_drvdata(pdev);
416
417 if (!mfd)
418 return -ENODEV;
419
420 if (mfd->key != MFD_KEY)
421 return -EINVAL;
422
423 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
424 return -ENOMEM;
425
426
427 mdp_dev = platform_device_alloc("mdp", pdev->id);
428 if (!mdp_dev)
429 return -ENOMEM;
430
431 /*
432 * link to the latest pdev
433 */
434 mfd->pdev = mdp_dev;
435 mfd->dest = DISPLAY_LCD;
436
437 /*
438 * alloc panel device data
439 */
440 if (platform_device_add_data
441 (mdp_dev, pdev->dev.platform_data,
442 sizeof(struct msm_fb_panel_data))) {
443 pr_err("mipi_dsi_probe: platform_device_add_data failed!\n");
444 platform_device_put(mdp_dev);
445 return -ENOMEM;
446 }
447 /*
448 * data chain
449 */
450 pdata = mdp_dev->dev.platform_data;
451 pdata->on = mipi_dsi_on;
452 pdata->off = mipi_dsi_off;
453 pdata->next = pdev;
454
455 /*
456 * get/set panel specific fb info
457 */
458 mfd->panel_info = pdata->panel_info;
459 pinfo = &mfd->panel_info;
460
461 if (mdp_rev == MDP_REV_303 &&
462 mipi_dsi_pdata->get_lane_config) {
463 if (mipi_dsi_pdata->get_lane_config() != 2) {
464 pr_info("Changing to DSI Single Mode Configuration\n");
465#ifdef CONFIG_FB_MSM_MDP303
466 update_lane_config(pinfo);
467#endif
468 }
469 }
470
471 if (mfd->index == 0)
472 mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
473 else
474 mfd->fb_imgType = MDP_RGB_565;
475
476 fbi = mfd->fbi;
477 fbi->var.pixclock = mfd->panel_info.clk_rate;
478 fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
479 fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
480 fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
481 fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
482 fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
483 fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
484
485 h_period = ((mfd->panel_info.lcdc.h_pulse_width)
486 + (mfd->panel_info.lcdc.h_back_porch)
487 + (mfd->panel_info.xres)
488 + (mfd->panel_info.lcdc.h_front_porch));
489
490 v_period = ((mfd->panel_info.lcdc.v_pulse_width)
491 + (mfd->panel_info.lcdc.v_back_porch)
492 + (mfd->panel_info.yres)
493 + (mfd->panel_info.lcdc.v_front_porch));
494
495 mipi = &mfd->panel_info.mipi;
496
497 if (mipi->data_lane3)
498 lanes += 1;
499 if (mipi->data_lane2)
500 lanes += 1;
501 if (mipi->data_lane1)
502 lanes += 1;
503 if (mipi->data_lane0)
504 lanes += 1;
505
506 if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
507 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
508 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
509 bpp = 3;
510 else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
511 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
512 bpp = 2;
513 else
514 bpp = 3; /* Default format set to RGB888 */
515
516 if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
517 !mfd->panel_info.clk_rate) {
518 h_period += mfd->panel_info.mipi.xres_pad;
519 v_period += mfd->panel_info.mipi.yres_pad;
520
521 if (lanes > 0) {
522 mfd->panel_info.clk_rate =
523 ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
524 / lanes);
525 } else {
526 pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__);
527 mfd->panel_info.clk_rate =
528 (h_period * v_period
529 * (mipi->frame_rate) * bpp * 8);
530 }
531 }
532 pll_divider_config.clk_rate = mfd->panel_info.clk_rate;
533
534 rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
535 if (rc)
536 goto mipi_dsi_probe_err;
537
538 if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
539 dsi_pclk_rate = 35000000;
540 mipi->dsi_pclk_rate = dsi_pclk_rate;
541
542 /*
543 * set driver data
544 */
545 platform_set_drvdata(mdp_dev, mfd);
546
547 /*
548 * register in mdp driver
549 */
550 rc = platform_device_add(mdp_dev);
551 if (rc)
552 goto mipi_dsi_probe_err;
553
554 pdev_list[pdev_list_cnt++] = pdev;
555
556return 0;
557
558mipi_dsi_probe_err:
559 platform_device_put(mdp_dev);
560 return rc;
561}
562
563static int mipi_dsi_remove(struct platform_device *pdev)
564{
565 struct msm_fb_data_type *mfd;
566
567 mfd = platform_get_drvdata(pdev);
568 iounmap(mipi_dsi_base);
569 return 0;
570}
571
572static int mipi_dsi_register_driver(void)
573{
574 return platform_driver_register(&mipi_dsi_driver);
575}
576
577static int __init mipi_dsi_driver_init(void)
578{
579 int ret;
580
581 mipi_dsi_init();
582
583 ret = mipi_dsi_register_driver();
584
585 device_initialize(&dsi_dev);
586
587 if (ret) {
588 pr_err("mipi_dsi_register_driver() failed!\n");
589 return ret;
590 }
591
592 return ret;
593}
594
595module_init(mipi_dsi_driver_init);