2 * linux/drivers/video/omap2/dss/dpi.c
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DSS_SUBSYS_NAME "DPI"
25 #include <linux/kernel.h>
26 #include <linux/clk.h>
27 #include <linux/delay.h>
28 #include <linux/errno.h>
30 #include <plat/display.h>
39 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
40 static int dpi_set_dsi_clk(bool is_tft
, unsigned long pck_req
,
41 unsigned long *fck
, int *lck_div
, int *pck_div
)
43 struct dsi_clock_info dsi_cinfo
;
44 struct dispc_clock_info dispc_cinfo
;
47 r
= dsi_pll_calc_clock_div_pck(is_tft
, pck_req
, &dsi_cinfo
,
52 r
= dsi_pll_set_clock_div(&dsi_cinfo
);
56 dss_select_clk_source(0, 1);
58 r
= dispc_set_clock_div(&dispc_cinfo
);
62 *fck
= dsi_cinfo
.dsi1_pll_fclk
;
63 *lck_div
= dispc_cinfo
.lck_div
;
64 *pck_div
= dispc_cinfo
.pck_div
;
69 static int dpi_set_dispc_clk(bool is_tft
, unsigned long pck_req
,
70 unsigned long *fck
, int *lck_div
, int *pck_div
)
72 struct dss_clock_info dss_cinfo
;
73 struct dispc_clock_info dispc_cinfo
;
76 r
= dss_calc_clock_div(is_tft
, pck_req
, &dss_cinfo
, &dispc_cinfo
);
80 r
= dss_set_clock_div(&dss_cinfo
);
84 r
= dispc_set_clock_div(&dispc_cinfo
);
89 *lck_div
= dispc_cinfo
.lck_div
;
90 *pck_div
= dispc_cinfo
.pck_div
;
96 static int dpi_set_mode(struct omap_dss_device
*dssdev
)
98 struct omap_video_timings
*t
= &dssdev
->panel
.timings
;
105 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
107 dispc_set_pol_freq(dssdev
->panel
.config
, dssdev
->panel
.acbi
,
110 is_tft
= (dssdev
->panel
.config
& OMAP_DSS_LCD_TFT
) != 0;
112 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
113 r
= dpi_set_dsi_clk(is_tft
, t
->pixel_clock
* 1000,
114 &fck
, &lck_div
, &pck_div
);
116 r
= dpi_set_dispc_clk(is_tft
, t
->pixel_clock
* 1000,
117 &fck
, &lck_div
, &pck_div
);
122 pck
= fck
/ lck_div
/ pck_div
/ 1000;
124 if (pck
!= t
->pixel_clock
) {
125 DSSWARN("Could not find exact pixel clock. "
126 "Requested %d kHz, got %lu kHz\n",
127 t
->pixel_clock
, pck
);
129 t
->pixel_clock
= pck
;
132 dispc_set_lcd_timings(t
);
135 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
139 static int dpi_basic_init(struct omap_dss_device
*dssdev
)
143 is_tft
= (dssdev
->panel
.config
& OMAP_DSS_LCD_TFT
) != 0;
145 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS
);
146 dispc_set_lcd_display_type(is_tft
? OMAP_DSS_LCD_DISPLAY_TFT
:
147 OMAP_DSS_LCD_DISPLAY_STN
);
148 dispc_set_tft_data_lines(dssdev
->phy
.dpi
.data_lines
);
153 static int dpi_display_enable(struct omap_dss_device
*dssdev
)
157 r
= omap_dss_start_device(dssdev
);
159 DSSERR("failed to start device\n");
163 if (dssdev
->state
!= OMAP_DSS_DISPLAY_DISABLED
) {
164 DSSERR("display already enabled\n");
169 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
171 r
= dpi_basic_init(dssdev
);
175 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
176 dss_clk_enable(DSS_CLK_FCK2
);
177 r
= dsi_pll_init(dssdev
, 0, 1);
181 r
= dpi_set_mode(dssdev
);
187 dispc_enable_lcd_out(1);
189 r
= dssdev
->driver
->enable(dssdev
);
193 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
198 dispc_enable_lcd_out(0);
200 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
203 dss_clk_disable(DSS_CLK_FCK2
);
206 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
208 omap_dss_stop_device(dssdev
);
213 static int dpi_display_resume(struct omap_dss_device
*dssdev
);
215 static void dpi_display_disable(struct omap_dss_device
*dssdev
)
217 if (dssdev
->state
== OMAP_DSS_DISPLAY_DISABLED
)
220 if (dssdev
->state
== OMAP_DSS_DISPLAY_SUSPENDED
)
221 dpi_display_resume(dssdev
);
223 dssdev
->driver
->disable(dssdev
);
225 dispc_enable_lcd_out(0);
227 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
228 dss_select_clk_source(0, 0);
230 dss_clk_disable(DSS_CLK_FCK2
);
233 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
235 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
237 omap_dss_stop_device(dssdev
);
240 static int dpi_display_suspend(struct omap_dss_device
*dssdev
)
242 if (dssdev
->state
!= OMAP_DSS_DISPLAY_ACTIVE
)
245 DSSDBG("dpi_display_suspend\n");
247 if (dssdev
->driver
->suspend
)
248 dssdev
->driver
->suspend(dssdev
);
250 dispc_enable_lcd_out(0);
252 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
254 dssdev
->state
= OMAP_DSS_DISPLAY_SUSPENDED
;
259 static int dpi_display_resume(struct omap_dss_device
*dssdev
)
261 if (dssdev
->state
!= OMAP_DSS_DISPLAY_SUSPENDED
)
264 DSSDBG("dpi_display_resume\n");
266 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
268 dispc_enable_lcd_out(1);
270 if (dssdev
->driver
->resume
)
271 dssdev
->driver
->resume(dssdev
);
273 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
278 static void dpi_set_timings(struct omap_dss_device
*dssdev
,
279 struct omap_video_timings
*timings
)
281 DSSDBG("dpi_set_timings\n");
282 dssdev
->panel
.timings
= *timings
;
283 if (dssdev
->state
== OMAP_DSS_DISPLAY_ACTIVE
) {
284 dpi_set_mode(dssdev
);
285 dispc_go(OMAP_DSS_CHANNEL_LCD
);
289 static int dpi_check_timings(struct omap_dss_device
*dssdev
,
290 struct omap_video_timings
*timings
)
294 int lck_div
, pck_div
;
298 if (!dispc_lcd_timings_ok(timings
))
301 if (timings
->pixel_clock
== 0)
304 is_tft
= (dssdev
->panel
.config
& OMAP_DSS_LCD_TFT
) != 0;
306 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
308 struct dsi_clock_info dsi_cinfo
;
309 struct dispc_clock_info dispc_cinfo
;
310 r
= dsi_pll_calc_clock_div_pck(is_tft
,
311 timings
->pixel_clock
* 1000,
312 &dsi_cinfo
, &dispc_cinfo
);
317 fck
= dsi_cinfo
.dsi1_pll_fclk
;
318 lck_div
= dispc_cinfo
.lck_div
;
319 pck_div
= dispc_cinfo
.pck_div
;
323 struct dss_clock_info dss_cinfo
;
324 struct dispc_clock_info dispc_cinfo
;
325 r
= dss_calc_clock_div(is_tft
, timings
->pixel_clock
* 1000,
326 &dss_cinfo
, &dispc_cinfo
);
332 lck_div
= dispc_cinfo
.lck_div
;
333 pck_div
= dispc_cinfo
.pck_div
;
337 pck
= fck
/ lck_div
/ pck_div
/ 1000;
339 timings
->pixel_clock
= pck
;
344 static void dpi_get_timings(struct omap_dss_device
*dssdev
,
345 struct omap_video_timings
*timings
)
347 *timings
= dssdev
->panel
.timings
;
350 static int dpi_display_set_update_mode(struct omap_dss_device
*dssdev
,
351 enum omap_dss_update_mode mode
)
353 if (mode
== OMAP_DSS_UPDATE_MANUAL
)
356 if (mode
== OMAP_DSS_UPDATE_DISABLED
) {
357 dispc_enable_lcd_out(0);
358 dpi
.update_enabled
= 0;
360 dispc_enable_lcd_out(1);
361 dpi
.update_enabled
= 1;
367 static enum omap_dss_update_mode
dpi_display_get_update_mode(
368 struct omap_dss_device
*dssdev
)
370 return dpi
.update_enabled
? OMAP_DSS_UPDATE_AUTO
:
371 OMAP_DSS_UPDATE_DISABLED
;
374 int dpi_init_display(struct omap_dss_device
*dssdev
)
376 DSSDBG("init_display\n");
378 dssdev
->enable
= dpi_display_enable
;
379 dssdev
->disable
= dpi_display_disable
;
380 dssdev
->suspend
= dpi_display_suspend
;
381 dssdev
->resume
= dpi_display_resume
;
382 dssdev
->set_timings
= dpi_set_timings
;
383 dssdev
->check_timings
= dpi_check_timings
;
384 dssdev
->get_timings
= dpi_get_timings
;
385 dssdev
->set_update_mode
= dpi_display_set_update_mode
;
386 dssdev
->get_update_mode
= dpi_display_get_update_mode
;