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