diff options
Diffstat (limited to 'drivers/video/omap2/dss/dpi.c')
-rw-r--r-- | drivers/video/omap2/dss/dpi.c | 126 |
1 files changed, 95 insertions, 31 deletions
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 56748cf8760e..4af136a04e53 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -49,34 +49,53 @@ static struct { | |||
49 | struct omap_dss_output output; | 49 | struct omap_dss_output output; |
50 | } dpi; | 50 | } dpi; |
51 | 51 | ||
52 | static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) | 52 | static struct platform_device *dpi_get_dsidev(enum omap_channel channel) |
53 | { | 53 | { |
54 | int dsi_module; | 54 | /* |
55 | 55 | * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL | |
56 | dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1; | 56 | * would also be used for DISPC fclk. Meaning, when the DPI output is |
57 | * disabled, DISPC clock will be disabled, and TV out will stop. | ||
58 | */ | ||
59 | switch (omapdss_get_version()) { | ||
60 | case OMAPDSS_VER_OMAP24xx: | ||
61 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
62 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
63 | case OMAPDSS_VER_OMAP3630: | ||
64 | case OMAPDSS_VER_AM35xx: | ||
65 | return NULL; | ||
66 | default: | ||
67 | break; | ||
68 | } | ||
57 | 69 | ||
58 | return dsi_get_dsidev_from_id(dsi_module); | 70 | switch (channel) { |
71 | case OMAP_DSS_CHANNEL_LCD: | ||
72 | return dsi_get_dsidev_from_id(0); | ||
73 | case OMAP_DSS_CHANNEL_LCD2: | ||
74 | return dsi_get_dsidev_from_id(1); | ||
75 | default: | ||
76 | return NULL; | ||
77 | } | ||
59 | } | 78 | } |
60 | 79 | ||
61 | static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev) | 80 | static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) |
62 | { | 81 | { |
63 | if (dssdev->clocks.dispc.dispc_fclk_src == | 82 | switch (channel) { |
64 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || | 83 | case OMAP_DSS_CHANNEL_LCD: |
65 | dssdev->clocks.dispc.dispc_fclk_src == | 84 | return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; |
66 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC || | 85 | case OMAP_DSS_CHANNEL_LCD2: |
67 | dssdev->clocks.dispc.channel.lcd_clk_src == | 86 | return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; |
68 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || | 87 | default: |
69 | dssdev->clocks.dispc.channel.lcd_clk_src == | 88 | /* this shouldn't happen */ |
70 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC) | 89 | WARN_ON(1); |
71 | return true; | 90 | return OMAP_DSS_CLK_SRC_FCK; |
72 | else | 91 | } |
73 | return false; | ||
74 | } | 92 | } |
75 | 93 | ||
76 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | 94 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, |
77 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 95 | unsigned long pck_req, unsigned long *fck, int *lck_div, |
78 | int *pck_div) | 96 | int *pck_div) |
79 | { | 97 | { |
98 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
80 | struct dsi_clock_info dsi_cinfo; | 99 | struct dsi_clock_info dsi_cinfo; |
81 | struct dispc_clock_info dispc_cinfo; | 100 | struct dispc_clock_info dispc_cinfo; |
82 | int r; | 101 | int r; |
@@ -90,7 +109,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | |||
90 | if (r) | 109 | if (r) |
91 | return r; | 110 | return r; |
92 | 111 | ||
93 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | 112 | dss_select_lcd_clk_source(mgr->id, |
113 | dpi_get_alt_clk_src(mgr->id)); | ||
94 | 114 | ||
95 | dpi.mgr_config.clock_info = dispc_cinfo; | 115 | dpi.mgr_config.clock_info = dispc_cinfo; |
96 | 116 | ||
@@ -135,7 +155,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) | |||
135 | unsigned long pck; | 155 | unsigned long pck; |
136 | int r = 0; | 156 | int r = 0; |
137 | 157 | ||
138 | if (dpi_use_dsi_pll(dssdev)) | 158 | if (dpi.dsidev) |
139 | r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, | 159 | r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, |
140 | &lck_div, &pck_div); | 160 | &lck_div, &pck_div); |
141 | else | 161 | else |
@@ -214,7 +234,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
214 | if (r) | 234 | if (r) |
215 | goto err_src_sel; | 235 | goto err_src_sel; |
216 | 236 | ||
217 | if (dpi_use_dsi_pll(dssdev)) { | 237 | if (dpi.dsidev) { |
218 | r = dsi_runtime_get(dpi.dsidev); | 238 | r = dsi_runtime_get(dpi.dsidev); |
219 | if (r) | 239 | if (r) |
220 | goto err_get_dsi; | 240 | goto err_get_dsi; |
@@ -242,10 +262,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
242 | 262 | ||
243 | err_mgr_enable: | 263 | err_mgr_enable: |
244 | err_set_mode: | 264 | err_set_mode: |
245 | if (dpi_use_dsi_pll(dssdev)) | 265 | if (dpi.dsidev) |
246 | dsi_pll_uninit(dpi.dsidev, true); | 266 | dsi_pll_uninit(dpi.dsidev, true); |
247 | err_dsi_pll_init: | 267 | err_dsi_pll_init: |
248 | if (dpi_use_dsi_pll(dssdev)) | 268 | if (dpi.dsidev) |
249 | dsi_runtime_put(dpi.dsidev); | 269 | dsi_runtime_put(dpi.dsidev); |
250 | err_get_dsi: | 270 | err_get_dsi: |
251 | err_src_sel: | 271 | err_src_sel: |
@@ -271,8 +291,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | |||
271 | 291 | ||
272 | dss_mgr_disable(mgr); | 292 | dss_mgr_disable(mgr); |
273 | 293 | ||
274 | if (dpi_use_dsi_pll(dssdev)) { | 294 | if (dpi.dsidev) { |
275 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 295 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
276 | dsi_pll_uninit(dpi.dsidev, true); | 296 | dsi_pll_uninit(dpi.dsidev, true); |
277 | dsi_runtime_put(dpi.dsidev); | 297 | dsi_runtime_put(dpi.dsidev); |
278 | } | 298 | } |
@@ -311,13 +331,13 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
311 | unsigned long pck; | 331 | unsigned long pck; |
312 | struct dispc_clock_info dispc_cinfo; | 332 | struct dispc_clock_info dispc_cinfo; |
313 | 333 | ||
314 | if (dss_mgr_check_timings(mgr, timings)) | 334 | if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) |
315 | return -EINVAL; | 335 | return -EINVAL; |
316 | 336 | ||
317 | if (timings->pixel_clock == 0) | 337 | if (timings->pixel_clock == 0) |
318 | return -EINVAL; | 338 | return -EINVAL; |
319 | 339 | ||
320 | if (dpi_use_dsi_pll(dssdev)) { | 340 | if (dpi.dsidev) { |
321 | struct dsi_clock_info dsi_cinfo; | 341 | struct dsi_clock_info dsi_cinfo; |
322 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, | 342 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, |
323 | timings->pixel_clock * 1000, | 343 | timings->pixel_clock * 1000, |
@@ -359,8 +379,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) | |||
359 | } | 379 | } |
360 | EXPORT_SYMBOL(omapdss_dpi_set_data_lines); | 380 | EXPORT_SYMBOL(omapdss_dpi_set_data_lines); |
361 | 381 | ||
382 | static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) | ||
383 | { | ||
384 | int r; | ||
385 | |||
386 | /* do initial setup with the PLL to see if it is operational */ | ||
387 | |||
388 | r = dsi_runtime_get(dsidev); | ||
389 | if (r) | ||
390 | return r; | ||
391 | |||
392 | r = dsi_pll_init(dsidev, 0, 1); | ||
393 | if (r) { | ||
394 | dsi_runtime_put(dsidev); | ||
395 | return r; | ||
396 | } | ||
397 | |||
398 | dsi_pll_uninit(dsidev, true); | ||
399 | dsi_runtime_put(dsidev); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
362 | static int __init dpi_init_display(struct omap_dss_device *dssdev) | 404 | static int __init dpi_init_display(struct omap_dss_device *dssdev) |
363 | { | 405 | { |
406 | struct platform_device *dsidev; | ||
407 | |||
364 | DSSDBG("init_display\n"); | 408 | DSSDBG("init_display\n"); |
365 | 409 | ||
366 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && | 410 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && |
@@ -377,19 +421,30 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) | |||
377 | dpi.vdds_dsi_reg = vdds_dsi; | 421 | dpi.vdds_dsi_reg = vdds_dsi; |
378 | } | 422 | } |
379 | 423 | ||
380 | if (dpi_use_dsi_pll(dssdev)) { | 424 | /* |
381 | enum omap_dss_clk_source dispc_fclk_src = | 425 | * XXX We shouldn't need dssdev->channel for this. The dsi pll clock |
382 | dssdev->clocks.dispc.dispc_fclk_src; | 426 | * source for DPI is SoC integration detail, not something that should |
383 | dpi.dsidev = dpi_get_dsidev(dispc_fclk_src); | 427 | * be configured in the dssdev |
428 | */ | ||
429 | dsidev = dpi_get_dsidev(dssdev->channel); | ||
430 | |||
431 | if (dsidev && dpi_verify_dsi_pll(dsidev)) { | ||
432 | dsidev = NULL; | ||
433 | DSSWARN("DSI PLL not operational\n"); | ||
384 | } | 434 | } |
385 | 435 | ||
436 | if (dsidev) | ||
437 | DSSDBG("using DSI PLL for DPI clock\n"); | ||
438 | |||
439 | dpi.dsidev = dsidev; | ||
440 | |||
386 | return 0; | 441 | return 0; |
387 | } | 442 | } |
388 | 443 | ||
389 | static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) | 444 | static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) |
390 | { | 445 | { |
391 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 446 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
392 | const char *def_disp_name = dss_get_default_display_name(); | 447 | const char *def_disp_name = omapdss_get_default_display_name(); |
393 | struct omap_dss_device *def_dssdev; | 448 | struct omap_dss_device *def_dssdev; |
394 | int i; | 449 | int i; |
395 | 450 | ||
@@ -438,9 +493,18 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) | |||
438 | return; | 493 | return; |
439 | } | 494 | } |
440 | 495 | ||
496 | r = omapdss_output_set_device(&dpi.output, dssdev); | ||
497 | if (r) { | ||
498 | DSSERR("failed to connect output to new device: %s\n", | ||
499 | dssdev->name); | ||
500 | dss_put_device(dssdev); | ||
501 | return; | ||
502 | } | ||
503 | |||
441 | r = dss_add_device(dssdev); | 504 | r = dss_add_device(dssdev); |
442 | if (r) { | 505 | if (r) { |
443 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 506 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
507 | omapdss_output_unset_device(&dpi.output); | ||
444 | dss_put_device(dssdev); | 508 | dss_put_device(dssdev); |
445 | return; | 509 | return; |
446 | } | 510 | } |