blob: 00256e66c5cac34bb7fda3f8f71cc5eb26a43155 [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);
kuogee hsieh8717a172011-09-05 09:57:58 -070090 mipi_dsi_mdp_busy_wait(mfd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 } else {
92 mdp3_dsi_cmd_dma_busy_wait(mfd);
93 }
94 }
95
96 /*
97 * Desctiption: change to DSI_CMD_MODE since it needed to
98 * tx DCS dsiplay off comamnd to panel
99 */
100 mipi_dsi_op_mode_config(DSI_CMD_MODE);
101
102 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
103 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700104 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530105 if (MDP_REV_303 != mdp_rev)
106 gpio_free(vsync_gpio);
107 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 mipi_dsi_set_tear_off(mfd);
109 }
110 }
111
112 ret = panel_next_off(pdev);
113
114#ifdef CONFIG_MSM_BUS_SCALING
115 mdp_bus_scale_update_request(0);
116#endif
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700117
118 local_bh_disable();
119 mipi_dsi_clk_disable();
120 local_bh_enable();
121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 /* disbale dsi engine */
123 MIPI_OUTP(MIPI_DSI_BASE + 0x0000, 0);
124
125 mipi_dsi_phy_ctrl(0);
126
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 local_bh_disable();
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700129 mipi_dsi_ahb_ctrl(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130 local_bh_enable();
131
132 if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
133 mipi_dsi_pdata->dsi_power_save(0);
134
135 if (mdp_rev >= MDP_REV_41)
136 mutex_unlock(&mfd->dma->ov_mutex);
137 else
138 up(&mfd->dma->mutex);
139
140 pr_debug("%s:\n", __func__);
141
142 return ret;
143}
144
145static int mipi_dsi_on(struct platform_device *pdev)
146{
147 int ret = 0;
148 u32 clk_rate;
149 struct msm_fb_data_type *mfd;
150 struct fb_info *fbi;
151 struct fb_var_screeninfo *var;
152 struct msm_panel_info *pinfo;
153 struct mipi_panel_info *mipi;
154 u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
155 u32 ystride, bpp, data;
156 u32 dummy_xres, dummy_yres;
157 int target_type = 0;
158
159 mfd = platform_get_drvdata(pdev);
160 fbi = mfd->fbi;
161 var = &fbi->var;
162 pinfo = &mfd->panel_info;
163
164 if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
165 mipi_dsi_pdata->dsi_power_save(1);
166
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700167 local_bh_disable();
168 mipi_dsi_ahb_ctrl(1);
169 local_bh_enable();
170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 clk_rate = mfd->fbi->var.pixclock;
172 clk_rate = min(clk_rate, mfd->panel_info.clk_max);
173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
175#ifndef CONFIG_FB_MSM_MDP303
176 mdp4_overlay_dsi_state_set(ST_DSI_RESUME);
177#endif
178
179 MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
180 MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
181
182 hbp = var->left_margin;
183 hfp = var->right_margin;
184 vbp = var->upper_margin;
185 vfp = var->lower_margin;
186 hspw = var->hsync_len;
187 vspw = var->vsync_len;
188 width = mfd->panel_info.xres;
189 height = mfd->panel_info.yres;
190
191 mipi_dsi_phy_ctrl(1);
192
193 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
194 target_type = mipi_dsi_pdata->target_type;
195
196 mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
197
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700198 local_bh_disable();
199 mipi_dsi_clk_enable();
200 local_bh_enable();
201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 mipi = &mfd->panel_info.mipi;
203 if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
204 dummy_xres = mfd->panel_info.mipi.xres_pad;
205 dummy_yres = mfd->panel_info.mipi.yres_pad;
206
207 if (mdp_rev >= MDP_REV_41) {
208 MIPI_OUTP(MIPI_DSI_BASE + 0x20,
209 ((hspw + hbp + width + dummy_xres) << 16 |
210 (hspw + hbp)));
211 MIPI_OUTP(MIPI_DSI_BASE + 0x24,
212 ((vspw + vbp + height + dummy_yres) << 16 |
213 (vspw + vbp)));
214 MIPI_OUTP(MIPI_DSI_BASE + 0x28,
215 (vspw + vbp + height + dummy_yres +
216 vfp - 1) << 16 | (hspw + hbp +
217 width + dummy_xres + hfp - 1));
218 } else {
219 /* DSI_LAN_SWAP_CTRL */
220 MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap);
221
222 MIPI_OUTP(MIPI_DSI_BASE + 0x20,
223 ((hbp + width + dummy_xres) << 16 | (hbp)));
224 MIPI_OUTP(MIPI_DSI_BASE + 0x24,
225 ((vbp + height + dummy_yres) << 16 | (vbp)));
226 MIPI_OUTP(MIPI_DSI_BASE + 0x28,
227 (vbp + height + dummy_yres + vfp) << 16 |
228 (hbp + width + dummy_xres + hfp));
229 }
230
231 MIPI_OUTP(MIPI_DSI_BASE + 0x2c, (hspw << 16));
232 MIPI_OUTP(MIPI_DSI_BASE + 0x30, 0);
233 MIPI_OUTP(MIPI_DSI_BASE + 0x34, (vspw << 16));
234
235 } else { /* command mode */
236 if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
237 bpp = 3;
238 else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666)
239 bpp = 3;
240 else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
241 bpp = 2;
242 else
243 bpp = 3; /* Default format set to RGB888 */
244
245 ystride = width * bpp + 1;
246
247 /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
248 data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE;
249 MIPI_OUTP(MIPI_DSI_BASE + 0x5c, data);
250 MIPI_OUTP(MIPI_DSI_BASE + 0x54, data);
251
252 /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
253 data = height << 16 | width;
254 MIPI_OUTP(MIPI_DSI_BASE + 0x60, data);
255 MIPI_OUTP(MIPI_DSI_BASE + 0x58, data);
256 }
257
258 mipi_dsi_host_init(mipi);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259
Amir Samuelovb84120b2011-09-03 17:49:43 +0300260 if (mipi->force_clk_lane_hs) {
261 u32 tmp;
262
263 tmp = MIPI_INP(MIPI_DSI_BASE + 0xA8);
264 tmp |= (1<<28);
265 MIPI_OUTP(MIPI_DSI_BASE + 0xA8, tmp);
266 wmb();
267 }
268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 ret = panel_next_on(pdev);
270
271 mipi_dsi_op_mode_config(mipi->mode);
272
273 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
274 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700275 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530276 if (mdp_rev >= MDP_REV_41) {
277 if (gpio_request(vsync_gpio,
278 "MDP_VSYNC") == 0)
279 gpio_direction_input(
280 vsync_gpio);
281 else
282 pr_err("%s: unable to \
283 request gpio=%d\n",
284 __func__, vsync_gpio);
285 } else if (mdp_rev == MDP_REV_303) {
286 if (!tlmm_settings && gpio_request(
287 vsync_gpio, "MDP_VSYNC") == 0) {
288 ret = gpio_tlmm_config(
289 GPIO_CFG(
290 vsync_gpio, 1,
291 GPIO_CFG_INPUT,
292 GPIO_CFG_PULL_DOWN,
293 GPIO_CFG_2MA),
294 GPIO_CFG_ENABLE);
295
296 if (ret) {
297 pr_err(
298 "%s: unable to config \
299 tlmm = %d\n",
300 __func__, vsync_gpio);
301 }
302 tlmm_settings = TRUE;
303
304 gpio_direction_input(
305 vsync_gpio);
306 } else {
307 if (!tlmm_settings) {
308 pr_err(
309 "%s: unable to request \
310 gpio=%d\n",
311 __func__, vsync_gpio);
312 }
313 }
314 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 }
316 mipi_dsi_set_tear_on(mfd);
317 }
318 }
319
320#ifdef CONFIG_MSM_BUS_SCALING
321 mdp_bus_scale_update_request(2);
322#endif
323 return ret;
324}
325
326
327static int mipi_dsi_resource_initialized;
328
329static int mipi_dsi_probe(struct platform_device *pdev)
330{
331 struct msm_fb_data_type *mfd;
332 struct fb_info *fbi;
333 struct msm_panel_info *pinfo;
334 struct mipi_panel_info *mipi;
335 struct platform_device *mdp_dev = NULL;
336 struct msm_fb_panel_data *pdata = NULL;
337 int rc;
338 uint8 lanes = 0, bpp;
339 uint32 h_period, v_period, dsi_pclk_rate;
340
341 resource_size_t size ;
342
343 if ((pdev->id == 1) && (pdev->num_resources >= 0)) {
344 mipi_dsi_pdata = pdev->dev.platform_data;
345
346 size = resource_size(&pdev->resource[0]);
347 mipi_dsi_base = ioremap(pdev->resource[0].start, size);
348
349 MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n",
350 pdev->resource[0].start, (int) mipi_dsi_base);
351
352 if (!mipi_dsi_base)
353 return -ENOMEM;
354
355 if (mdp_rev >= MDP_REV_41) {
356 mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100);
357 MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x,"
358 "virt = 0x%x\n", MMSS_SFPB_BASE_PHY,
359 (int) mmss_sfpb_base);
360
361 if (!mmss_sfpb_base)
362 return -ENOMEM;
363 }
364
365 dsi_irq = platform_get_irq(pdev, 0);
366 if (dsi_irq < 0) {
367 pr_err("mipi_dsi: can not get mdp irq\n");
368 return -ENOMEM;
369 }
370
371 rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED,
372 "MIPI_DSI", 0);
373 if (rc) {
374 pr_err("mipi_dsi_host request_irq() failed!\n");
375 return rc;
376 }
377
378 disable_irq(dsi_irq);
379
380 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata &&
381 mipi_dsi_pdata->target_type == 1) {
382 /* Target type is 1 for device with (De)serializer
383 * 0x4f00000 is the base for TV Encoder.
384 * Unused Offset 0x1000 is used for
385 * (de)serializer on emulation platform
386 */
387 periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100);
388
389 if (periph_base) {
390 pr_debug("periph_base %p\n", periph_base);
391 writel(0x4, periph_base + 0x28);
392 writel(0xc, periph_base + 0x28);
393 } else {
394 pr_err("periph_base is NULL\n");
395 free_irq(dsi_irq, 0);
396 return -ENOMEM;
397 }
398 }
399
400 if (mipi_dsi_pdata) {
401 vsync_gpio = mipi_dsi_pdata->vsync_gpio;
402 pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio);
403
404 if (mdp_rev == MDP_REV_303 &&
405 mipi_dsi_pdata->dsi_client_reset) {
406 if (mipi_dsi_pdata->dsi_client_reset())
407 pr_err("%s: DSI Client Reset failed!\n",
408 __func__);
409 else
410 pr_debug("%s: DSI Client Reset success\n",
411 __func__);
412 }
413 }
414
415 mipi_dsi_resource_initialized = 1;
416
417 return 0;
418 }
419
420 mipi_dsi_clk_init(&pdev->dev);
421
422 if (!mipi_dsi_resource_initialized)
423 return -EPERM;
424
425 mfd = platform_get_drvdata(pdev);
426
427 if (!mfd)
428 return -ENODEV;
429
430 if (mfd->key != MFD_KEY)
431 return -EINVAL;
432
433 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
434 return -ENOMEM;
435
436
437 mdp_dev = platform_device_alloc("mdp", pdev->id);
438 if (!mdp_dev)
439 return -ENOMEM;
440
441 /*
442 * link to the latest pdev
443 */
444 mfd->pdev = mdp_dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445
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
Ravishangar Kalyanam7a7e46f2011-09-12 12:45:29 -0700470 if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
471 mfd->dest = DISPLAY_LCDC;
472 else
473 mfd->dest = DISPLAY_LCD;
474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 if (mdp_rev == MDP_REV_303 &&
476 mipi_dsi_pdata->get_lane_config) {
477 if (mipi_dsi_pdata->get_lane_config() != 2) {
478 pr_info("Changing to DSI Single Mode Configuration\n");
479#ifdef CONFIG_FB_MSM_MDP303
480 update_lane_config(pinfo);
481#endif
482 }
483 }
484
485 if (mfd->index == 0)
486 mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
487 else
488 mfd->fb_imgType = MDP_RGB_565;
489
490 fbi = mfd->fbi;
491 fbi->var.pixclock = mfd->panel_info.clk_rate;
492 fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
493 fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
494 fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
495 fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
496 fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
497 fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
498
499 h_period = ((mfd->panel_info.lcdc.h_pulse_width)
500 + (mfd->panel_info.lcdc.h_back_porch)
501 + (mfd->panel_info.xres)
502 + (mfd->panel_info.lcdc.h_front_porch));
503
504 v_period = ((mfd->panel_info.lcdc.v_pulse_width)
505 + (mfd->panel_info.lcdc.v_back_porch)
506 + (mfd->panel_info.yres)
507 + (mfd->panel_info.lcdc.v_front_porch));
508
509 mipi = &mfd->panel_info.mipi;
510
511 if (mipi->data_lane3)
512 lanes += 1;
513 if (mipi->data_lane2)
514 lanes += 1;
515 if (mipi->data_lane1)
516 lanes += 1;
517 if (mipi->data_lane0)
518 lanes += 1;
519
520 if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
521 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
522 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
523 bpp = 3;
524 else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
525 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
526 bpp = 2;
527 else
528 bpp = 3; /* Default format set to RGB888 */
529
530 if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
531 !mfd->panel_info.clk_rate) {
532 h_period += mfd->panel_info.mipi.xres_pad;
533 v_period += mfd->panel_info.mipi.yres_pad;
534
535 if (lanes > 0) {
536 mfd->panel_info.clk_rate =
537 ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
538 / lanes);
539 } else {
540 pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__);
541 mfd->panel_info.clk_rate =
542 (h_period * v_period
543 * (mipi->frame_rate) * bpp * 8);
544 }
545 }
546 pll_divider_config.clk_rate = mfd->panel_info.clk_rate;
547
548 rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
549 if (rc)
550 goto mipi_dsi_probe_err;
551
552 if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
553 dsi_pclk_rate = 35000000;
554 mipi->dsi_pclk_rate = dsi_pclk_rate;
555
556 /*
557 * set driver data
558 */
559 platform_set_drvdata(mdp_dev, mfd);
560
561 /*
562 * register in mdp driver
563 */
564 rc = platform_device_add(mdp_dev);
565 if (rc)
566 goto mipi_dsi_probe_err;
567
568 pdev_list[pdev_list_cnt++] = pdev;
569
570return 0;
571
572mipi_dsi_probe_err:
573 platform_device_put(mdp_dev);
574 return rc;
575}
576
577static int mipi_dsi_remove(struct platform_device *pdev)
578{
579 struct msm_fb_data_type *mfd;
580
581 mfd = platform_get_drvdata(pdev);
582 iounmap(mipi_dsi_base);
583 return 0;
584}
585
586static int mipi_dsi_register_driver(void)
587{
588 return platform_driver_register(&mipi_dsi_driver);
589}
590
591static int __init mipi_dsi_driver_init(void)
592{
593 int ret;
594
595 mipi_dsi_init();
596
597 ret = mipi_dsi_register_driver();
598
599 device_initialize(&dsi_dev);
600
601 if (ret) {
602 pr_err("mipi_dsi_register_driver() failed!\n");
603 return ret;
604 }
605
606 return ret;
607}
608
609module_init(mipi_dsi_driver_init);