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