@@ -2043,7 +2043,7 @@ config FB_TMIO_ACCELL
config FB_S3C
tristate "Samsung S3C framebuffer support"
- depends on FB && S3C_DEV_FB
+ depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -66,6 +66,9 @@ struct s3c_fb;
#define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
#define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
+#define FIMD_CLK_TYPE0 0
+#define FIMD_CLK_TYPE1 1
+
/**
* struct s3c_fb_variant - fb variant information
* @is_2443: Set if S3C2443/S3C2416 style hardware.
@@ -98,6 +101,7 @@ struct s3c_fb_variant {
unsigned int has_prtcon:1;
unsigned int has_shadowcon:1;
+ unsigned int clk_type:1;
};
/**
@@ -184,7 +188,8 @@ struct s3c_fb_vsync {
* struct s3c_fb - overall hardware state of the hardware
* @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.
+ * @bus_clk: The clk (hclk) feeding FIMD IP core.
+ * @lcd_clk: The clk (sclk) feeding our interface and possibly pixclk.
* @regs: The mapped hardware registers.
* @variant: Variant information for this hardware.
* @enabled: A bitmask of enabled hardware windows.
@@ -198,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;
@@ -335,7 +341,7 @@ 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 = clk_get_rate(sfb->lcd_clk);
unsigned long long tmp;
unsigned int result;
@@ -518,7 +524,7 @@ static int s3c_fb_set_par(struct fb_info *info)
data = VIDTCON2_LINEVAL(var->yres - 1) |
VIDTCON2_HOZVAL(var->xres - 1);
- writel(data, regs +sfb->variant.vidtcon + 8 );
+ writel(data, regs + sfb->variant.vidtcon + 8);
}
/* write the buffer address */
@@ -1309,8 +1315,10 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
struct s3c_fb_platdata *pd;
struct s3c_fb *sfb;
struct resource *res;
+ struct clk *mout_mpll = NULL;
int win;
int ret = 0;
+ u32 rate = 134000000;
fbdrv = (struct s3c_fb_driverdata *)platform_get_device_id(pdev)->driver_data;
@@ -1337,9 +1345,48 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
sfb->pdata = pd;
sfb->variant = fbdrv->variant;
- sfb->bus_clk = clk_get(dev, "lcd");
- if (IS_ERR(sfb->bus_clk)) {
- dev_err(dev, "failed to get bus clock\n");
+ switch (sfb->variant.clk_type) {
+ case FIMD_CLK_TYPE0:
+ sfb->bus_clk = clk_get(dev, "lcd");
+ if (IS_ERR(sfb->bus_clk)) {
+ dev_err(dev, "failed to get bus clock\n");
+ goto err_sfb;
+ }
+
+ clk_enable(sfb->bus_clk);
+
+ sfb->lcd_clk = sfb->bus_clk;
+ break;
+
+ case FIMD_CLK_TYPE1:
+ sfb->bus_clk = clk_get(&pdev->dev, "fimd");
+ if (IS_ERR(sfb->bus_clk)) {
+ dev_err(&pdev->dev, "failed to get clock for fimd\n");
+ goto err_sfb;
+ }
+ clk_enable(sfb->bus_clk);
+
+ sfb->lcd_clk = clk_get(&pdev->dev, "sclk_fimd");
+ if (IS_ERR(sfb->lcd_clk)) {
+ dev_err(&pdev->dev, "failed to get sclk for fimd\n");
+ goto err_bus_clk;
+ }
+
+ mout_mpll = clk_get(&pdev->dev, "mout_mpll");
+ if (IS_ERR(mout_mpll)) {
+ dev_err(&pdev->dev, "failed to get mout_mpll\n");
+ goto err_lcd_clk;
+ }
+ clk_set_parent(sfb->lcd_clk, mout_mpll);
+ clk_put(mout_mpll);
+
+ clk_set_rate(sfb->lcd_clk, rate);
+ clk_enable(sfb->lcd_clk);
+ dev_dbg(&pdev->dev, "set fimd sclk rate to %d\n", rate);
+ break;
+
+ default:
+ dev_err(dev, "failed to enable clock for FIMD\n");
goto err_sfb;
}
@@ -1351,7 +1398,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
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),
@@ -1359,7 +1406,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));
@@ -1442,9 +1489,15 @@ err_req_region:
release_resource(sfb->regs_res);
kfree(sfb->regs_res);
-err_clk:
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
+err_lcd_clk:
+ clk_disable(sfb->lcd_clk);
+ clk_put(sfb->lcd_clk);
+
+err_bus_clk:
+ if (sfb->variant.clk_type != FIMD_CLK_TYPE0) {
+ clk_disable(sfb->bus_clk);
+ clk_put(sfb->bus_clk);
+ }
err_sfb:
kfree(sfb);
@@ -1473,8 +1526,20 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
iounmap(sfb->regs);
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
+ switch (sfb->variant.clk_type) {
+ case FIMD_CLK_TYPE1:
+ clk_disable(sfb->lcd_clk);
+ clk_put(sfb->lcd_clk);
+ /* fall through to default case */
+ case FIMD_CLK_TYPE0:
+ clk_disable(sfb->bus_clk);
+ clk_put(sfb->bus_clk);
+ break;
+ default:
+ dev_err(sfb->dev, "invalid clock type(%d)\n",
+ sfb->variant.clk_type);
+ break;
+ }
release_resource(sfb->regs_res);
kfree(sfb->regs_res);
@@ -1753,6 +1818,37 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
.win[4] = &s3c_fb_data_64xx_wins[4],
};
+static struct s3c_fb_driverdata s3c_fb_data_s5pv310 = {
+ .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,
+ .clk_type = FIMD_CLK_TYPE1,
+ },
+ .win[0] = &s3c_fb_data_64xx_wins[0],
+ .win[1] = &s3c_fb_data_64xx_wins[1],
+ .win[2] = &s3c_fb_data_64xx_wins[2],
+ .win[3] = &s3c_fb_data_64xx_wins[3],
+ .win[4] = &s3c_fb_data_64xx_wins[4],
+};
+
/* S3C2443/S3C2416 style hardware */
static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
.variant = {
@@ -1800,6 +1896,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
.name = "s5pv210-fb",
.driver_data = (unsigned long)&s3c_fb_data_s5pv210,
}, {
+ .name = "s5pv310-fb",
+ .driver_data = (unsigned long)&s3c_fb_data_s5pv310,
+ }, {
.name = "s3c2443-fb",
.driver_data = (unsigned long)&s3c_fb_data_s3c2443,
},