diff options
Diffstat (limited to 'drivers/video/omap2/dss/dispc.c')
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 335 |
1 files changed, 242 insertions, 93 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 9f8c69f16e61..7804779c9da1 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
34 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
35 | #include <linux/interrupt.h> | ||
35 | 36 | ||
36 | #include <plat/sram.h> | 37 | #include <plat/sram.h> |
37 | #include <plat/clock.h> | 38 | #include <plat/clock.h> |
@@ -42,8 +43,6 @@ | |||
42 | #include "dss_features.h" | 43 | #include "dss_features.h" |
43 | 44 | ||
44 | /* DISPC */ | 45 | /* DISPC */ |
45 | #define DISPC_BASE 0x48050400 | ||
46 | |||
47 | #define DISPC_SZ_REGS SZ_4K | 46 | #define DISPC_SZ_REGS SZ_4K |
48 | 47 | ||
49 | struct dispc_reg { u16 idx; }; | 48 | struct dispc_reg { u16 idx; }; |
@@ -74,7 +73,7 @@ struct dispc_reg { u16 idx; }; | |||
74 | #define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400) | 73 | #define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400) |
75 | #define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404) | 74 | #define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404) |
76 | #define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408) | 75 | #define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408) |
77 | #define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) | 76 | #define DISPC_DIVISORo(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) |
78 | #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) | 77 | #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) |
79 | #define DISPC_SIZE_DIG DISPC_REG(0x0078) | 78 | #define DISPC_SIZE_DIG DISPC_REG(0x0078) |
80 | #define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC) | 79 | #define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC) |
@@ -129,6 +128,7 @@ struct dispc_reg { u16 idx; }; | |||
129 | 128 | ||
130 | #define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04) | 129 | #define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04) |
131 | 130 | ||
131 | #define DISPC_DIVISOR DISPC_REG(0x0804) | ||
132 | 132 | ||
133 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | 133 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ |
134 | DISPC_IRQ_OCP_ERR | \ | 134 | DISPC_IRQ_OCP_ERR | \ |
@@ -178,7 +178,9 @@ struct dispc_irq_stats { | |||
178 | }; | 178 | }; |
179 | 179 | ||
180 | static struct { | 180 | static struct { |
181 | struct platform_device *pdev; | ||
181 | void __iomem *base; | 182 | void __iomem *base; |
183 | int irq; | ||
182 | 184 | ||
183 | u32 fifo_size[3]; | 185 | u32 fifo_size[3]; |
184 | 186 | ||
@@ -230,7 +232,7 @@ void dispc_save_context(void) | |||
230 | SR(TIMING_H(0)); | 232 | SR(TIMING_H(0)); |
231 | SR(TIMING_V(0)); | 233 | SR(TIMING_V(0)); |
232 | SR(POL_FREQ(0)); | 234 | SR(POL_FREQ(0)); |
233 | SR(DIVISOR(0)); | 235 | SR(DIVISORo(0)); |
234 | SR(GLOBAL_ALPHA); | 236 | SR(GLOBAL_ALPHA); |
235 | SR(SIZE_DIG); | 237 | SR(SIZE_DIG); |
236 | SR(SIZE_LCD(0)); | 238 | SR(SIZE_LCD(0)); |
@@ -242,7 +244,7 @@ void dispc_save_context(void) | |||
242 | SR(TIMING_H(2)); | 244 | SR(TIMING_H(2)); |
243 | SR(TIMING_V(2)); | 245 | SR(TIMING_V(2)); |
244 | SR(POL_FREQ(2)); | 246 | SR(POL_FREQ(2)); |
245 | SR(DIVISOR(2)); | 247 | SR(DIVISORo(2)); |
246 | SR(CONFIG2); | 248 | SR(CONFIG2); |
247 | } | 249 | } |
248 | 250 | ||
@@ -373,6 +375,9 @@ void dispc_save_context(void) | |||
373 | SR(VID_FIR_COEF_V(1, 7)); | 375 | SR(VID_FIR_COEF_V(1, 7)); |
374 | 376 | ||
375 | SR(VID_PRELOAD(1)); | 377 | SR(VID_PRELOAD(1)); |
378 | |||
379 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | ||
380 | SR(DIVISOR); | ||
376 | } | 381 | } |
377 | 382 | ||
378 | void dispc_restore_context(void) | 383 | void dispc_restore_context(void) |
@@ -389,7 +394,7 @@ void dispc_restore_context(void) | |||
389 | RR(TIMING_H(0)); | 394 | RR(TIMING_H(0)); |
390 | RR(TIMING_V(0)); | 395 | RR(TIMING_V(0)); |
391 | RR(POL_FREQ(0)); | 396 | RR(POL_FREQ(0)); |
392 | RR(DIVISOR(0)); | 397 | RR(DIVISORo(0)); |
393 | RR(GLOBAL_ALPHA); | 398 | RR(GLOBAL_ALPHA); |
394 | RR(SIZE_DIG); | 399 | RR(SIZE_DIG); |
395 | RR(SIZE_LCD(0)); | 400 | RR(SIZE_LCD(0)); |
@@ -400,7 +405,7 @@ void dispc_restore_context(void) | |||
400 | RR(TIMING_H(2)); | 405 | RR(TIMING_H(2)); |
401 | RR(TIMING_V(2)); | 406 | RR(TIMING_V(2)); |
402 | RR(POL_FREQ(2)); | 407 | RR(POL_FREQ(2)); |
403 | RR(DIVISOR(2)); | 408 | RR(DIVISORo(2)); |
404 | RR(CONFIG2); | 409 | RR(CONFIG2); |
405 | } | 410 | } |
406 | 411 | ||
@@ -532,6 +537,9 @@ void dispc_restore_context(void) | |||
532 | 537 | ||
533 | RR(VID_PRELOAD(1)); | 538 | RR(VID_PRELOAD(1)); |
534 | 539 | ||
540 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | ||
541 | RR(DIVISOR); | ||
542 | |||
535 | /* enable last, because LCD & DIGIT enable are here */ | 543 | /* enable last, because LCD & DIGIT enable are here */ |
536 | RR(CONTROL); | 544 | RR(CONTROL); |
537 | if (dss_has_feature(FEAT_MGR_LCD2)) | 545 | if (dss_has_feature(FEAT_MGR_LCD2)) |
@@ -552,9 +560,9 @@ void dispc_restore_context(void) | |||
552 | static inline void enable_clocks(bool enable) | 560 | static inline void enable_clocks(bool enable) |
553 | { | 561 | { |
554 | if (enable) | 562 | if (enable) |
555 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); | 563 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); |
556 | else | 564 | else |
557 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); | 565 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); |
558 | } | 566 | } |
559 | 567 | ||
560 | bool dispc_go_busy(enum omap_channel channel) | 568 | bool dispc_go_busy(enum omap_channel channel) |
@@ -1000,6 +1008,20 @@ void dispc_set_burst_size(enum omap_plane plane, | |||
1000 | enable_clocks(0); | 1008 | enable_clocks(0); |
1001 | } | 1009 | } |
1002 | 1010 | ||
1011 | void dispc_enable_gamma_table(bool enable) | ||
1012 | { | ||
1013 | /* | ||
1014 | * This is partially implemented to support only disabling of | ||
1015 | * the gamma table. | ||
1016 | */ | ||
1017 | if (enable) { | ||
1018 | DSSWARN("Gamma table enabling for TV not yet supported"); | ||
1019 | return; | ||
1020 | } | ||
1021 | |||
1022 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); | ||
1023 | } | ||
1024 | |||
1003 | static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) | 1025 | static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) |
1004 | { | 1026 | { |
1005 | u32 val; | 1027 | u32 val; |
@@ -1129,10 +1151,16 @@ static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) | |||
1129 | u32 val; | 1151 | u32 val; |
1130 | const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0), | 1152 | const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0), |
1131 | DISPC_VID_ACCU0(1) }; | 1153 | DISPC_VID_ACCU0(1) }; |
1154 | u8 hor_start, hor_end, vert_start, vert_end; | ||
1132 | 1155 | ||
1133 | BUG_ON(plane == OMAP_DSS_GFX); | 1156 | BUG_ON(plane == OMAP_DSS_GFX); |
1134 | 1157 | ||
1135 | val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0); | 1158 | dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); |
1159 | dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); | ||
1160 | |||
1161 | val = FLD_VAL(vaccu, vert_start, vert_end) | | ||
1162 | FLD_VAL(haccu, hor_start, hor_end); | ||
1163 | |||
1136 | dispc_write_reg(ac0_reg[plane-1], val); | 1164 | dispc_write_reg(ac0_reg[plane-1], val); |
1137 | } | 1165 | } |
1138 | 1166 | ||
@@ -1141,10 +1169,16 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) | |||
1141 | u32 val; | 1169 | u32 val; |
1142 | const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0), | 1170 | const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0), |
1143 | DISPC_VID_ACCU1(1) }; | 1171 | DISPC_VID_ACCU1(1) }; |
1172 | u8 hor_start, hor_end, vert_start, vert_end; | ||
1144 | 1173 | ||
1145 | BUG_ON(plane == OMAP_DSS_GFX); | 1174 | BUG_ON(plane == OMAP_DSS_GFX); |
1146 | 1175 | ||
1147 | val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0); | 1176 | dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); |
1177 | dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); | ||
1178 | |||
1179 | val = FLD_VAL(vaccu, vert_start, vert_end) | | ||
1180 | FLD_VAL(haccu, hor_start, hor_end); | ||
1181 | |||
1148 | dispc_write_reg(ac1_reg[plane-1], val); | 1182 | dispc_write_reg(ac1_reg[plane-1], val); |
1149 | } | 1183 | } |
1150 | 1184 | ||
@@ -1182,16 +1216,25 @@ static void _dispc_set_scaling(enum omap_plane plane, | |||
1182 | _dispc_set_fir(plane, fir_hinc, fir_vinc); | 1216 | _dispc_set_fir(plane, fir_hinc, fir_vinc); |
1183 | 1217 | ||
1184 | l = dispc_read_reg(dispc_reg_att[plane]); | 1218 | l = dispc_read_reg(dispc_reg_att[plane]); |
1185 | l &= ~((0x0f << 5) | (0x3 << 21)); | ||
1186 | 1219 | ||
1220 | /* RESIZEENABLE and VERTICALTAPS */ | ||
1221 | l &= ~((0x3 << 5) | (0x1 << 21)); | ||
1187 | l |= fir_hinc ? (1 << 5) : 0; | 1222 | l |= fir_hinc ? (1 << 5) : 0; |
1188 | l |= fir_vinc ? (1 << 6) : 0; | 1223 | l |= fir_vinc ? (1 << 6) : 0; |
1224 | l |= five_taps ? (1 << 21) : 0; | ||
1189 | 1225 | ||
1190 | l |= hscaleup ? 0 : (1 << 7); | 1226 | /* VRESIZECONF and HRESIZECONF */ |
1191 | l |= vscaleup ? 0 : (1 << 8); | 1227 | if (dss_has_feature(FEAT_RESIZECONF)) { |
1228 | l &= ~(0x3 << 7); | ||
1229 | l |= hscaleup ? 0 : (1 << 7); | ||
1230 | l |= vscaleup ? 0 : (1 << 8); | ||
1231 | } | ||
1192 | 1232 | ||
1193 | l |= five_taps ? (1 << 21) : 0; | 1233 | /* LINEBUFFERSPLIT */ |
1194 | l |= five_taps ? (1 << 22) : 0; | 1234 | if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) { |
1235 | l &= ~(0x1 << 22); | ||
1236 | l |= five_taps ? (1 << 22) : 0; | ||
1237 | } | ||
1195 | 1238 | ||
1196 | dispc_write_reg(dispc_reg_att[plane], l); | 1239 | dispc_write_reg(dispc_reg_att[plane], l); |
1197 | 1240 | ||
@@ -1215,9 +1258,11 @@ static void _dispc_set_scaling(enum omap_plane plane, | |||
1215 | static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, | 1258 | static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, |
1216 | bool mirroring, enum omap_color_mode color_mode) | 1259 | bool mirroring, enum omap_color_mode color_mode) |
1217 | { | 1260 | { |
1261 | bool row_repeat = false; | ||
1262 | int vidrot = 0; | ||
1263 | |||
1218 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 1264 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
1219 | color_mode == OMAP_DSS_COLOR_UYVY) { | 1265 | color_mode == OMAP_DSS_COLOR_UYVY) { |
1220 | int vidrot = 0; | ||
1221 | 1266 | ||
1222 | if (mirroring) { | 1267 | if (mirroring) { |
1223 | switch (rotation) { | 1268 | switch (rotation) { |
@@ -1251,16 +1296,15 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, | |||
1251 | } | 1296 | } |
1252 | } | 1297 | } |
1253 | 1298 | ||
1254 | REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12); | ||
1255 | |||
1256 | if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270) | 1299 | if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270) |
1257 | REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18); | 1300 | row_repeat = true; |
1258 | else | 1301 | else |
1259 | REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18); | 1302 | row_repeat = false; |
1260 | } else { | ||
1261 | REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12); | ||
1262 | REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18); | ||
1263 | } | 1303 | } |
1304 | |||
1305 | REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12); | ||
1306 | if (dss_has_feature(FEAT_ROWREPEATENABLE)) | ||
1307 | REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18); | ||
1264 | } | 1308 | } |
1265 | 1309 | ||
1266 | static int color_mode_to_bpp(enum omap_color_mode color_mode) | 1310 | static int color_mode_to_bpp(enum omap_color_mode color_mode) |
@@ -2293,7 +2337,7 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, | |||
2293 | BUG_ON(pck_div < 2); | 2337 | BUG_ON(pck_div < 2); |
2294 | 2338 | ||
2295 | enable_clocks(1); | 2339 | enable_clocks(1); |
2296 | dispc_write_reg(DISPC_DIVISOR(channel), | 2340 | dispc_write_reg(DISPC_DIVISORo(channel), |
2297 | FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); | 2341 | FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); |
2298 | enable_clocks(0); | 2342 | enable_clocks(0); |
2299 | } | 2343 | } |
@@ -2302,7 +2346,7 @@ static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, | |||
2302 | int *pck_div) | 2346 | int *pck_div) |
2303 | { | 2347 | { |
2304 | u32 l; | 2348 | u32 l; |
2305 | l = dispc_read_reg(DISPC_DIVISOR(channel)); | 2349 | l = dispc_read_reg(DISPC_DIVISORo(channel)); |
2306 | *lck_div = FLD_GET(l, 23, 16); | 2350 | *lck_div = FLD_GET(l, 23, 16); |
2307 | *pck_div = FLD_GET(l, 7, 0); | 2351 | *pck_div = FLD_GET(l, 7, 0); |
2308 | } | 2352 | } |
@@ -2311,14 +2355,17 @@ unsigned long dispc_fclk_rate(void) | |||
2311 | { | 2355 | { |
2312 | unsigned long r = 0; | 2356 | unsigned long r = 0; |
2313 | 2357 | ||
2314 | if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) | 2358 | switch (dss_get_dispc_clk_source()) { |
2315 | r = dss_clk_get_rate(DSS_CLK_FCK1); | 2359 | case DSS_CLK_SRC_FCK: |
2316 | else | 2360 | r = dss_clk_get_rate(DSS_CLK_FCK); |
2317 | #ifdef CONFIG_OMAP2_DSS_DSI | 2361 | break; |
2318 | r = dsi_get_dsi1_pll_rate(); | 2362 | case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
2319 | #else | 2363 | r = dsi_get_pll_hsdiv_dispc_rate(); |
2320 | BUG(); | 2364 | break; |
2321 | #endif | 2365 | default: |
2366 | BUG(); | ||
2367 | } | ||
2368 | |||
2322 | return r; | 2369 | return r; |
2323 | } | 2370 | } |
2324 | 2371 | ||
@@ -2328,47 +2375,72 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) | |||
2328 | unsigned long r; | 2375 | unsigned long r; |
2329 | u32 l; | 2376 | u32 l; |
2330 | 2377 | ||
2331 | l = dispc_read_reg(DISPC_DIVISOR(channel)); | 2378 | l = dispc_read_reg(DISPC_DIVISORo(channel)); |
2332 | 2379 | ||
2333 | lcd = FLD_GET(l, 23, 16); | 2380 | lcd = FLD_GET(l, 23, 16); |
2334 | 2381 | ||
2335 | r = dispc_fclk_rate(); | 2382 | switch (dss_get_lcd_clk_source(channel)) { |
2383 | case DSS_CLK_SRC_FCK: | ||
2384 | r = dss_clk_get_rate(DSS_CLK_FCK); | ||
2385 | break; | ||
2386 | case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | ||
2387 | r = dsi_get_pll_hsdiv_dispc_rate(); | ||
2388 | break; | ||
2389 | default: | ||
2390 | BUG(); | ||
2391 | } | ||
2336 | 2392 | ||
2337 | return r / lcd; | 2393 | return r / lcd; |
2338 | } | 2394 | } |
2339 | 2395 | ||
2340 | unsigned long dispc_pclk_rate(enum omap_channel channel) | 2396 | unsigned long dispc_pclk_rate(enum omap_channel channel) |
2341 | { | 2397 | { |
2342 | int lcd, pcd; | 2398 | int pcd; |
2343 | unsigned long r; | 2399 | unsigned long r; |
2344 | u32 l; | 2400 | u32 l; |
2345 | 2401 | ||
2346 | l = dispc_read_reg(DISPC_DIVISOR(channel)); | 2402 | l = dispc_read_reg(DISPC_DIVISORo(channel)); |
2347 | 2403 | ||
2348 | lcd = FLD_GET(l, 23, 16); | ||
2349 | pcd = FLD_GET(l, 7, 0); | 2404 | pcd = FLD_GET(l, 7, 0); |
2350 | 2405 | ||
2351 | r = dispc_fclk_rate(); | 2406 | r = dispc_lclk_rate(channel); |
2352 | 2407 | ||
2353 | return r / lcd / pcd; | 2408 | return r / pcd; |
2354 | } | 2409 | } |
2355 | 2410 | ||
2356 | void dispc_dump_clocks(struct seq_file *s) | 2411 | void dispc_dump_clocks(struct seq_file *s) |
2357 | { | 2412 | { |
2358 | int lcd, pcd; | 2413 | int lcd, pcd; |
2414 | u32 l; | ||
2415 | enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); | ||
2416 | enum dss_clk_source lcd_clk_src; | ||
2359 | 2417 | ||
2360 | enable_clocks(1); | 2418 | enable_clocks(1); |
2361 | 2419 | ||
2362 | seq_printf(s, "- DISPC -\n"); | 2420 | seq_printf(s, "- DISPC -\n"); |
2363 | 2421 | ||
2364 | seq_printf(s, "dispc fclk source = %s\n", | 2422 | seq_printf(s, "dispc fclk source = %s (%s)\n", |
2365 | dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? | 2423 | dss_get_generic_clk_source_name(dispc_clk_src), |
2366 | "dss1_alwon_fclk" : "dsi1_pll_fclk"); | 2424 | dss_feat_get_clk_source_name(dispc_clk_src)); |
2367 | 2425 | ||
2368 | seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); | 2426 | seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); |
2369 | 2427 | ||
2428 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) { | ||
2429 | seq_printf(s, "- DISPC-CORE-CLK -\n"); | ||
2430 | l = dispc_read_reg(DISPC_DIVISOR); | ||
2431 | lcd = FLD_GET(l, 23, 16); | ||
2432 | |||
2433 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | ||
2434 | (dispc_fclk_rate()/lcd), lcd); | ||
2435 | } | ||
2370 | seq_printf(s, "- LCD1 -\n"); | 2436 | seq_printf(s, "- LCD1 -\n"); |
2371 | 2437 | ||
2438 | lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD); | ||
2439 | |||
2440 | seq_printf(s, "lcd1_clk source = %s (%s)\n", | ||
2441 | dss_get_generic_clk_source_name(lcd_clk_src), | ||
2442 | dss_feat_get_clk_source_name(lcd_clk_src)); | ||
2443 | |||
2372 | dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); | 2444 | dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); |
2373 | 2445 | ||
2374 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | 2446 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", |
@@ -2378,6 +2450,12 @@ void dispc_dump_clocks(struct seq_file *s) | |||
2378 | if (dss_has_feature(FEAT_MGR_LCD2)) { | 2450 | if (dss_has_feature(FEAT_MGR_LCD2)) { |
2379 | seq_printf(s, "- LCD2 -\n"); | 2451 | seq_printf(s, "- LCD2 -\n"); |
2380 | 2452 | ||
2453 | lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2); | ||
2454 | |||
2455 | seq_printf(s, "lcd2_clk source = %s (%s)\n", | ||
2456 | dss_get_generic_clk_source_name(lcd_clk_src), | ||
2457 | dss_feat_get_clk_source_name(lcd_clk_src)); | ||
2458 | |||
2381 | dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); | 2459 | dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); |
2382 | 2460 | ||
2383 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | 2461 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", |
@@ -2440,7 +2518,7 @@ void dispc_dump_regs(struct seq_file *s) | |||
2440 | { | 2518 | { |
2441 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r)) | 2519 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r)) |
2442 | 2520 | ||
2443 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); | 2521 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); |
2444 | 2522 | ||
2445 | DUMPREG(DISPC_REVISION); | 2523 | DUMPREG(DISPC_REVISION); |
2446 | DUMPREG(DISPC_SYSCONFIG); | 2524 | DUMPREG(DISPC_SYSCONFIG); |
@@ -2459,7 +2537,7 @@ void dispc_dump_regs(struct seq_file *s) | |||
2459 | DUMPREG(DISPC_TIMING_H(0)); | 2537 | DUMPREG(DISPC_TIMING_H(0)); |
2460 | DUMPREG(DISPC_TIMING_V(0)); | 2538 | DUMPREG(DISPC_TIMING_V(0)); |
2461 | DUMPREG(DISPC_POL_FREQ(0)); | 2539 | DUMPREG(DISPC_POL_FREQ(0)); |
2462 | DUMPREG(DISPC_DIVISOR(0)); | 2540 | DUMPREG(DISPC_DIVISORo(0)); |
2463 | DUMPREG(DISPC_GLOBAL_ALPHA); | 2541 | DUMPREG(DISPC_GLOBAL_ALPHA); |
2464 | DUMPREG(DISPC_SIZE_DIG); | 2542 | DUMPREG(DISPC_SIZE_DIG); |
2465 | DUMPREG(DISPC_SIZE_LCD(0)); | 2543 | DUMPREG(DISPC_SIZE_LCD(0)); |
@@ -2471,7 +2549,7 @@ void dispc_dump_regs(struct seq_file *s) | |||
2471 | DUMPREG(DISPC_TIMING_H(2)); | 2549 | DUMPREG(DISPC_TIMING_H(2)); |
2472 | DUMPREG(DISPC_TIMING_V(2)); | 2550 | DUMPREG(DISPC_TIMING_V(2)); |
2473 | DUMPREG(DISPC_POL_FREQ(2)); | 2551 | DUMPREG(DISPC_POL_FREQ(2)); |
2474 | DUMPREG(DISPC_DIVISOR(2)); | 2552 | DUMPREG(DISPC_DIVISORo(2)); |
2475 | DUMPREG(DISPC_SIZE_LCD(2)); | 2553 | DUMPREG(DISPC_SIZE_LCD(2)); |
2476 | } | 2554 | } |
2477 | 2555 | ||
@@ -2597,7 +2675,7 @@ void dispc_dump_regs(struct seq_file *s) | |||
2597 | DUMPREG(DISPC_VID_PRELOAD(0)); | 2675 | DUMPREG(DISPC_VID_PRELOAD(0)); |
2598 | DUMPREG(DISPC_VID_PRELOAD(1)); | 2676 | DUMPREG(DISPC_VID_PRELOAD(1)); |
2599 | 2677 | ||
2600 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); | 2678 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); |
2601 | #undef DUMPREG | 2679 | #undef DUMPREG |
2602 | } | 2680 | } |
2603 | 2681 | ||
@@ -2713,8 +2791,8 @@ int dispc_get_clock_div(enum omap_channel channel, | |||
2713 | 2791 | ||
2714 | fck = dispc_fclk_rate(); | 2792 | fck = dispc_fclk_rate(); |
2715 | 2793 | ||
2716 | cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16); | 2794 | cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16); |
2717 | cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0); | 2795 | cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0); |
2718 | 2796 | ||
2719 | cinfo->lck = fck / cinfo->lck_div; | 2797 | cinfo->lck = fck / cinfo->lck_div; |
2720 | cinfo->pck = cinfo->lck / cinfo->pck_div; | 2798 | cinfo->pck = cinfo->lck / cinfo->pck_div; |
@@ -2791,6 +2869,9 @@ int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | |||
2791 | break; | 2869 | break; |
2792 | } | 2870 | } |
2793 | 2871 | ||
2872 | if (ret) | ||
2873 | goto err; | ||
2874 | |||
2794 | _omap_dispc_set_irqs(); | 2875 | _omap_dispc_set_irqs(); |
2795 | 2876 | ||
2796 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | 2877 | spin_unlock_irqrestore(&dispc.irq_lock, flags); |
@@ -2866,10 +2947,10 @@ static void print_irq_status(u32 status) | |||
2866 | * but we presume they are on because we got an IRQ. However, | 2947 | * but we presume they are on because we got an IRQ. However, |
2867 | * an irq handler may turn the clocks off, so we may not have | 2948 | * an irq handler may turn the clocks off, so we may not have |
2868 | * clock later in the function. */ | 2949 | * clock later in the function. */ |
2869 | void dispc_irq_handler(void) | 2950 | static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) |
2870 | { | 2951 | { |
2871 | int i; | 2952 | int i; |
2872 | u32 irqstatus; | 2953 | u32 irqstatus, irqenable; |
2873 | u32 handledirqs = 0; | 2954 | u32 handledirqs = 0; |
2874 | u32 unhandled_errors; | 2955 | u32 unhandled_errors; |
2875 | struct omap_dispc_isr_data *isr_data; | 2956 | struct omap_dispc_isr_data *isr_data; |
@@ -2878,6 +2959,13 @@ void dispc_irq_handler(void) | |||
2878 | spin_lock(&dispc.irq_lock); | 2959 | spin_lock(&dispc.irq_lock); |
2879 | 2960 | ||
2880 | irqstatus = dispc_read_reg(DISPC_IRQSTATUS); | 2961 | irqstatus = dispc_read_reg(DISPC_IRQSTATUS); |
2962 | irqenable = dispc_read_reg(DISPC_IRQENABLE); | ||
2963 | |||
2964 | /* IRQ is not for us */ | ||
2965 | if (!(irqstatus & irqenable)) { | ||
2966 | spin_unlock(&dispc.irq_lock); | ||
2967 | return IRQ_NONE; | ||
2968 | } | ||
2881 | 2969 | ||
2882 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 2970 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
2883 | spin_lock(&dispc.irq_stats_lock); | 2971 | spin_lock(&dispc.irq_stats_lock); |
@@ -2929,6 +3017,8 @@ void dispc_irq_handler(void) | |||
2929 | } | 3017 | } |
2930 | 3018 | ||
2931 | spin_unlock(&dispc.irq_lock); | 3019 | spin_unlock(&dispc.irq_lock); |
3020 | |||
3021 | return IRQ_HANDLED; | ||
2932 | } | 3022 | } |
2933 | 3023 | ||
2934 | static void dispc_error_worker(struct work_struct *work) | 3024 | static void dispc_error_worker(struct work_struct *work) |
@@ -3253,6 +3343,15 @@ static void _omap_dispc_initial_config(void) | |||
3253 | l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ | 3343 | l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ |
3254 | dispc_write_reg(DISPC_SYSCONFIG, l); | 3344 | dispc_write_reg(DISPC_SYSCONFIG, l); |
3255 | 3345 | ||
3346 | /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ | ||
3347 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) { | ||
3348 | l = dispc_read_reg(DISPC_DIVISOR); | ||
3349 | /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ | ||
3350 | l = FLD_MOD(l, 1, 0, 0); | ||
3351 | l = FLD_MOD(l, 1, 23, 16); | ||
3352 | dispc_write_reg(DISPC_DIVISOR, l); | ||
3353 | } | ||
3354 | |||
3256 | /* FUNCGATED */ | 3355 | /* FUNCGATED */ |
3257 | if (dss_has_feature(FEAT_FUNCGATED)) | 3356 | if (dss_has_feature(FEAT_FUNCGATED)) |
3258 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); | 3357 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); |
@@ -3269,47 +3368,6 @@ static void _omap_dispc_initial_config(void) | |||
3269 | dispc_read_plane_fifo_sizes(); | 3368 | dispc_read_plane_fifo_sizes(); |
3270 | } | 3369 | } |
3271 | 3370 | ||
3272 | int dispc_init(void) | ||
3273 | { | ||
3274 | u32 rev; | ||
3275 | |||
3276 | spin_lock_init(&dispc.irq_lock); | ||
3277 | |||
3278 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
3279 | spin_lock_init(&dispc.irq_stats_lock); | ||
3280 | dispc.irq_stats.last_reset = jiffies; | ||
3281 | #endif | ||
3282 | |||
3283 | INIT_WORK(&dispc.error_work, dispc_error_worker); | ||
3284 | |||
3285 | dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS); | ||
3286 | if (!dispc.base) { | ||
3287 | DSSERR("can't ioremap DISPC\n"); | ||
3288 | return -ENOMEM; | ||
3289 | } | ||
3290 | |||
3291 | enable_clocks(1); | ||
3292 | |||
3293 | _omap_dispc_initial_config(); | ||
3294 | |||
3295 | _omap_dispc_initialize_irq(); | ||
3296 | |||
3297 | dispc_save_context(); | ||
3298 | |||
3299 | rev = dispc_read_reg(DISPC_REVISION); | ||
3300 | printk(KERN_INFO "OMAP DISPC rev %d.%d\n", | ||
3301 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | ||
3302 | |||
3303 | enable_clocks(0); | ||
3304 | |||
3305 | return 0; | ||
3306 | } | ||
3307 | |||
3308 | void dispc_exit(void) | ||
3309 | { | ||
3310 | iounmap(dispc.base); | ||
3311 | } | ||
3312 | |||
3313 | int dispc_enable_plane(enum omap_plane plane, bool enable) | 3371 | int dispc_enable_plane(enum omap_plane plane, bool enable) |
3314 | { | 3372 | { |
3315 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); | 3373 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); |
@@ -3359,3 +3417,94 @@ int dispc_setup_plane(enum omap_plane plane, | |||
3359 | 3417 | ||
3360 | return r; | 3418 | return r; |
3361 | } | 3419 | } |
3420 | |||
3421 | /* DISPC HW IP initialisation */ | ||
3422 | static int omap_dispchw_probe(struct platform_device *pdev) | ||
3423 | { | ||
3424 | u32 rev; | ||
3425 | int r = 0; | ||
3426 | struct resource *dispc_mem; | ||
3427 | |||
3428 | dispc.pdev = pdev; | ||
3429 | |||
3430 | spin_lock_init(&dispc.irq_lock); | ||
3431 | |||
3432 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
3433 | spin_lock_init(&dispc.irq_stats_lock); | ||
3434 | dispc.irq_stats.last_reset = jiffies; | ||
3435 | #endif | ||
3436 | |||
3437 | INIT_WORK(&dispc.error_work, dispc_error_worker); | ||
3438 | |||
3439 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); | ||
3440 | if (!dispc_mem) { | ||
3441 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); | ||
3442 | r = -EINVAL; | ||
3443 | goto fail0; | ||
3444 | } | ||
3445 | dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); | ||
3446 | if (!dispc.base) { | ||
3447 | DSSERR("can't ioremap DISPC\n"); | ||
3448 | r = -ENOMEM; | ||
3449 | goto fail0; | ||
3450 | } | ||
3451 | dispc.irq = platform_get_irq(dispc.pdev, 0); | ||
3452 | if (dispc.irq < 0) { | ||
3453 | DSSERR("platform_get_irq failed\n"); | ||
3454 | r = -ENODEV; | ||
3455 | goto fail1; | ||
3456 | } | ||
3457 | |||
3458 | r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, | ||
3459 | "OMAP DISPC", dispc.pdev); | ||
3460 | if (r < 0) { | ||
3461 | DSSERR("request_irq failed\n"); | ||
3462 | goto fail1; | ||
3463 | } | ||
3464 | |||
3465 | enable_clocks(1); | ||
3466 | |||
3467 | _omap_dispc_initial_config(); | ||
3468 | |||
3469 | _omap_dispc_initialize_irq(); | ||
3470 | |||
3471 | dispc_save_context(); | ||
3472 | |||
3473 | rev = dispc_read_reg(DISPC_REVISION); | ||
3474 | dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", | ||
3475 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | ||
3476 | |||
3477 | enable_clocks(0); | ||
3478 | |||
3479 | return 0; | ||
3480 | fail1: | ||
3481 | iounmap(dispc.base); | ||
3482 | fail0: | ||
3483 | return r; | ||
3484 | } | ||
3485 | |||
3486 | static int omap_dispchw_remove(struct platform_device *pdev) | ||
3487 | { | ||
3488 | free_irq(dispc.irq, dispc.pdev); | ||
3489 | iounmap(dispc.base); | ||
3490 | return 0; | ||
3491 | } | ||
3492 | |||
3493 | static struct platform_driver omap_dispchw_driver = { | ||
3494 | .probe = omap_dispchw_probe, | ||
3495 | .remove = omap_dispchw_remove, | ||
3496 | .driver = { | ||
3497 | .name = "omapdss_dispc", | ||
3498 | .owner = THIS_MODULE, | ||
3499 | }, | ||
3500 | }; | ||
3501 | |||
3502 | int dispc_init_platform_driver(void) | ||
3503 | { | ||
3504 | return platform_driver_register(&omap_dispchw_driver); | ||
3505 | } | ||
3506 | |||
3507 | void dispc_uninit_platform_driver(void) | ||
3508 | { | ||
3509 | return platform_driver_unregister(&omap_dispchw_driver); | ||
3510 | } | ||