diff options
-rw-r--r-- | drivers/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/s3c-fb.c | 88 |
2 files changed, 85 insertions, 5 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 549b960667c8..963b8b767b83 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -2027,7 +2027,7 @@ config FB_TMIO_ACCELL | |||
2027 | 2027 | ||
2028 | config FB_S3C | 2028 | config FB_S3C |
2029 | tristate "Samsung S3C framebuffer support" | 2029 | tristate "Samsung S3C framebuffer support" |
2030 | depends on FB && S3C_DEV_FB | 2030 | depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0) |
2031 | select FB_CFB_FILLRECT | 2031 | select FB_CFB_FILLRECT |
2032 | select FB_CFB_COPYAREA | 2032 | select FB_CFB_COPYAREA |
2033 | select FB_CFB_IMAGEBLIT | 2033 | select FB_CFB_IMAGEBLIT |
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index fd9f20df912f..170029e7cba8 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
@@ -81,6 +81,7 @@ struct s3c_fb; | |||
81 | * @palette: Address of palette memory, or 0 if none. | 81 | * @palette: Address of palette memory, or 0 if none. |
82 | * @has_prtcon: Set if has PRTCON register. | 82 | * @has_prtcon: Set if has PRTCON register. |
83 | * @has_shadowcon: Set if has SHADOWCON register. | 83 | * @has_shadowcon: Set if has SHADOWCON register. |
84 | * @has_clksel: Set if VIDCON0 register has CLKSEL bit. | ||
84 | */ | 85 | */ |
85 | struct s3c_fb_variant { | 86 | struct s3c_fb_variant { |
86 | unsigned int is_2443:1; | 87 | unsigned int is_2443:1; |
@@ -98,6 +99,7 @@ struct s3c_fb_variant { | |||
98 | 99 | ||
99 | unsigned int has_prtcon:1; | 100 | unsigned int has_prtcon:1; |
100 | unsigned int has_shadowcon:1; | 101 | unsigned int has_shadowcon:1; |
102 | unsigned int has_clksel:1; | ||
101 | }; | 103 | }; |
102 | 104 | ||
103 | /** | 105 | /** |
@@ -186,6 +188,7 @@ struct s3c_fb_vsync { | |||
186 | * @dev: The device that we bound to, for printing, etc. | 188 | * @dev: The device that we bound to, for printing, etc. |
187 | * @regs_res: The resource we claimed for the IO registers. | 189 | * @regs_res: The resource we claimed for the IO registers. |
188 | * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. | 190 | * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. |
191 | * @lcd_clk: The clk (sclk) feeding pixclk. | ||
189 | * @regs: The mapped hardware registers. | 192 | * @regs: The mapped hardware registers. |
190 | * @variant: Variant information for this hardware. | 193 | * @variant: Variant information for this hardware. |
191 | * @enabled: A bitmask of enabled hardware windows. | 194 | * @enabled: A bitmask of enabled hardware windows. |
@@ -200,6 +203,7 @@ struct s3c_fb { | |||
200 | struct device *dev; | 203 | struct device *dev; |
201 | struct resource *regs_res; | 204 | struct resource *regs_res; |
202 | struct clk *bus_clk; | 205 | struct clk *bus_clk; |
206 | struct clk *lcd_clk; | ||
203 | void __iomem *regs; | 207 | void __iomem *regs; |
204 | struct s3c_fb_variant variant; | 208 | struct s3c_fb_variant variant; |
205 | 209 | ||
@@ -336,10 +340,15 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, | |||
336 | */ | 340 | */ |
337 | static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) | 341 | static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) |
338 | { | 342 | { |
339 | unsigned long clk = clk_get_rate(sfb->bus_clk); | 343 | unsigned long clk; |
340 | unsigned long long tmp; | 344 | unsigned long long tmp; |
341 | unsigned int result; | 345 | unsigned int result; |
342 | 346 | ||
347 | if (sfb->variant.has_clksel) | ||
348 | clk = clk_get_rate(sfb->bus_clk); | ||
349 | else | ||
350 | clk = clk_get_rate(sfb->lcd_clk); | ||
351 | |||
343 | tmp = (unsigned long long)clk; | 352 | tmp = (unsigned long long)clk; |
344 | tmp *= pixclk; | 353 | tmp *= pixclk; |
345 | 354 | ||
@@ -1354,13 +1363,24 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1354 | 1363 | ||
1355 | clk_enable(sfb->bus_clk); | 1364 | clk_enable(sfb->bus_clk); |
1356 | 1365 | ||
1366 | if (!sfb->variant.has_clksel) { | ||
1367 | sfb->lcd_clk = clk_get(dev, "sclk_fimd"); | ||
1368 | if (IS_ERR(sfb->lcd_clk)) { | ||
1369 | dev_err(dev, "failed to get lcd clock\n"); | ||
1370 | ret = PTR_ERR(sfb->lcd_clk); | ||
1371 | goto err_bus_clk; | ||
1372 | } | ||
1373 | |||
1374 | clk_enable(sfb->lcd_clk); | ||
1375 | } | ||
1376 | |||
1357 | pm_runtime_enable(sfb->dev); | 1377 | pm_runtime_enable(sfb->dev); |
1358 | 1378 | ||
1359 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1379 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1360 | if (!res) { | 1380 | if (!res) { |
1361 | dev_err(dev, "failed to find registers\n"); | 1381 | dev_err(dev, "failed to find registers\n"); |
1362 | ret = -ENOENT; | 1382 | ret = -ENOENT; |
1363 | goto err_clk; | 1383 | goto err_lcd_clk; |
1364 | } | 1384 | } |
1365 | 1385 | ||
1366 | sfb->regs_res = request_mem_region(res->start, resource_size(res), | 1386 | sfb->regs_res = request_mem_region(res->start, resource_size(res), |
@@ -1368,7 +1388,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1368 | if (!sfb->regs_res) { | 1388 | if (!sfb->regs_res) { |
1369 | dev_err(dev, "failed to claim register region\n"); | 1389 | dev_err(dev, "failed to claim register region\n"); |
1370 | ret = -ENOENT; | 1390 | ret = -ENOENT; |
1371 | goto err_clk; | 1391 | goto err_lcd_clk; |
1372 | } | 1392 | } |
1373 | 1393 | ||
1374 | sfb->regs = ioremap(res->start, resource_size(res)); | 1394 | sfb->regs = ioremap(res->start, resource_size(res)); |
@@ -1450,7 +1470,13 @@ err_ioremap: | |||
1450 | err_req_region: | 1470 | err_req_region: |
1451 | release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); | 1471 | release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); |
1452 | 1472 | ||
1453 | err_clk: | 1473 | err_lcd_clk: |
1474 | if (!sfb->variant.has_clksel) { | ||
1475 | clk_disable(sfb->lcd_clk); | ||
1476 | clk_put(sfb->lcd_clk); | ||
1477 | } | ||
1478 | |||
1479 | err_bus_clk: | ||
1454 | clk_disable(sfb->bus_clk); | 1480 | clk_disable(sfb->bus_clk); |
1455 | clk_put(sfb->bus_clk); | 1481 | clk_put(sfb->bus_clk); |
1456 | 1482 | ||
@@ -1481,6 +1507,11 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
1481 | 1507 | ||
1482 | iounmap(sfb->regs); | 1508 | iounmap(sfb->regs); |
1483 | 1509 | ||
1510 | if (!sfb->variant.has_clksel) { | ||
1511 | clk_disable(sfb->lcd_clk); | ||
1512 | clk_put(sfb->lcd_clk); | ||
1513 | } | ||
1514 | |||
1484 | clk_disable(sfb->bus_clk); | 1515 | clk_disable(sfb->bus_clk); |
1485 | clk_put(sfb->bus_clk); | 1516 | clk_put(sfb->bus_clk); |
1486 | 1517 | ||
@@ -1510,6 +1541,9 @@ static int s3c_fb_suspend(struct device *dev) | |||
1510 | s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); | 1541 | s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); |
1511 | } | 1542 | } |
1512 | 1543 | ||
1544 | if (!sfb->variant.has_clksel) | ||
1545 | clk_disable(sfb->lcd_clk); | ||
1546 | |||
1513 | clk_disable(sfb->bus_clk); | 1547 | clk_disable(sfb->bus_clk); |
1514 | return 0; | 1548 | return 0; |
1515 | } | 1549 | } |
@@ -1524,6 +1558,9 @@ static int s3c_fb_resume(struct device *dev) | |||
1524 | 1558 | ||
1525 | clk_enable(sfb->bus_clk); | 1559 | clk_enable(sfb->bus_clk); |
1526 | 1560 | ||
1561 | if (!sfb->variant.has_clksel) | ||
1562 | clk_enable(sfb->lcd_clk); | ||
1563 | |||
1527 | /* setup gpio and output polarity controls */ | 1564 | /* setup gpio and output polarity controls */ |
1528 | pd->setup_gpio(); | 1565 | pd->setup_gpio(); |
1529 | writel(pd->vidcon1, sfb->regs + VIDCON1); | 1566 | writel(pd->vidcon1, sfb->regs + VIDCON1); |
@@ -1569,6 +1606,9 @@ static int s3c_fb_runtime_suspend(struct device *dev) | |||
1569 | s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); | 1606 | s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); |
1570 | } | 1607 | } |
1571 | 1608 | ||
1609 | if (!sfb->variant.has_clksel) | ||
1610 | clk_disable(sfb->lcd_clk); | ||
1611 | |||
1572 | clk_disable(sfb->bus_clk); | 1612 | clk_disable(sfb->bus_clk); |
1573 | return 0; | 1613 | return 0; |
1574 | } | 1614 | } |
@@ -1583,6 +1623,9 @@ static int s3c_fb_runtime_resume(struct device *dev) | |||
1583 | 1623 | ||
1584 | clk_enable(sfb->bus_clk); | 1624 | clk_enable(sfb->bus_clk); |
1585 | 1625 | ||
1626 | if (!sfb->variant.has_clksel) | ||
1627 | clk_enable(sfb->lcd_clk); | ||
1628 | |||
1586 | /* setup gpio and output polarity controls */ | 1629 | /* setup gpio and output polarity controls */ |
1587 | pd->setup_gpio(); | 1630 | pd->setup_gpio(); |
1588 | writel(pd->vidcon1, sfb->regs + VIDCON1); | 1631 | writel(pd->vidcon1, sfb->regs + VIDCON1); |
@@ -1755,6 +1798,7 @@ static struct s3c_fb_driverdata s3c_fb_data_64xx = { | |||
1755 | }, | 1798 | }, |
1756 | 1799 | ||
1757 | .has_prtcon = 1, | 1800 | .has_prtcon = 1, |
1801 | .has_clksel = 1, | ||
1758 | }, | 1802 | }, |
1759 | .win[0] = &s3c_fb_data_64xx_wins[0], | 1803 | .win[0] = &s3c_fb_data_64xx_wins[0], |
1760 | .win[1] = &s3c_fb_data_64xx_wins[1], | 1804 | .win[1] = &s3c_fb_data_64xx_wins[1], |
@@ -1785,6 +1829,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = { | |||
1785 | }, | 1829 | }, |
1786 | 1830 | ||
1787 | .has_prtcon = 1, | 1831 | .has_prtcon = 1, |
1832 | .has_clksel = 1, | ||
1788 | }, | 1833 | }, |
1789 | .win[0] = &s3c_fb_data_s5p_wins[0], | 1834 | .win[0] = &s3c_fb_data_s5p_wins[0], |
1790 | .win[1] = &s3c_fb_data_s5p_wins[1], | 1835 | .win[1] = &s3c_fb_data_s5p_wins[1], |
@@ -1815,6 +1860,37 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = { | |||
1815 | }, | 1860 | }, |
1816 | 1861 | ||
1817 | .has_shadowcon = 1, | 1862 | .has_shadowcon = 1, |
1863 | .has_clksel = 1, | ||
1864 | }, | ||
1865 | .win[0] = &s3c_fb_data_s5p_wins[0], | ||
1866 | .win[1] = &s3c_fb_data_s5p_wins[1], | ||
1867 | .win[2] = &s3c_fb_data_s5p_wins[2], | ||
1868 | .win[3] = &s3c_fb_data_s5p_wins[3], | ||
1869 | .win[4] = &s3c_fb_data_s5p_wins[4], | ||
1870 | }; | ||
1871 | |||
1872 | static struct s3c_fb_driverdata s3c_fb_data_exynos4 = { | ||
1873 | .variant = { | ||
1874 | .nr_windows = 5, | ||
1875 | .vidtcon = VIDTCON0, | ||
1876 | .wincon = WINCON(0), | ||
1877 | .winmap = WINxMAP(0), | ||
1878 | .keycon = WKEYCON, | ||
1879 | .osd = VIDOSD_BASE, | ||
1880 | .osd_stride = 16, | ||
1881 | .buf_start = VIDW_BUF_START(0), | ||
1882 | .buf_size = VIDW_BUF_SIZE(0), | ||
1883 | .buf_end = VIDW_BUF_END(0), | ||
1884 | |||
1885 | .palette = { | ||
1886 | [0] = 0x2400, | ||
1887 | [1] = 0x2800, | ||
1888 | [2] = 0x2c00, | ||
1889 | [3] = 0x3000, | ||
1890 | [4] = 0x3400, | ||
1891 | }, | ||
1892 | |||
1893 | .has_shadowcon = 1, | ||
1818 | }, | 1894 | }, |
1819 | .win[0] = &s3c_fb_data_s5p_wins[0], | 1895 | .win[0] = &s3c_fb_data_s5p_wins[0], |
1820 | .win[1] = &s3c_fb_data_s5p_wins[1], | 1896 | .win[1] = &s3c_fb_data_s5p_wins[1], |
@@ -1843,6 +1919,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = { | |||
1843 | [0] = 0x400, | 1919 | [0] = 0x400, |
1844 | [1] = 0x800, | 1920 | [1] = 0x800, |
1845 | }, | 1921 | }, |
1922 | .has_clksel = 1, | ||
1846 | }, | 1923 | }, |
1847 | .win[0] = &(struct s3c_fb_win_variant) { | 1924 | .win[0] = &(struct s3c_fb_win_variant) { |
1848 | .palette_sz = 256, | 1925 | .palette_sz = 256, |
@@ -1870,6 +1947,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = { | |||
1870 | .name = "s5pv210-fb", | 1947 | .name = "s5pv210-fb", |
1871 | .driver_data = (unsigned long)&s3c_fb_data_s5pv210, | 1948 | .driver_data = (unsigned long)&s3c_fb_data_s5pv210, |
1872 | }, { | 1949 | }, { |
1950 | .name = "exynos4-fb", | ||
1951 | .driver_data = (unsigned long)&s3c_fb_data_exynos4, | ||
1952 | }, { | ||
1873 | .name = "s3c2443-fb", | 1953 | .name = "s3c2443-fb", |
1874 | .driver_data = (unsigned long)&s3c_fb_data_s3c2443, | 1954 | .driver_data = (unsigned long)&s3c_fb_data_s3c2443, |
1875 | }, | 1955 | }, |