|
@@ -81,6 +81,7 @@ struct s3c_fb;
|
|
|
* @palette: Address of palette memory, or 0 if none.
|
|
|
* @has_prtcon: Set if has PRTCON register.
|
|
|
* @has_shadowcon: Set if has SHADOWCON register.
|
|
|
+ * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
|
|
|
*/
|
|
|
struct s3c_fb_variant {
|
|
|
unsigned int is_2443:1;
|
|
@@ -98,6 +99,7 @@ struct s3c_fb_variant {
|
|
|
|
|
|
unsigned int has_prtcon:1;
|
|
|
unsigned int has_shadowcon:1;
|
|
|
+ unsigned int has_clksel:1;
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -186,6 +188,7 @@ struct s3c_fb_vsync {
|
|
|
* @dev: The device that we bound to, for printing, etc.
|
|
|
* @regs_res: The resource we claimed for the IO registers.
|
|
|
* @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
|
|
|
+ * @lcd_clk: The clk (sclk) feeding pixclk.
|
|
|
* @regs: The mapped hardware registers.
|
|
|
* @variant: Variant information for this hardware.
|
|
|
* @enabled: A bitmask of enabled hardware windows.
|
|
@@ -200,6 +203,7 @@ struct s3c_fb {
|
|
|
struct device *dev;
|
|
|
struct resource *regs_res;
|
|
|
struct clk *bus_clk;
|
|
|
+ struct clk *lcd_clk;
|
|
|
void __iomem *regs;
|
|
|
struct s3c_fb_variant variant;
|
|
|
|
|
@@ -336,10 +340,15 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
|
|
|
*/
|
|
|
static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
|
|
|
{
|
|
|
- unsigned long clk = clk_get_rate(sfb->bus_clk);
|
|
|
+ unsigned long clk;
|
|
|
unsigned long long tmp;
|
|
|
unsigned int result;
|
|
|
|
|
|
+ if (sfb->variant.has_clksel)
|
|
|
+ clk = clk_get_rate(sfb->bus_clk);
|
|
|
+ else
|
|
|
+ clk = clk_get_rate(sfb->lcd_clk);
|
|
|
+
|
|
|
tmp = (unsigned long long)clk;
|
|
|
tmp *= pixclk;
|
|
|
|
|
@@ -1354,13 +1363,24 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
|
|
|
|
|
|
clk_enable(sfb->bus_clk);
|
|
|
|
|
|
+ if (!sfb->variant.has_clksel) {
|
|
|
+ sfb->lcd_clk = clk_get(dev, "sclk_fimd");
|
|
|
+ if (IS_ERR(sfb->lcd_clk)) {
|
|
|
+ dev_err(dev, "failed to get lcd clock\n");
|
|
|
+ ret = PTR_ERR(sfb->lcd_clk);
|
|
|
+ goto err_bus_clk;
|
|
|
+ }
|
|
|
+
|
|
|
+ clk_enable(sfb->lcd_clk);
|
|
|
+ }
|
|
|
+
|
|
|
pm_runtime_enable(sfb->dev);
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
if (!res) {
|
|
|
dev_err(dev, "failed to find registers\n");
|
|
|
ret = -ENOENT;
|
|
|
- goto err_clk;
|
|
|
+ goto err_lcd_clk;
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
if (!sfb->regs_res) {
|
|
|
dev_err(dev, "failed to claim register region\n");
|
|
|
ret = -ENOENT;
|
|
|
- goto err_clk;
|
|
|
+ goto err_lcd_clk;
|
|
|
}
|
|
|
|
|
|
sfb->regs = ioremap(res->start, resource_size(res));
|
|
@@ -1450,7 +1470,13 @@ err_ioremap:
|
|
|
err_req_region:
|
|
|
release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
|
|
|
|
|
|
-err_clk:
|
|
|
+err_lcd_clk:
|
|
|
+ if (!sfb->variant.has_clksel) {
|
|
|
+ clk_disable(sfb->lcd_clk);
|
|
|
+ clk_put(sfb->lcd_clk);
|
|
|
+ }
|
|
|
+
|
|
|
+err_bus_clk:
|
|
|
clk_disable(sfb->bus_clk);
|
|
|
clk_put(sfb->bus_clk);
|
|
|
|
|
@@ -1481,6 +1507,11 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
|
|
|
|
|
|
iounmap(sfb->regs);
|
|
|
|
|
|
+ if (!sfb->variant.has_clksel) {
|
|
|
+ clk_disable(sfb->lcd_clk);
|
|
|
+ clk_put(sfb->lcd_clk);
|
|
|
+ }
|
|
|
+
|
|
|
clk_disable(sfb->bus_clk);
|
|
|
clk_put(sfb->bus_clk);
|
|
|
|
|
@@ -1510,6 +1541,9 @@ static int s3c_fb_suspend(struct device *dev)
|
|
|
s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
|
|
|
}
|
|
|
|
|
|
+ if (!sfb->variant.has_clksel)
|
|
|
+ clk_disable(sfb->lcd_clk);
|
|
|
+
|
|
|
clk_disable(sfb->bus_clk);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1524,6 +1558,9 @@ static int s3c_fb_resume(struct device *dev)
|
|
|
|
|
|
clk_enable(sfb->bus_clk);
|
|
|
|
|
|
+ if (!sfb->variant.has_clksel)
|
|
|
+ clk_enable(sfb->lcd_clk);
|
|
|
+
|
|
|
/* setup gpio and output polarity controls */
|
|
|
pd->setup_gpio();
|
|
|
writel(pd->vidcon1, sfb->regs + VIDCON1);
|
|
@@ -1569,6 +1606,9 @@ static int s3c_fb_runtime_suspend(struct device *dev)
|
|
|
s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
|
|
|
}
|
|
|
|
|
|
+ if (!sfb->variant.has_clksel)
|
|
|
+ clk_disable(sfb->lcd_clk);
|
|
|
+
|
|
|
clk_disable(sfb->bus_clk);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1583,6 +1623,9 @@ static int s3c_fb_runtime_resume(struct device *dev)
|
|
|
|
|
|
clk_enable(sfb->bus_clk);
|
|
|
|
|
|
+ if (!sfb->variant.has_clksel)
|
|
|
+ clk_enable(sfb->lcd_clk);
|
|
|
+
|
|
|
/* setup gpio and output polarity controls */
|
|
|
pd->setup_gpio();
|
|
|
writel(pd->vidcon1, sfb->regs + VIDCON1);
|
|
@@ -1755,6 +1798,7 @@ static struct s3c_fb_driverdata s3c_fb_data_64xx = {
|
|
|
},
|
|
|
|
|
|
.has_prtcon = 1,
|
|
|
+ .has_clksel = 1,
|
|
|
},
|
|
|
.win[0] = &s3c_fb_data_64xx_wins[0],
|
|
|
.win[1] = &s3c_fb_data_64xx_wins[1],
|
|
@@ -1785,6 +1829,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
|
|
|
},
|
|
|
|
|
|
.has_prtcon = 1,
|
|
|
+ .has_clksel = 1,
|
|
|
},
|
|
|
.win[0] = &s3c_fb_data_s5p_wins[0],
|
|
|
.win[1] = &s3c_fb_data_s5p_wins[1],
|
|
@@ -1794,6 +1839,37 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
|
|
|
};
|
|
|
|
|
|
static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
|
|
|
+ .variant = {
|
|
|
+ .nr_windows = 5,
|
|
|
+ .vidtcon = VIDTCON0,
|
|
|
+ .wincon = WINCON(0),
|
|
|
+ .winmap = WINxMAP(0),
|
|
|
+ .keycon = WKEYCON,
|
|
|
+ .osd = VIDOSD_BASE,
|
|
|
+ .osd_stride = 16,
|
|
|
+ .buf_start = VIDW_BUF_START(0),
|
|
|
+ .buf_size = VIDW_BUF_SIZE(0),
|
|
|
+ .buf_end = VIDW_BUF_END(0),
|
|
|
+
|
|
|
+ .palette = {
|
|
|
+ [0] = 0x2400,
|
|
|
+ [1] = 0x2800,
|
|
|
+ [2] = 0x2c00,
|
|
|
+ [3] = 0x3000,
|
|
|
+ [4] = 0x3400,
|
|
|
+ },
|
|
|
+
|
|
|
+ .has_shadowcon = 1,
|
|
|
+ .has_clksel = 1,
|
|
|
+ },
|
|
|
+ .win[0] = &s3c_fb_data_s5p_wins[0],
|
|
|
+ .win[1] = &s3c_fb_data_s5p_wins[1],
|
|
|
+ .win[2] = &s3c_fb_data_s5p_wins[2],
|
|
|
+ .win[3] = &s3c_fb_data_s5p_wins[3],
|
|
|
+ .win[4] = &s3c_fb_data_s5p_wins[4],
|
|
|
+};
|
|
|
+
|
|
|
+static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
|
|
|
.variant = {
|
|
|
.nr_windows = 5,
|
|
|
.vidtcon = VIDTCON0,
|
|
@@ -1843,6 +1919,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
|
|
|
[0] = 0x400,
|
|
|
[1] = 0x800,
|
|
|
},
|
|
|
+ .has_clksel = 1,
|
|
|
},
|
|
|
.win[0] = &(struct s3c_fb_win_variant) {
|
|
|
.palette_sz = 256,
|
|
@@ -1869,6 +1946,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
|
|
|
}, {
|
|
|
.name = "s5pv210-fb",
|
|
|
.driver_data = (unsigned long)&s3c_fb_data_s5pv210,
|
|
|
+ }, {
|
|
|
+ .name = "exynos4-fb",
|
|
|
+ .driver_data = (unsigned long)&s3c_fb_data_exynos4,
|
|
|
}, {
|
|
|
.name = "s3c2443-fb",
|
|
|
.driver_data = (unsigned long)&s3c_fb_data_s3c2443,
|