diff options
Diffstat (limited to 'drivers/video/omap2/dss/dss.c')
-rw-r--r-- | drivers/video/omap2/dss/dss.c | 763 |
1 files changed, 625 insertions, 138 deletions
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 77c3621c9171..3f1fee63c678 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -26,14 +26,13 @@ | |||
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
31 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
32 | 31 | ||
33 | #include <plat/display.h> | 32 | #include <plat/display.h> |
33 | #include <plat/clock.h> | ||
34 | #include "dss.h" | 34 | #include "dss.h" |
35 | 35 | #include "dss_features.h" | |
36 | #define DSS_BASE 0x48050000 | ||
37 | 36 | ||
38 | #define DSS_SZ_REGS SZ_512 | 37 | #define DSS_SZ_REGS SZ_512 |
39 | 38 | ||
@@ -59,9 +58,17 @@ struct dss_reg { | |||
59 | dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) | 58 | dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) |
60 | 59 | ||
61 | static struct { | 60 | static struct { |
61 | struct platform_device *pdev; | ||
62 | void __iomem *base; | 62 | void __iomem *base; |
63 | int ctx_id; | ||
63 | 64 | ||
64 | struct clk *dpll4_m4_ck; | 65 | struct clk *dpll4_m4_ck; |
66 | struct clk *dss_ick; | ||
67 | struct clk *dss_fck; | ||
68 | struct clk *dss_sys_clk; | ||
69 | struct clk *dss_tv_fck; | ||
70 | struct clk *dss_video_fck; | ||
71 | unsigned num_clks_enabled; | ||
65 | 72 | ||
66 | unsigned long cache_req_pck; | 73 | unsigned long cache_req_pck; |
67 | unsigned long cache_prate; | 74 | unsigned long cache_prate; |
@@ -70,10 +77,22 @@ static struct { | |||
70 | 77 | ||
71 | enum dss_clk_source dsi_clk_source; | 78 | enum dss_clk_source dsi_clk_source; |
72 | enum dss_clk_source dispc_clk_source; | 79 | enum dss_clk_source dispc_clk_source; |
80 | enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; | ||
73 | 81 | ||
74 | u32 ctx[DSS_SZ_REGS / sizeof(u32)]; | 82 | u32 ctx[DSS_SZ_REGS / sizeof(u32)]; |
75 | } dss; | 83 | } dss; |
76 | 84 | ||
85 | static const char * const dss_generic_clk_source_names[] = { | ||
86 | [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", | ||
87 | [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", | ||
88 | [DSS_CLK_SRC_FCK] = "DSS_FCK", | ||
89 | }; | ||
90 | |||
91 | static void dss_clk_enable_all_no_ctx(void); | ||
92 | static void dss_clk_disable_all_no_ctx(void); | ||
93 | static void dss_clk_enable_no_ctx(enum dss_clock clks); | ||
94 | static void dss_clk_disable_no_ctx(enum dss_clock clks); | ||
95 | |||
77 | static int _omap_dss_wait_reset(void); | 96 | static int _omap_dss_wait_reset(void); |
78 | 97 | ||
79 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) | 98 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) |
@@ -99,10 +118,11 @@ void dss_save_context(void) | |||
99 | SR(SYSCONFIG); | 118 | SR(SYSCONFIG); |
100 | SR(CONTROL); | 119 | SR(CONTROL); |
101 | 120 | ||
102 | #ifdef CONFIG_OMAP2_DSS_SDI | 121 | if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & |
103 | SR(SDI_CONTROL); | 122 | OMAP_DISPLAY_TYPE_SDI) { |
104 | SR(PLL_CONTROL); | 123 | SR(SDI_CONTROL); |
105 | #endif | 124 | SR(PLL_CONTROL); |
125 | } | ||
106 | } | 126 | } |
107 | 127 | ||
108 | void dss_restore_context(void) | 128 | void dss_restore_context(void) |
@@ -113,10 +133,11 @@ void dss_restore_context(void) | |||
113 | RR(SYSCONFIG); | 133 | RR(SYSCONFIG); |
114 | RR(CONTROL); | 134 | RR(CONTROL); |
115 | 135 | ||
116 | #ifdef CONFIG_OMAP2_DSS_SDI | 136 | if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & |
117 | RR(SDI_CONTROL); | 137 | OMAP_DISPLAY_TYPE_SDI) { |
118 | RR(PLL_CONTROL); | 138 | RR(SDI_CONTROL); |
119 | #endif | 139 | RR(PLL_CONTROL); |
140 | } | ||
120 | } | 141 | } |
121 | 142 | ||
122 | #undef SR | 143 | #undef SR |
@@ -209,66 +230,96 @@ void dss_sdi_disable(void) | |||
209 | REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ | 230 | REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ |
210 | } | 231 | } |
211 | 232 | ||
233 | const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src) | ||
234 | { | ||
235 | return dss_generic_clk_source_names[clk_src]; | ||
236 | } | ||
237 | |||
212 | void dss_dump_clocks(struct seq_file *s) | 238 | void dss_dump_clocks(struct seq_file *s) |
213 | { | 239 | { |
214 | unsigned long dpll4_ck_rate; | 240 | unsigned long dpll4_ck_rate; |
215 | unsigned long dpll4_m4_ck_rate; | 241 | unsigned long dpll4_m4_ck_rate; |
242 | const char *fclk_name, *fclk_real_name; | ||
243 | unsigned long fclk_rate; | ||
216 | 244 | ||
217 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); | 245 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); |
218 | |||
219 | dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | ||
220 | dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); | ||
221 | 246 | ||
222 | seq_printf(s, "- DSS -\n"); | 247 | seq_printf(s, "- DSS -\n"); |
223 | 248 | ||
224 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); | 249 | fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK); |
250 | fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK); | ||
251 | fclk_rate = dss_clk_get_rate(DSS_CLK_FCK); | ||
225 | 252 | ||
226 | if (cpu_is_omap3630()) | 253 | if (dss.dpll4_m4_ck) { |
227 | seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n", | 254 | dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
228 | dpll4_ck_rate, | 255 | dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); |
229 | dpll4_ck_rate / dpll4_m4_ck_rate, | 256 | |
230 | dss_clk_get_rate(DSS_CLK_FCK1)); | 257 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); |
231 | else | ||
232 | seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", | ||
233 | dpll4_ck_rate, | ||
234 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
235 | dss_clk_get_rate(DSS_CLK_FCK1)); | ||
236 | 258 | ||
237 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); | 259 | if (cpu_is_omap3630() || cpu_is_omap44xx()) |
260 | seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", | ||
261 | fclk_name, fclk_real_name, | ||
262 | dpll4_ck_rate, | ||
263 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
264 | fclk_rate); | ||
265 | else | ||
266 | seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", | ||
267 | fclk_name, fclk_real_name, | ||
268 | dpll4_ck_rate, | ||
269 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
270 | fclk_rate); | ||
271 | } else { | ||
272 | seq_printf(s, "%s (%s) = %lu\n", | ||
273 | fclk_name, fclk_real_name, | ||
274 | fclk_rate); | ||
275 | } | ||
276 | |||
277 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); | ||
238 | } | 278 | } |
239 | 279 | ||
240 | void dss_dump_regs(struct seq_file *s) | 280 | void dss_dump_regs(struct seq_file *s) |
241 | { | 281 | { |
242 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) | 282 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) |
243 | 283 | ||
244 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); | 284 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); |
245 | 285 | ||
246 | DUMPREG(DSS_REVISION); | 286 | DUMPREG(DSS_REVISION); |
247 | DUMPREG(DSS_SYSCONFIG); | 287 | DUMPREG(DSS_SYSCONFIG); |
248 | DUMPREG(DSS_SYSSTATUS); | 288 | DUMPREG(DSS_SYSSTATUS); |
249 | DUMPREG(DSS_IRQSTATUS); | 289 | DUMPREG(DSS_IRQSTATUS); |
250 | DUMPREG(DSS_CONTROL); | 290 | DUMPREG(DSS_CONTROL); |
251 | DUMPREG(DSS_SDI_CONTROL); | ||
252 | DUMPREG(DSS_PLL_CONTROL); | ||
253 | DUMPREG(DSS_SDI_STATUS); | ||
254 | 291 | ||
255 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); | 292 | if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & |
293 | OMAP_DISPLAY_TYPE_SDI) { | ||
294 | DUMPREG(DSS_SDI_CONTROL); | ||
295 | DUMPREG(DSS_PLL_CONTROL); | ||
296 | DUMPREG(DSS_SDI_STATUS); | ||
297 | } | ||
298 | |||
299 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); | ||
256 | #undef DUMPREG | 300 | #undef DUMPREG |
257 | } | 301 | } |
258 | 302 | ||
259 | void dss_select_dispc_clk_source(enum dss_clk_source clk_src) | 303 | void dss_select_dispc_clk_source(enum dss_clk_source clk_src) |
260 | { | 304 | { |
261 | int b; | 305 | int b; |
306 | u8 start, end; | ||
307 | |||
308 | switch (clk_src) { | ||
309 | case DSS_CLK_SRC_FCK: | ||
310 | b = 0; | ||
311 | break; | ||
312 | case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | ||
313 | b = 1; | ||
314 | dsi_wait_pll_hsdiv_dispc_active(); | ||
315 | break; | ||
316 | default: | ||
317 | BUG(); | ||
318 | } | ||
262 | 319 | ||
263 | BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK && | 320 | dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); |
264 | clk_src != DSS_SRC_DSS1_ALWON_FCLK); | ||
265 | |||
266 | b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; | ||
267 | |||
268 | if (clk_src == DSS_SRC_DSI1_PLL_FCLK) | ||
269 | dsi_wait_dsi1_pll_active(); | ||
270 | 321 | ||
271 | REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ | 322 | REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */ |
272 | 323 | ||
273 | dss.dispc_clk_source = clk_src; | 324 | dss.dispc_clk_source = clk_src; |
274 | } | 325 | } |
@@ -277,19 +328,51 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) | |||
277 | { | 328 | { |
278 | int b; | 329 | int b; |
279 | 330 | ||
280 | BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK && | 331 | switch (clk_src) { |
281 | clk_src != DSS_SRC_DSS1_ALWON_FCLK); | 332 | case DSS_CLK_SRC_FCK: |
282 | 333 | b = 0; | |
283 | b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; | 334 | break; |
284 | 335 | case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: | |
285 | if (clk_src == DSS_SRC_DSI2_PLL_FCLK) | 336 | b = 1; |
286 | dsi_wait_dsi2_pll_active(); | 337 | dsi_wait_pll_hsdiv_dsi_active(); |
338 | break; | ||
339 | default: | ||
340 | BUG(); | ||
341 | } | ||
287 | 342 | ||
288 | REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ | 343 | REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ |
289 | 344 | ||
290 | dss.dsi_clk_source = clk_src; | 345 | dss.dsi_clk_source = clk_src; |
291 | } | 346 | } |
292 | 347 | ||
348 | void dss_select_lcd_clk_source(enum omap_channel channel, | ||
349 | enum dss_clk_source clk_src) | ||
350 | { | ||
351 | int b, ix, pos; | ||
352 | |||
353 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) | ||
354 | return; | ||
355 | |||
356 | switch (clk_src) { | ||
357 | case DSS_CLK_SRC_FCK: | ||
358 | b = 0; | ||
359 | break; | ||
360 | case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | ||
361 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); | ||
362 | b = 1; | ||
363 | dsi_wait_pll_hsdiv_dispc_active(); | ||
364 | break; | ||
365 | default: | ||
366 | BUG(); | ||
367 | } | ||
368 | |||
369 | pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; | ||
370 | REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */ | ||
371 | |||
372 | ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; | ||
373 | dss.lcd_clk_source[ix] = clk_src; | ||
374 | } | ||
375 | |||
293 | enum dss_clk_source dss_get_dispc_clk_source(void) | 376 | enum dss_clk_source dss_get_dispc_clk_source(void) |
294 | { | 377 | { |
295 | return dss.dispc_clk_source; | 378 | return dss.dispc_clk_source; |
@@ -300,34 +383,52 @@ enum dss_clk_source dss_get_dsi_clk_source(void) | |||
300 | return dss.dsi_clk_source; | 383 | return dss.dsi_clk_source; |
301 | } | 384 | } |
302 | 385 | ||
386 | enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) | ||
387 | { | ||
388 | int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; | ||
389 | return dss.lcd_clk_source[ix]; | ||
390 | } | ||
391 | |||
303 | /* calculate clock rates using dividers in cinfo */ | 392 | /* calculate clock rates using dividers in cinfo */ |
304 | int dss_calc_clock_rates(struct dss_clock_info *cinfo) | 393 | int dss_calc_clock_rates(struct dss_clock_info *cinfo) |
305 | { | 394 | { |
306 | unsigned long prate; | 395 | if (dss.dpll4_m4_ck) { |
396 | unsigned long prate; | ||
397 | u16 fck_div_max = 16; | ||
307 | 398 | ||
308 | if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) || | 399 | if (cpu_is_omap3630() || cpu_is_omap44xx()) |
309 | cinfo->fck_div == 0) | 400 | fck_div_max = 32; |
310 | return -EINVAL; | 401 | |
402 | if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) | ||
403 | return -EINVAL; | ||
311 | 404 | ||
312 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | 405 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
313 | 406 | ||
314 | cinfo->fck = prate / cinfo->fck_div; | 407 | cinfo->fck = prate / cinfo->fck_div; |
408 | } else { | ||
409 | if (cinfo->fck_div != 0) | ||
410 | return -EINVAL; | ||
411 | cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); | ||
412 | } | ||
315 | 413 | ||
316 | return 0; | 414 | return 0; |
317 | } | 415 | } |
318 | 416 | ||
319 | int dss_set_clock_div(struct dss_clock_info *cinfo) | 417 | int dss_set_clock_div(struct dss_clock_info *cinfo) |
320 | { | 418 | { |
321 | unsigned long prate; | 419 | if (dss.dpll4_m4_ck) { |
322 | int r; | 420 | unsigned long prate; |
421 | int r; | ||
323 | 422 | ||
324 | if (cpu_is_omap34xx()) { | ||
325 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | 423 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
326 | DSSDBG("dpll4_m4 = %ld\n", prate); | 424 | DSSDBG("dpll4_m4 = %ld\n", prate); |
327 | 425 | ||
328 | r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); | 426 | r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); |
329 | if (r) | 427 | if (r) |
330 | return r; | 428 | return r; |
429 | } else { | ||
430 | if (cinfo->fck_div != 0) | ||
431 | return -EINVAL; | ||
331 | } | 432 | } |
332 | 433 | ||
333 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); | 434 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); |
@@ -337,12 +438,14 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
337 | 438 | ||
338 | int dss_get_clock_div(struct dss_clock_info *cinfo) | 439 | int dss_get_clock_div(struct dss_clock_info *cinfo) |
339 | { | 440 | { |
340 | cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1); | 441 | cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); |
341 | 442 | ||
342 | if (cpu_is_omap34xx()) { | 443 | if (dss.dpll4_m4_ck) { |
343 | unsigned long prate; | 444 | unsigned long prate; |
445 | |||
344 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | 446 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
345 | if (cpu_is_omap3630()) | 447 | |
448 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | ||
346 | cinfo->fck_div = prate / (cinfo->fck); | 449 | cinfo->fck_div = prate / (cinfo->fck); |
347 | else | 450 | else |
348 | cinfo->fck_div = prate / (cinfo->fck / 2); | 451 | cinfo->fck_div = prate / (cinfo->fck / 2); |
@@ -355,7 +458,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) | |||
355 | 458 | ||
356 | unsigned long dss_get_dpll4_rate(void) | 459 | unsigned long dss_get_dpll4_rate(void) |
357 | { | 460 | { |
358 | if (cpu_is_omap34xx()) | 461 | if (dss.dpll4_m4_ck) |
359 | return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | 462 | return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
360 | else | 463 | else |
361 | return 0; | 464 | return 0; |
@@ -369,16 +472,18 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, | |||
369 | struct dss_clock_info best_dss; | 472 | struct dss_clock_info best_dss; |
370 | struct dispc_clock_info best_dispc; | 473 | struct dispc_clock_info best_dispc; |
371 | 474 | ||
372 | unsigned long fck; | 475 | unsigned long fck, max_dss_fck; |
373 | 476 | ||
374 | u16 fck_div; | 477 | u16 fck_div, fck_div_max = 16; |
375 | 478 | ||
376 | int match = 0; | 479 | int match = 0; |
377 | int min_fck_per_pck; | 480 | int min_fck_per_pck; |
378 | 481 | ||
379 | prate = dss_get_dpll4_rate(); | 482 | prate = dss_get_dpll4_rate(); |
380 | 483 | ||
381 | fck = dss_clk_get_rate(DSS_CLK_FCK1); | 484 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); |
485 | |||
486 | fck = dss_clk_get_rate(DSS_CLK_FCK); | ||
382 | if (req_pck == dss.cache_req_pck && | 487 | if (req_pck == dss.cache_req_pck && |
383 | ((cpu_is_omap34xx() && prate == dss.cache_prate) || | 488 | ((cpu_is_omap34xx() && prate == dss.cache_prate) || |
384 | dss.cache_dss_cinfo.fck == fck)) { | 489 | dss.cache_dss_cinfo.fck == fck)) { |
@@ -391,7 +496,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, | |||
391 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; | 496 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; |
392 | 497 | ||
393 | if (min_fck_per_pck && | 498 | if (min_fck_per_pck && |
394 | req_pck * min_fck_per_pck > DISPC_MAX_FCK) { | 499 | req_pck * min_fck_per_pck > max_dss_fck) { |
395 | DSSERR("Requested pixel clock not possible with the current " | 500 | DSSERR("Requested pixel clock not possible with the current " |
396 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " | 501 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " |
397 | "the constraint off.\n"); | 502 | "the constraint off.\n"); |
@@ -402,10 +507,10 @@ retry: | |||
402 | memset(&best_dss, 0, sizeof(best_dss)); | 507 | memset(&best_dss, 0, sizeof(best_dss)); |
403 | memset(&best_dispc, 0, sizeof(best_dispc)); | 508 | memset(&best_dispc, 0, sizeof(best_dispc)); |
404 | 509 | ||
405 | if (cpu_is_omap24xx()) { | 510 | if (dss.dpll4_m4_ck == NULL) { |
406 | struct dispc_clock_info cur_dispc; | 511 | struct dispc_clock_info cur_dispc; |
407 | /* XXX can we change the clock on omap2? */ | 512 | /* XXX can we change the clock on omap2? */ |
408 | fck = dss_clk_get_rate(DSS_CLK_FCK1); | 513 | fck = dss_clk_get_rate(DSS_CLK_FCK); |
409 | fck_div = 1; | 514 | fck_div = 1; |
410 | 515 | ||
411 | dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); | 516 | dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); |
@@ -417,17 +522,19 @@ retry: | |||
417 | best_dispc = cur_dispc; | 522 | best_dispc = cur_dispc; |
418 | 523 | ||
419 | goto found; | 524 | goto found; |
420 | } else if (cpu_is_omap34xx()) { | 525 | } else { |
421 | for (fck_div = (cpu_is_omap3630() ? 32 : 16); | 526 | if (cpu_is_omap3630() || cpu_is_omap44xx()) |
422 | fck_div > 0; --fck_div) { | 527 | fck_div_max = 32; |
528 | |||
529 | for (fck_div = fck_div_max; fck_div > 0; --fck_div) { | ||
423 | struct dispc_clock_info cur_dispc; | 530 | struct dispc_clock_info cur_dispc; |
424 | 531 | ||
425 | if (cpu_is_omap3630()) | 532 | if (fck_div_max == 32) |
426 | fck = prate / fck_div; | 533 | fck = prate / fck_div; |
427 | else | 534 | else |
428 | fck = prate / fck_div * 2; | 535 | fck = prate / fck_div * 2; |
429 | 536 | ||
430 | if (fck > DISPC_MAX_FCK) | 537 | if (fck > max_dss_fck) |
431 | continue; | 538 | continue; |
432 | 539 | ||
433 | if (min_fck_per_pck && | 540 | if (min_fck_per_pck && |
@@ -450,8 +557,6 @@ retry: | |||
450 | goto found; | 557 | goto found; |
451 | } | 558 | } |
452 | } | 559 | } |
453 | } else { | ||
454 | BUG(); | ||
455 | } | 560 | } |
456 | 561 | ||
457 | found: | 562 | found: |
@@ -482,31 +587,6 @@ found: | |||
482 | return 0; | 587 | return 0; |
483 | } | 588 | } |
484 | 589 | ||
485 | |||
486 | |||
487 | static irqreturn_t dss_irq_handler_omap2(int irq, void *arg) | ||
488 | { | ||
489 | dispc_irq_handler(); | ||
490 | |||
491 | return IRQ_HANDLED; | ||
492 | } | ||
493 | |||
494 | static irqreturn_t dss_irq_handler_omap3(int irq, void *arg) | ||
495 | { | ||
496 | u32 irqstatus; | ||
497 | |||
498 | irqstatus = dss_read_reg(DSS_IRQSTATUS); | ||
499 | |||
500 | if (irqstatus & (1<<0)) /* DISPC_IRQ */ | ||
501 | dispc_irq_handler(); | ||
502 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
503 | if (irqstatus & (1<<1)) /* DSI_IRQ */ | ||
504 | dsi_irq_handler(); | ||
505 | #endif | ||
506 | |||
507 | return IRQ_HANDLED; | ||
508 | } | ||
509 | |||
510 | static int _omap_dss_wait_reset(void) | 590 | static int _omap_dss_wait_reset(void) |
511 | { | 591 | { |
512 | int t = 0; | 592 | int t = 0; |
@@ -549,34 +629,45 @@ void dss_set_dac_pwrdn_bgz(bool enable) | |||
549 | REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ | 629 | REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ |
550 | } | 630 | } |
551 | 631 | ||
552 | int dss_init(bool skip_init) | 632 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) |
633 | { | ||
634 | REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ | ||
635 | } | ||
636 | |||
637 | static int dss_init(void) | ||
553 | { | 638 | { |
554 | int r; | 639 | int r; |
555 | u32 rev; | 640 | u32 rev; |
641 | struct resource *dss_mem; | ||
642 | struct clk *dpll4_m4_ck; | ||
556 | 643 | ||
557 | dss.base = ioremap(DSS_BASE, DSS_SZ_REGS); | 644 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); |
645 | if (!dss_mem) { | ||
646 | DSSERR("can't get IORESOURCE_MEM DSS\n"); | ||
647 | r = -EINVAL; | ||
648 | goto fail0; | ||
649 | } | ||
650 | dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); | ||
558 | if (!dss.base) { | 651 | if (!dss.base) { |
559 | DSSERR("can't ioremap DSS\n"); | 652 | DSSERR("can't ioremap DSS\n"); |
560 | r = -ENOMEM; | 653 | r = -ENOMEM; |
561 | goto fail0; | 654 | goto fail0; |
562 | } | 655 | } |
563 | 656 | ||
564 | if (!skip_init) { | 657 | /* disable LCD and DIGIT output. This seems to fix the synclost |
565 | /* disable LCD and DIGIT output. This seems to fix the synclost | 658 | * problem that we get, if the bootloader starts the DSS and |
566 | * problem that we get, if the bootloader starts the DSS and | 659 | * the kernel resets it */ |
567 | * the kernel resets it */ | 660 | omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440); |
568 | omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440); | ||
569 | 661 | ||
570 | /* We need to wait here a bit, otherwise we sometimes start to | 662 | /* We need to wait here a bit, otherwise we sometimes start to |
571 | * get synclost errors, and after that only power cycle will | 663 | * get synclost errors, and after that only power cycle will |
572 | * restore DSS functionality. I have no idea why this happens. | 664 | * restore DSS functionality. I have no idea why this happens. |
573 | * And we have to wait _before_ resetting the DSS, but after | 665 | * And we have to wait _before_ resetting the DSS, but after |
574 | * enabling clocks. | 666 | * enabling clocks. |
575 | */ | 667 | */ |
576 | msleep(50); | 668 | msleep(50); |
577 | 669 | ||
578 | _omap_dss_reset(); | 670 | _omap_dss_reset(); |
579 | } | ||
580 | 671 | ||
581 | /* autoidle */ | 672 | /* autoidle */ |
582 | REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0); | 673 | REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0); |
@@ -589,29 +680,30 @@ int dss_init(bool skip_init) | |||
589 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ | 680 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ |
590 | REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ | 681 | REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ |
591 | #endif | 682 | #endif |
592 | |||
593 | r = request_irq(INT_24XX_DSS_IRQ, | ||
594 | cpu_is_omap24xx() | ||
595 | ? dss_irq_handler_omap2 | ||
596 | : dss_irq_handler_omap3, | ||
597 | 0, "OMAP DSS", NULL); | ||
598 | |||
599 | if (r < 0) { | ||
600 | DSSERR("omap2 dss: request_irq failed\n"); | ||
601 | goto fail1; | ||
602 | } | ||
603 | |||
604 | if (cpu_is_omap34xx()) { | 683 | if (cpu_is_omap34xx()) { |
605 | dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); | 684 | dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); |
606 | if (IS_ERR(dss.dpll4_m4_ck)) { | 685 | if (IS_ERR(dpll4_m4_ck)) { |
607 | DSSERR("Failed to get dpll4_m4_ck\n"); | 686 | DSSERR("Failed to get dpll4_m4_ck\n"); |
608 | r = PTR_ERR(dss.dpll4_m4_ck); | 687 | r = PTR_ERR(dpll4_m4_ck); |
609 | goto fail2; | 688 | goto fail1; |
610 | } | 689 | } |
690 | } else if (cpu_is_omap44xx()) { | ||
691 | dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); | ||
692 | if (IS_ERR(dpll4_m4_ck)) { | ||
693 | DSSERR("Failed to get dpll4_m4_ck\n"); | ||
694 | r = PTR_ERR(dpll4_m4_ck); | ||
695 | goto fail1; | ||
696 | } | ||
697 | } else { /* omap24xx */ | ||
698 | dpll4_m4_ck = NULL; | ||
611 | } | 699 | } |
612 | 700 | ||
613 | dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK; | 701 | dss.dpll4_m4_ck = dpll4_m4_ck; |
614 | dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK; | 702 | |
703 | dss.dsi_clk_source = DSS_CLK_SRC_FCK; | ||
704 | dss.dispc_clk_source = DSS_CLK_SRC_FCK; | ||
705 | dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; | ||
706 | dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; | ||
615 | 707 | ||
616 | dss_save_context(); | 708 | dss_save_context(); |
617 | 709 | ||
@@ -621,21 +713,416 @@ int dss_init(bool skip_init) | |||
621 | 713 | ||
622 | return 0; | 714 | return 0; |
623 | 715 | ||
624 | fail2: | ||
625 | free_irq(INT_24XX_DSS_IRQ, NULL); | ||
626 | fail1: | 716 | fail1: |
627 | iounmap(dss.base); | 717 | iounmap(dss.base); |
628 | fail0: | 718 | fail0: |
629 | return r; | 719 | return r; |
630 | } | 720 | } |
631 | 721 | ||
632 | void dss_exit(void) | 722 | static void dss_exit(void) |
633 | { | 723 | { |
634 | if (cpu_is_omap34xx()) | 724 | if (dss.dpll4_m4_ck) |
635 | clk_put(dss.dpll4_m4_ck); | 725 | clk_put(dss.dpll4_m4_ck); |
636 | 726 | ||
637 | free_irq(INT_24XX_DSS_IRQ, NULL); | ||
638 | |||
639 | iounmap(dss.base); | 727 | iounmap(dss.base); |
640 | } | 728 | } |
641 | 729 | ||
730 | /* CONTEXT */ | ||
731 | static int dss_get_ctx_id(void) | ||
732 | { | ||
733 | struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; | ||
734 | int r; | ||
735 | |||
736 | if (!pdata->board_data->get_last_off_on_transaction_id) | ||
737 | return 0; | ||
738 | r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev); | ||
739 | if (r < 0) { | ||
740 | dev_err(&dss.pdev->dev, "getting transaction ID failed, " | ||
741 | "will force context restore\n"); | ||
742 | r = -1; | ||
743 | } | ||
744 | return r; | ||
745 | } | ||
746 | |||
747 | int dss_need_ctx_restore(void) | ||
748 | { | ||
749 | int id = dss_get_ctx_id(); | ||
750 | |||
751 | if (id < 0 || id != dss.ctx_id) { | ||
752 | DSSDBG("ctx id %d -> id %d\n", | ||
753 | dss.ctx_id, id); | ||
754 | dss.ctx_id = id; | ||
755 | return 1; | ||
756 | } else { | ||
757 | return 0; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | static void save_all_ctx(void) | ||
762 | { | ||
763 | DSSDBG("save context\n"); | ||
764 | |||
765 | dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); | ||
766 | |||
767 | dss_save_context(); | ||
768 | dispc_save_context(); | ||
769 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
770 | dsi_save_context(); | ||
771 | #endif | ||
772 | |||
773 | dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); | ||
774 | } | ||
775 | |||
776 | static void restore_all_ctx(void) | ||
777 | { | ||
778 | DSSDBG("restore context\n"); | ||
779 | |||
780 | dss_clk_enable_all_no_ctx(); | ||
781 | |||
782 | dss_restore_context(); | ||
783 | dispc_restore_context(); | ||
784 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
785 | dsi_restore_context(); | ||
786 | #endif | ||
787 | |||
788 | dss_clk_disable_all_no_ctx(); | ||
789 | } | ||
790 | |||
791 | static int dss_get_clock(struct clk **clock, const char *clk_name) | ||
792 | { | ||
793 | struct clk *clk; | ||
794 | |||
795 | clk = clk_get(&dss.pdev->dev, clk_name); | ||
796 | |||
797 | if (IS_ERR(clk)) { | ||
798 | DSSERR("can't get clock %s", clk_name); | ||
799 | return PTR_ERR(clk); | ||
800 | } | ||
801 | |||
802 | *clock = clk; | ||
803 | |||
804 | DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk)); | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static int dss_get_clocks(void) | ||
810 | { | ||
811 | int r; | ||
812 | struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; | ||
813 | |||
814 | dss.dss_ick = NULL; | ||
815 | dss.dss_fck = NULL; | ||
816 | dss.dss_sys_clk = NULL; | ||
817 | dss.dss_tv_fck = NULL; | ||
818 | dss.dss_video_fck = NULL; | ||
819 | |||
820 | r = dss_get_clock(&dss.dss_ick, "ick"); | ||
821 | if (r) | ||
822 | goto err; | ||
823 | |||
824 | r = dss_get_clock(&dss.dss_fck, "fck"); | ||
825 | if (r) | ||
826 | goto err; | ||
827 | |||
828 | if (!pdata->opt_clock_available) { | ||
829 | r = -ENODEV; | ||
830 | goto err; | ||
831 | } | ||
832 | |||
833 | if (pdata->opt_clock_available("sys_clk")) { | ||
834 | r = dss_get_clock(&dss.dss_sys_clk, "sys_clk"); | ||
835 | if (r) | ||
836 | goto err; | ||
837 | } | ||
838 | |||
839 | if (pdata->opt_clock_available("tv_clk")) { | ||
840 | r = dss_get_clock(&dss.dss_tv_fck, "tv_clk"); | ||
841 | if (r) | ||
842 | goto err; | ||
843 | } | ||
844 | |||
845 | if (pdata->opt_clock_available("video_clk")) { | ||
846 | r = dss_get_clock(&dss.dss_video_fck, "video_clk"); | ||
847 | if (r) | ||
848 | goto err; | ||
849 | } | ||
850 | |||
851 | return 0; | ||
852 | |||
853 | err: | ||
854 | if (dss.dss_ick) | ||
855 | clk_put(dss.dss_ick); | ||
856 | if (dss.dss_fck) | ||
857 | clk_put(dss.dss_fck); | ||
858 | if (dss.dss_sys_clk) | ||
859 | clk_put(dss.dss_sys_clk); | ||
860 | if (dss.dss_tv_fck) | ||
861 | clk_put(dss.dss_tv_fck); | ||
862 | if (dss.dss_video_fck) | ||
863 | clk_put(dss.dss_video_fck); | ||
864 | |||
865 | return r; | ||
866 | } | ||
867 | |||
868 | static void dss_put_clocks(void) | ||
869 | { | ||
870 | if (dss.dss_video_fck) | ||
871 | clk_put(dss.dss_video_fck); | ||
872 | if (dss.dss_tv_fck) | ||
873 | clk_put(dss.dss_tv_fck); | ||
874 | if (dss.dss_sys_clk) | ||
875 | clk_put(dss.dss_sys_clk); | ||
876 | clk_put(dss.dss_fck); | ||
877 | clk_put(dss.dss_ick); | ||
878 | } | ||
879 | |||
880 | unsigned long dss_clk_get_rate(enum dss_clock clk) | ||
881 | { | ||
882 | switch (clk) { | ||
883 | case DSS_CLK_ICK: | ||
884 | return clk_get_rate(dss.dss_ick); | ||
885 | case DSS_CLK_FCK: | ||
886 | return clk_get_rate(dss.dss_fck); | ||
887 | case DSS_CLK_SYSCK: | ||
888 | return clk_get_rate(dss.dss_sys_clk); | ||
889 | case DSS_CLK_TVFCK: | ||
890 | return clk_get_rate(dss.dss_tv_fck); | ||
891 | case DSS_CLK_VIDFCK: | ||
892 | return clk_get_rate(dss.dss_video_fck); | ||
893 | } | ||
894 | |||
895 | BUG(); | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | static unsigned count_clk_bits(enum dss_clock clks) | ||
900 | { | ||
901 | unsigned num_clks = 0; | ||
902 | |||
903 | if (clks & DSS_CLK_ICK) | ||
904 | ++num_clks; | ||
905 | if (clks & DSS_CLK_FCK) | ||
906 | ++num_clks; | ||
907 | if (clks & DSS_CLK_SYSCK) | ||
908 | ++num_clks; | ||
909 | if (clks & DSS_CLK_TVFCK) | ||
910 | ++num_clks; | ||
911 | if (clks & DSS_CLK_VIDFCK) | ||
912 | ++num_clks; | ||
913 | |||
914 | return num_clks; | ||
915 | } | ||
916 | |||
917 | static void dss_clk_enable_no_ctx(enum dss_clock clks) | ||
918 | { | ||
919 | unsigned num_clks = count_clk_bits(clks); | ||
920 | |||
921 | if (clks & DSS_CLK_ICK) | ||
922 | clk_enable(dss.dss_ick); | ||
923 | if (clks & DSS_CLK_FCK) | ||
924 | clk_enable(dss.dss_fck); | ||
925 | if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) | ||
926 | clk_enable(dss.dss_sys_clk); | ||
927 | if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) | ||
928 | clk_enable(dss.dss_tv_fck); | ||
929 | if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) | ||
930 | clk_enable(dss.dss_video_fck); | ||
931 | |||
932 | dss.num_clks_enabled += num_clks; | ||
933 | } | ||
934 | |||
935 | void dss_clk_enable(enum dss_clock clks) | ||
936 | { | ||
937 | bool check_ctx = dss.num_clks_enabled == 0; | ||
938 | |||
939 | dss_clk_enable_no_ctx(clks); | ||
940 | |||
941 | /* | ||
942 | * HACK: On omap4 the registers may not be accessible right after | ||
943 | * enabling the clocks. At some point this will be handled by | ||
944 | * pm_runtime, but for the time begin this should make things work. | ||
945 | */ | ||
946 | if (cpu_is_omap44xx() && check_ctx) | ||
947 | udelay(10); | ||
948 | |||
949 | if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) | ||
950 | restore_all_ctx(); | ||
951 | } | ||
952 | |||
953 | static void dss_clk_disable_no_ctx(enum dss_clock clks) | ||
954 | { | ||
955 | unsigned num_clks = count_clk_bits(clks); | ||
956 | |||
957 | if (clks & DSS_CLK_ICK) | ||
958 | clk_disable(dss.dss_ick); | ||
959 | if (clks & DSS_CLK_FCK) | ||
960 | clk_disable(dss.dss_fck); | ||
961 | if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) | ||
962 | clk_disable(dss.dss_sys_clk); | ||
963 | if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) | ||
964 | clk_disable(dss.dss_tv_fck); | ||
965 | if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) | ||
966 | clk_disable(dss.dss_video_fck); | ||
967 | |||
968 | dss.num_clks_enabled -= num_clks; | ||
969 | } | ||
970 | |||
971 | void dss_clk_disable(enum dss_clock clks) | ||
972 | { | ||
973 | if (cpu_is_omap34xx()) { | ||
974 | unsigned num_clks = count_clk_bits(clks); | ||
975 | |||
976 | BUG_ON(dss.num_clks_enabled < num_clks); | ||
977 | |||
978 | if (dss.num_clks_enabled == num_clks) | ||
979 | save_all_ctx(); | ||
980 | } | ||
981 | |||
982 | dss_clk_disable_no_ctx(clks); | ||
983 | } | ||
984 | |||
985 | static void dss_clk_enable_all_no_ctx(void) | ||
986 | { | ||
987 | enum dss_clock clks; | ||
988 | |||
989 | clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; | ||
990 | if (cpu_is_omap34xx()) | ||
991 | clks |= DSS_CLK_VIDFCK; | ||
992 | dss_clk_enable_no_ctx(clks); | ||
993 | } | ||
994 | |||
995 | static void dss_clk_disable_all_no_ctx(void) | ||
996 | { | ||
997 | enum dss_clock clks; | ||
998 | |||
999 | clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; | ||
1000 | if (cpu_is_omap34xx()) | ||
1001 | clks |= DSS_CLK_VIDFCK; | ||
1002 | dss_clk_disable_no_ctx(clks); | ||
1003 | } | ||
1004 | |||
1005 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | ||
1006 | /* CLOCKS */ | ||
1007 | static void core_dump_clocks(struct seq_file *s) | ||
1008 | { | ||
1009 | int i; | ||
1010 | struct clk *clocks[5] = { | ||
1011 | dss.dss_ick, | ||
1012 | dss.dss_fck, | ||
1013 | dss.dss_sys_clk, | ||
1014 | dss.dss_tv_fck, | ||
1015 | dss.dss_video_fck | ||
1016 | }; | ||
1017 | |||
1018 | seq_printf(s, "- CORE -\n"); | ||
1019 | |||
1020 | seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled); | ||
1021 | |||
1022 | for (i = 0; i < 5; i++) { | ||
1023 | if (!clocks[i]) | ||
1024 | continue; | ||
1025 | seq_printf(s, "%-15s\t%lu\t%d\n", | ||
1026 | clocks[i]->name, | ||
1027 | clk_get_rate(clocks[i]), | ||
1028 | clocks[i]->usecount); | ||
1029 | } | ||
1030 | } | ||
1031 | #endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */ | ||
1032 | |||
1033 | /* DEBUGFS */ | ||
1034 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | ||
1035 | void dss_debug_dump_clocks(struct seq_file *s) | ||
1036 | { | ||
1037 | core_dump_clocks(s); | ||
1038 | dss_dump_clocks(s); | ||
1039 | dispc_dump_clocks(s); | ||
1040 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
1041 | dsi_dump_clocks(s); | ||
1042 | #endif | ||
1043 | } | ||
1044 | #endif | ||
1045 | |||
1046 | |||
1047 | /* DSS HW IP initialisation */ | ||
1048 | static int omap_dsshw_probe(struct platform_device *pdev) | ||
1049 | { | ||
1050 | int r; | ||
1051 | |||
1052 | dss.pdev = pdev; | ||
1053 | |||
1054 | r = dss_get_clocks(); | ||
1055 | if (r) | ||
1056 | goto err_clocks; | ||
1057 | |||
1058 | dss_clk_enable_all_no_ctx(); | ||
1059 | |||
1060 | dss.ctx_id = dss_get_ctx_id(); | ||
1061 | DSSDBG("initial ctx id %u\n", dss.ctx_id); | ||
1062 | |||
1063 | r = dss_init(); | ||
1064 | if (r) { | ||
1065 | DSSERR("Failed to initialize DSS\n"); | ||
1066 | goto err_dss; | ||
1067 | } | ||
1068 | |||
1069 | r = dpi_init(); | ||
1070 | if (r) { | ||
1071 | DSSERR("Failed to initialize DPI\n"); | ||
1072 | goto err_dpi; | ||
1073 | } | ||
1074 | |||
1075 | r = sdi_init(); | ||
1076 | if (r) { | ||
1077 | DSSERR("Failed to initialize SDI\n"); | ||
1078 | goto err_sdi; | ||
1079 | } | ||
1080 | |||
1081 | dss_clk_disable_all_no_ctx(); | ||
1082 | return 0; | ||
1083 | err_sdi: | ||
1084 | dpi_exit(); | ||
1085 | err_dpi: | ||
1086 | dss_exit(); | ||
1087 | err_dss: | ||
1088 | dss_clk_disable_all_no_ctx(); | ||
1089 | dss_put_clocks(); | ||
1090 | err_clocks: | ||
1091 | return r; | ||
1092 | } | ||
1093 | |||
1094 | static int omap_dsshw_remove(struct platform_device *pdev) | ||
1095 | { | ||
1096 | |||
1097 | dss_exit(); | ||
1098 | |||
1099 | /* | ||
1100 | * As part of hwmod changes, DSS is not the only controller of dss | ||
1101 | * clocks; hwmod framework itself will also enable clocks during hwmod | ||
1102 | * init for dss, and autoidle is set in h/w for DSS. Hence, there's no | ||
1103 | * need to disable clocks if their usecounts > 1. | ||
1104 | */ | ||
1105 | WARN_ON(dss.num_clks_enabled > 0); | ||
1106 | |||
1107 | dss_put_clocks(); | ||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | static struct platform_driver omap_dsshw_driver = { | ||
1112 | .probe = omap_dsshw_probe, | ||
1113 | .remove = omap_dsshw_remove, | ||
1114 | .driver = { | ||
1115 | .name = "omapdss_dss", | ||
1116 | .owner = THIS_MODULE, | ||
1117 | }, | ||
1118 | }; | ||
1119 | |||
1120 | int dss_init_platform_driver(void) | ||
1121 | { | ||
1122 | return platform_driver_register(&omap_dsshw_driver); | ||
1123 | } | ||
1124 | |||
1125 | void dss_uninit_platform_driver(void) | ||
1126 | { | ||
1127 | return platform_driver_unregister(&omap_dsshw_driver); | ||
1128 | } | ||