aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/s3c-fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/s3c-fb.c')
-rw-r--r--drivers/video/s3c-fb.c160
1 files changed, 85 insertions, 75 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index f3105160bf98..ea7b661e7229 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 */
@@ -361,7 +361,7 @@ static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
361 result = (unsigned int)tmp / 1000; 361 result = (unsigned int)tmp / 1000;
362 362
363 dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", 363 dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
364 pixclk, clk, result, clk / result); 364 pixclk, clk, result, result ? clk / result : clk);
365 365
366 return result; 366 return result;
367} 367}
@@ -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 */
1114static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode) 1059static 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 */
1294static 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.
@@ -1354,8 +1348,14 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
1354 writel(0, regs + VIDOSD_A(win, sfb->variant)); 1348 writel(0, regs + VIDOSD_A(win, sfb->variant));
1355 writel(0, regs + VIDOSD_B(win, sfb->variant)); 1349 writel(0, regs + VIDOSD_B(win, sfb->variant));
1356 writel(0, regs + VIDOSD_C(win, sfb->variant)); 1350 writel(0, regs + VIDOSD_C(win, sfb->variant));
1357 reg = readl(regs + SHADOWCON); 1351
1358 writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON); 1352 if (sfb->variant.has_shadowcon) {
1353 reg = readl(sfb->regs + SHADOWCON);
1354 reg &= ~(SHADOWCON_WINx_PROTECT(win) |
1355 SHADOWCON_CHx_ENABLE(win) |
1356 SHADOWCON_CHx_LOCAL_ENABLE(win));
1357 writel(reg, sfb->regs + SHADOWCON);
1358 }
1359} 1359}
1360 1360
1361static int __devinit s3c_fb_probe(struct platform_device *pdev) 1361static int __devinit s3c_fb_probe(struct platform_device *pdev)
@@ -1481,15 +1481,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
1481 writel(0xffffff, regs + WKEYCON1); 1481 writel(0xffffff, regs + WKEYCON1);
1482 } 1482 }
1483 1483
1484 s3c_fb_set_rgb_timing(sfb);
1485
1484 /* we have the register setup, start allocating framebuffers */ 1486 /* we have the register setup, start allocating framebuffers */
1485 1487
1486 for (win = 0; win < fbdrv->variant.nr_windows; win++) { 1488 for (win = 0; win < fbdrv->variant.nr_windows; win++) {
1487 if (!pd->win[win]) 1489 if (!pd->win[win])
1488 continue; 1490 continue;
1489 1491
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], 1492 ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
1494 &sfb->windows[win]); 1493 &sfb->windows[win]);
1495 if (ret < 0) { 1494 if (ret < 0) {
@@ -1564,6 +1563,8 @@ static int s3c_fb_suspend(struct device *dev)
1564 struct s3c_fb_win *win; 1563 struct s3c_fb_win *win;
1565 int win_no; 1564 int win_no;
1566 1565
1566 pm_runtime_get_sync(sfb->dev);
1567
1567 for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { 1568 for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1568 win = sfb->windows[win_no]; 1569 win = sfb->windows[win_no];
1569 if (!win) 1570 if (!win)
@@ -1577,6 +1578,9 @@ static int s3c_fb_suspend(struct device *dev)
1577 clk_disable(sfb->lcd_clk); 1578 clk_disable(sfb->lcd_clk);
1578 1579
1579 clk_disable(sfb->bus_clk); 1580 clk_disable(sfb->bus_clk);
1581
1582 pm_runtime_put_sync(sfb->dev);
1583
1580 return 0; 1584 return 0;
1581} 1585}
1582 1586
@@ -1589,6 +1593,8 @@ static int s3c_fb_resume(struct device *dev)
1589 int win_no; 1593 int win_no;
1590 u32 reg; 1594 u32 reg;
1591 1595
1596 pm_runtime_get_sync(sfb->dev);
1597
1592 clk_enable(sfb->bus_clk); 1598 clk_enable(sfb->bus_clk);
1593 1599
1594 if (!sfb->variant.has_clksel) 1600 if (!sfb->variant.has_clksel)
@@ -1623,6 +1629,8 @@ static int s3c_fb_resume(struct device *dev)
1623 shadow_protect_win(win, 0); 1629 shadow_protect_win(win, 0);
1624 } 1630 }
1625 1631
1632 s3c_fb_set_rgb_timing(sfb);
1633
1626 /* restore framebuffers */ 1634 /* restore framebuffers */
1627 for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { 1635 for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1628 win = sfb->windows[win_no]; 1636 win = sfb->windows[win_no];
@@ -1633,6 +1641,8 @@ static int s3c_fb_resume(struct device *dev)
1633 s3c_fb_set_par(win->fbinfo); 1641 s3c_fb_set_par(win->fbinfo);
1634 } 1642 }
1635 1643
1644 pm_runtime_put_sync(sfb->dev);
1645
1636 return 0; 1646 return 0;
1637} 1647}
1638#endif 1648#endif