diff options
Diffstat (limited to 'drivers/video/s3c-fb.c')
-rw-r--r-- | drivers/video/s3c-fb.c | 148 |
1 files changed, 76 insertions, 72 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index f3105160bf9..5f9d8e69029 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
@@ -47,7 +47,7 @@ | |||
47 | #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE | 47 | #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE |
48 | #undef writel | 48 | #undef writel |
49 | #define writel(v, r) do { \ | 49 | #define writel(v, r) do { \ |
50 | printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ | 50 | pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \ |
51 | __raw_writel(v, r); \ | 51 | __raw_writel(v, r); \ |
52 | } while (0) | 52 | } while (0) |
53 | #endif /* FB_S3C_DEBUG_REGWRITE */ | 53 | #endif /* FB_S3C_DEBUG_REGWRITE */ |
@@ -495,7 +495,6 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
495 | u32 alpha = 0; | 495 | u32 alpha = 0; |
496 | u32 data; | 496 | u32 data; |
497 | u32 pagewidth; | 497 | u32 pagewidth; |
498 | int clkdiv; | ||
499 | 498 | ||
500 | dev_dbg(sfb->dev, "setting framebuffer parameters\n"); | 499 | dev_dbg(sfb->dev, "setting framebuffer parameters\n"); |
501 | 500 | ||
@@ -532,48 +531,9 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
532 | /* disable the window whilst we update it */ | 531 | /* disable the window whilst we update it */ |
533 | writel(0, regs + WINCON(win_no)); | 532 | writel(0, regs + WINCON(win_no)); |
534 | 533 | ||
535 | /* use platform specified window as the basis for the lcd timings */ | 534 | if (!sfb->output_on) |
536 | |||
537 | if (win_no == sfb->pdata->default_win) { | ||
538 | clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); | ||
539 | |||
540 | data = sfb->pdata->vidcon0; | ||
541 | data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); | ||
542 | |||
543 | if (clkdiv > 1) | ||
544 | data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; | ||
545 | else | ||
546 | data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ | ||
547 | |||
548 | /* write the timing data to the panel */ | ||
549 | |||
550 | if (sfb->variant.is_2443) | ||
551 | data |= (1 << 5); | ||
552 | |||
553 | writel(data, regs + VIDCON0); | ||
554 | |||
555 | s3c_fb_enable(sfb, 1); | 535 | s3c_fb_enable(sfb, 1); |
556 | 536 | ||
557 | data = VIDTCON0_VBPD(var->upper_margin - 1) | | ||
558 | VIDTCON0_VFPD(var->lower_margin - 1) | | ||
559 | VIDTCON0_VSPW(var->vsync_len - 1); | ||
560 | |||
561 | writel(data, regs + sfb->variant.vidtcon); | ||
562 | |||
563 | data = VIDTCON1_HBPD(var->left_margin - 1) | | ||
564 | VIDTCON1_HFPD(var->right_margin - 1) | | ||
565 | VIDTCON1_HSPW(var->hsync_len - 1); | ||
566 | |||
567 | /* VIDTCON1 */ | ||
568 | writel(data, regs + sfb->variant.vidtcon + 4); | ||
569 | |||
570 | data = VIDTCON2_LINEVAL(var->yres - 1) | | ||
571 | VIDTCON2_HOZVAL(var->xres - 1) | | ||
572 | VIDTCON2_LINEVAL_E(var->yres - 1) | | ||
573 | VIDTCON2_HOZVAL_E(var->xres - 1); | ||
574 | writel(data, regs + sfb->variant.vidtcon + 8); | ||
575 | } | ||
576 | |||
577 | /* write the buffer address */ | 537 | /* write the buffer address */ |
578 | 538 | ||
579 | /* start and end registers stride is 8 */ | 539 | /* start and end registers stride is 8 */ |
@@ -839,6 +799,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
839 | struct s3c_fb *sfb = win->parent; | 799 | struct s3c_fb *sfb = win->parent; |
840 | unsigned int index = win->index; | 800 | unsigned int index = win->index; |
841 | u32 wincon; | 801 | u32 wincon; |
802 | u32 output_on = sfb->output_on; | ||
842 | 803 | ||
843 | dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); | 804 | dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); |
844 | 805 | ||
@@ -877,34 +838,18 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
877 | 838 | ||
878 | shadow_protect_win(win, 1); | 839 | shadow_protect_win(win, 1); |
879 | writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); | 840 | writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); |
880 | shadow_protect_win(win, 0); | ||
881 | 841 | ||
882 | /* Check the enabled state to see if we need to be running the | 842 | /* Check the enabled state to see if we need to be running the |
883 | * main LCD interface, as if there are no active windows then | 843 | * main LCD interface, as if there are no active windows then |
884 | * it is highly likely that we also do not need to output | 844 | * it is highly likely that we also do not need to output |
885 | * anything. | 845 | * anything. |
886 | */ | 846 | */ |
887 | 847 | s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); | |
888 | /* We could do something like the following code, but the current | 848 | shadow_protect_win(win, 0); |
889 | * system of using framebuffer events means that we cannot make | ||
890 | * the distinction between just window 0 being inactive and all | ||
891 | * the windows being down. | ||
892 | * | ||
893 | * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); | ||
894 | */ | ||
895 | |||
896 | /* we're stuck with this until we can do something about overriding | ||
897 | * the power control using the blanking event for a single fb. | ||
898 | */ | ||
899 | if (index == sfb->pdata->default_win) { | ||
900 | shadow_protect_win(win, 1); | ||
901 | s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); | ||
902 | shadow_protect_win(win, 0); | ||
903 | } | ||
904 | 849 | ||
905 | pm_runtime_put_sync(sfb->dev); | 850 | pm_runtime_put_sync(sfb->dev); |
906 | 851 | ||
907 | return 0; | 852 | return output_on == sfb->output_on; |
908 | } | 853 | } |
909 | 854 | ||
910 | /** | 855 | /** |
@@ -1111,7 +1056,7 @@ static struct fb_ops s3c_fb_ops = { | |||
1111 | * | 1056 | * |
1112 | * Calculate the pixel clock when none has been given through platform data. | 1057 | * Calculate the pixel clock when none has been given through platform data. |
1113 | */ | 1058 | */ |
1114 | static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode) | 1059 | static void s3c_fb_missing_pixclock(struct fb_videomode *mode) |
1115 | { | 1060 | { |
1116 | u64 pixclk = 1000000000000ULL; | 1061 | u64 pixclk = 1000000000000ULL; |
1117 | u32 div; | 1062 | u32 div; |
@@ -1144,11 +1089,11 @@ static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb, | |||
1144 | 1089 | ||
1145 | dev_dbg(sfb->dev, "allocating memory for display\n"); | 1090 | dev_dbg(sfb->dev, "allocating memory for display\n"); |
1146 | 1091 | ||
1147 | real_size = windata->win_mode.xres * windata->win_mode.yres; | 1092 | real_size = windata->xres * windata->yres; |
1148 | virt_size = windata->virtual_x * windata->virtual_y; | 1093 | virt_size = windata->virtual_x * windata->virtual_y; |
1149 | 1094 | ||
1150 | dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", | 1095 | dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", |
1151 | real_size, windata->win_mode.xres, windata->win_mode.yres, | 1096 | real_size, windata->xres, windata->yres, |
1152 | virt_size, windata->virtual_x, windata->virtual_y); | 1097 | virt_size, windata->virtual_x, windata->virtual_y); |
1153 | 1098 | ||
1154 | size = (real_size > virt_size) ? real_size : virt_size; | 1099 | size = (real_size > virt_size) ? real_size : virt_size; |
@@ -1230,7 +1175,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
1230 | struct s3c_fb_win **res) | 1175 | struct s3c_fb_win **res) |
1231 | { | 1176 | { |
1232 | struct fb_var_screeninfo *var; | 1177 | struct fb_var_screeninfo *var; |
1233 | struct fb_videomode *initmode; | 1178 | struct fb_videomode initmode; |
1234 | struct s3c_fb_pd_win *windata; | 1179 | struct s3c_fb_pd_win *windata; |
1235 | struct s3c_fb_win *win; | 1180 | struct s3c_fb_win *win; |
1236 | struct fb_info *fbinfo; | 1181 | struct fb_info *fbinfo; |
@@ -1251,11 +1196,11 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
1251 | } | 1196 | } |
1252 | 1197 | ||
1253 | windata = sfb->pdata->win[win_no]; | 1198 | windata = sfb->pdata->win[win_no]; |
1254 | initmode = &windata->win_mode; | 1199 | initmode = *sfb->pdata->vtiming; |
1255 | 1200 | ||
1256 | WARN_ON(windata->max_bpp == 0); | 1201 | WARN_ON(windata->max_bpp == 0); |
1257 | WARN_ON(windata->win_mode.xres == 0); | 1202 | WARN_ON(windata->xres == 0); |
1258 | WARN_ON(windata->win_mode.yres == 0); | 1203 | WARN_ON(windata->yres == 0); |
1259 | 1204 | ||
1260 | win = fbinfo->par; | 1205 | win = fbinfo->par; |
1261 | *res = win; | 1206 | *res = win; |
@@ -1294,7 +1239,9 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
1294 | } | 1239 | } |
1295 | 1240 | ||
1296 | /* setup the initial video mode from the window */ | 1241 | /* setup the initial video mode from the window */ |
1297 | fb_videomode_to_var(&fbinfo->var, initmode); | 1242 | initmode.xres = windata->xres; |
1243 | initmode.yres = windata->yres; | ||
1244 | fb_videomode_to_var(&fbinfo->var, &initmode); | ||
1298 | 1245 | ||
1299 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | 1246 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; |
1300 | fbinfo->fix.accel = FB_ACCEL_NONE; | 1247 | fbinfo->fix.accel = FB_ACCEL_NONE; |
@@ -1339,6 +1286,53 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
1339 | } | 1286 | } |
1340 | 1287 | ||
1341 | /** | 1288 | /** |
1289 | * s3c_fb_set_rgb_timing() - set video timing for rgb interface. | ||
1290 | * @sfb: The base resources for the hardware. | ||
1291 | * | ||
1292 | * Set horizontal and vertical lcd rgb interface timing. | ||
1293 | */ | ||
1294 | static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb) | ||
1295 | { | ||
1296 | struct fb_videomode *vmode = sfb->pdata->vtiming; | ||
1297 | void __iomem *regs = sfb->regs; | ||
1298 | int clkdiv; | ||
1299 | u32 data; | ||
1300 | |||
1301 | if (!vmode->pixclock) | ||
1302 | s3c_fb_missing_pixclock(vmode); | ||
1303 | |||
1304 | clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock); | ||
1305 | |||
1306 | data = sfb->pdata->vidcon0; | ||
1307 | data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); | ||
1308 | |||
1309 | if (clkdiv > 1) | ||
1310 | data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; | ||
1311 | else | ||
1312 | data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ | ||
1313 | |||
1314 | if (sfb->variant.is_2443) | ||
1315 | data |= (1 << 5); | ||
1316 | writel(data, regs + VIDCON0); | ||
1317 | |||
1318 | data = VIDTCON0_VBPD(vmode->upper_margin - 1) | | ||
1319 | VIDTCON0_VFPD(vmode->lower_margin - 1) | | ||
1320 | VIDTCON0_VSPW(vmode->vsync_len - 1); | ||
1321 | writel(data, regs + sfb->variant.vidtcon); | ||
1322 | |||
1323 | data = VIDTCON1_HBPD(vmode->left_margin - 1) | | ||
1324 | VIDTCON1_HFPD(vmode->right_margin - 1) | | ||
1325 | VIDTCON1_HSPW(vmode->hsync_len - 1); | ||
1326 | writel(data, regs + sfb->variant.vidtcon + 4); | ||
1327 | |||
1328 | data = VIDTCON2_LINEVAL(vmode->yres - 1) | | ||
1329 | VIDTCON2_HOZVAL(vmode->xres - 1) | | ||
1330 | VIDTCON2_LINEVAL_E(vmode->yres - 1) | | ||
1331 | VIDTCON2_HOZVAL_E(vmode->xres - 1); | ||
1332 | writel(data, regs + sfb->variant.vidtcon + 8); | ||
1333 | } | ||
1334 | |||
1335 | /** | ||
1342 | * s3c_fb_clear_win() - clear hardware window registers. | 1336 | * s3c_fb_clear_win() - clear hardware window registers. |
1343 | * @sfb: The base resources for the hardware. | 1337 | * @sfb: The base resources for the hardware. |
1344 | * @win: The window to process. | 1338 | * @win: The window to process. |
@@ -1481,15 +1475,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1481 | writel(0xffffff, regs + WKEYCON1); | 1475 | writel(0xffffff, regs + WKEYCON1); |
1482 | } | 1476 | } |
1483 | 1477 | ||
1478 | s3c_fb_set_rgb_timing(sfb); | ||
1479 | |||
1484 | /* we have the register setup, start allocating framebuffers */ | 1480 | /* we have the register setup, start allocating framebuffers */ |
1485 | 1481 | ||
1486 | for (win = 0; win < fbdrv->variant.nr_windows; win++) { | 1482 | for (win = 0; win < fbdrv->variant.nr_windows; win++) { |
1487 | if (!pd->win[win]) | 1483 | if (!pd->win[win]) |
1488 | continue; | 1484 | continue; |
1489 | 1485 | ||
1490 | if (!pd->win[win]->win_mode.pixclock) | ||
1491 | s3c_fb_missing_pixclock(&pd->win[win]->win_mode); | ||
1492 | |||
1493 | ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], | 1486 | ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], |
1494 | &sfb->windows[win]); | 1487 | &sfb->windows[win]); |
1495 | if (ret < 0) { | 1488 | if (ret < 0) { |
@@ -1564,6 +1557,8 @@ static int s3c_fb_suspend(struct device *dev) | |||
1564 | struct s3c_fb_win *win; | 1557 | struct s3c_fb_win *win; |
1565 | int win_no; | 1558 | int win_no; |
1566 | 1559 | ||
1560 | pm_runtime_get_sync(sfb->dev); | ||
1561 | |||
1567 | for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { | 1562 | for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { |
1568 | win = sfb->windows[win_no]; | 1563 | win = sfb->windows[win_no]; |
1569 | if (!win) | 1564 | if (!win) |
@@ -1577,6 +1572,9 @@ static int s3c_fb_suspend(struct device *dev) | |||
1577 | clk_disable(sfb->lcd_clk); | 1572 | clk_disable(sfb->lcd_clk); |
1578 | 1573 | ||
1579 | clk_disable(sfb->bus_clk); | 1574 | clk_disable(sfb->bus_clk); |
1575 | |||
1576 | pm_runtime_put_sync(sfb->dev); | ||
1577 | |||
1580 | return 0; | 1578 | return 0; |
1581 | } | 1579 | } |
1582 | 1580 | ||
@@ -1589,6 +1587,8 @@ static int s3c_fb_resume(struct device *dev) | |||
1589 | int win_no; | 1587 | int win_no; |
1590 | u32 reg; | 1588 | u32 reg; |
1591 | 1589 | ||
1590 | pm_runtime_get_sync(sfb->dev); | ||
1591 | |||
1592 | clk_enable(sfb->bus_clk); | 1592 | clk_enable(sfb->bus_clk); |
1593 | 1593 | ||
1594 | if (!sfb->variant.has_clksel) | 1594 | if (!sfb->variant.has_clksel) |
@@ -1623,6 +1623,8 @@ static int s3c_fb_resume(struct device *dev) | |||
1623 | shadow_protect_win(win, 0); | 1623 | shadow_protect_win(win, 0); |
1624 | } | 1624 | } |
1625 | 1625 | ||
1626 | s3c_fb_set_rgb_timing(sfb); | ||
1627 | |||
1626 | /* restore framebuffers */ | 1628 | /* restore framebuffers */ |
1627 | for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { | 1629 | for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { |
1628 | win = sfb->windows[win_no]; | 1630 | win = sfb->windows[win_no]; |
@@ -1633,6 +1635,8 @@ static int s3c_fb_resume(struct device *dev) | |||
1633 | s3c_fb_set_par(win->fbinfo); | 1635 | s3c_fb_set_par(win->fbinfo); |
1634 | } | 1636 | } |
1635 | 1637 | ||
1638 | pm_runtime_put_sync(sfb->dev); | ||
1639 | |||
1636 | return 0; | 1640 | return 0; |
1637 | } | 1641 | } |
1638 | #endif | 1642 | #endif |