[PATCH 3/4] s3c-fb: Add support S5PV310 FIMD
Inki Dae
inki.dae at samsung.com
Fri Nov 12 04:54:29 EST 2010
Hello, all.
This is my opinion and patch.
Jonghun's patch is adding clock type(FIMD_CLK_TYPE1 or FIMD_CLK_TYPE2) and
also
clk_type variable to s3c_fb_variant to select which clock would be used.
I think we could meet that simply if source clock and parent clock
names are set to platform data in machine file.
I added my comments to Jonghun's patch and attached modified patch below.
Thank you.
diff --git a/arch/arm/plat-samsung/include/plat/fb.h
b/arch/arm/plat-samsung/include/plat/fb.h
index ed70fc5..411380e 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -47,6 +47,10 @@ struct s3c_fb_pd_win {
* @vidcon1: The base vidcon1 values to control the panel data output.
* @win: The setup data for each hardware window, or NULL for unused.
* @display_mode: The LCD output display mode.
+ * @sclk_name: source clock name and sclk_name valiable should be set
+ * at machine specific file.
+ * @pclk_name: parent clock name and pclk_name valiable should be set
+ * at machine specific file.
*
* The platform data supplies the video driver with all the information
* it requires to work with the display(s) attached to the machine. It
@@ -63,6 +67,9 @@ struct s3c_fb_platdata {
u32 vidcon0;
u32 vidcon1;
+
+ const char *sclk_name;
+ const char *pclk_name;
};
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index f9aca9d..96a746c 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -27,6 +27,7 @@
#include <mach/map.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
+#include <plat/clock.h>
/* This driver will export a number of framebuffer interfaces depending
* on the configuration passed in via the platform data. Each fb instance
@@ -183,7 +184,7 @@ 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.
+ * @lcd_clk: The clk (hclk or 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.
@@ -196,7 +197,7 @@ struct s3c_fb_vsync {
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;
@@ -334,7 +335,11 @@ 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);
+ /**
+ * if it fails to get clock rate from lcd_clk
+ * then would get it from parent clock of lcd_clk.
+ */
+ unsigned long clk = clk_get_rate(sfb->lcd_clk);
unsigned long long tmp;
unsigned int result;
@@ -1314,13 +1319,22 @@ 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");
+ /* if sclk_name is NULL then it would use bus clock as default. */
+ if (!pd->sclk_name)
+ sfb->lcd_clk = clk_get(dev, "lcd");
+ else
+ sfb->lcd_clk = clk_get(dev, pd->sclk_name);
+
+ if (IS_ERR(sfb->lcd_clk)) {
+ dev_err(dev, "failed to get lcd clock\n");
+ clk_put(sfb->lcd_clk);
goto err_sfb;
}
- clk_enable(sfb->bus_clk);
+ if (pd->pclk_name)
+ sfb->lcd_clk->parent = clk_get(dev, pd->pclk_name);
+
+ clk_enable(sfb->lcd_clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1414,8 +1428,8 @@ err_req_region:
kfree(sfb->regs_res);
err_clk:
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
+ clk_disable(sfb->lcd_clk);
+ clk_put(sfb->lcd_clk);
err_sfb:
kfree(sfb);
@@ -1442,8 +1456,8 @@ static int __devexit s3c_fb_remove(struct
platform_device *pdev)
iounmap(sfb->regs);
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
+ clk_disable(sfb->lcd_clk);
+ clk_put(sfb->lcd_clk);
release_resource(sfb->regs_res);
kfree(sfb->regs_res);
@@ -1469,7 +1483,8 @@ static int s3c_fb_suspend(struct platform_device
*pdev, pm_message_t state)
s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
}
- clk_disable(sfb->bus_clk);
+ clk_disable(sfb->lcd_clk);
+
return 0;
}
@@ -1480,7 +1495,7 @@ static int s3c_fb_resume(struct platform_device *pdev)
struct s3c_fb_win *win;
int win_no;
- clk_enable(sfb->bus_clk);
+ clk_enable(sfb->lcd_clk);
/* setup registers */
writel(pd->vidcon1, sfb->regs + VIDCON1);
@@ -1656,6 +1671,36 @@ 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,
+ },
+ .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 = {
@@ -1703,6 +1748,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,
},
> -----Original Message-----
> From: linux-fbdev-owner at vger.kernel.org [mailto:linux-fbdev-
> owner at vger.kernel.org] On Behalf Of Kukjin Kim
> Sent: Friday, November 12, 2010 2:26 PM
> To: 'Sangbeom Kim'; linux-arm-kernel at lists.infradead.org; linux-samsung-
> soc at vger.kernel.org; linux-fbdev at vger.kernel.org
> Cc: ben-linux at fluff.org; akpm at linux-foundation.org; 'Jonghun Han'
> Subject: RE: [PATCH 3/4] s3c-fb: Add support S5PV310 FIMD
>
> Sangbeom Kim wrote:
> >
> > From: Jonghun Han <jonghun.han at samsung.com>
> >
> > This patch adds s3c_fb_driverdata for S5PV310 FIMD0. The clk_type is
> added
> > to distinguish clock type in structure s3c_fb_variant and lcd_clk is
> added
> > in structure s3c_fb to calculate divider for lcd panel.
> > FIMD can handles two clocks. The one is for FIMD IP and the other is for
> > LCD pixel clock. Before S5PV310 LCD pixel clock can be same with FIMD IP
> > clock. From S5PV310 LCD pixel clock is separated from FIMD IP clock.
> >
> > Signed-off-by: Jonghun Han <jonghun.han at samsung.com>
> > Reviewed-by: Kukjin Kim <kgene.kim at samsung.com>
> > Signed-off-by: Sangbeom Kim <sbkim73 at samsung.com>
> > Cc: Ben Dooks <ben-linux at fluff.org>
>
> Hi Ben,
>
> How do you think about this?
> If you're ok, I'd like to send this to upstream via mmotm.
>
> > ---
> > NOTE: This patch is only for FIMD0.
> > FIMD1 will be implemented later.
> > drivers/video/Kconfig | 2 +-
> > drivers/video/s3c-fb.c | 128
> ++++++++++++++++++++++++++++++++++++++++++----
> > --
> > 2 files changed, 114 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > index 8b31fdf..3e2e02a 100644
> > --- a/drivers/video/Kconfig
> > +++ b/drivers/video/Kconfig
> > @@ -1946,7 +1946,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
> > diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> > index f9aca9d..bc182ea 100644
> > --- a/drivers/video/s3c-fb.c
> > +++ b/drivers/video/s3c-fb.c
> > @@ -65,6 +65,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
> > +
this macro is unnecessary.
> > /**
> > * struct s3c_fb_variant - fb variant information
> > * @is_2443: Set if S3C2443/S3C2416 style hardware.
> > @@ -97,6 +100,7 @@ struct s3c_fb_variant {
> >
> > unsigned int has_prtcon:1;
> > unsigned int has_shadowcon:1;
> > + unsigned int clk_type:1;
> > };
> >
> > /**
> > @@ -183,7 +187,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.
> > @@ -197,6 +202,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;
> >
bus_clk and lcd_clk could be integrated as lcd_clk.
and Ben, lcd_clk is better then bus_clk because hclk or sclk could be used
according to lcd panel on machine for stable use.
> > @@ -334,7 +340,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;
> >
> > @@ -517,7 +523,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 */
> > @@ -1286,8 +1292,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;
> >
> > @@ -1314,19 +1322,56 @@ 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;
> > }
> >
This code above is unnecessary. if sclk_name of platform data is null then
it could get clock "lcd" otherwise sclk_name.
in case of "lcd", fimd would use bus clock as parent clock but
for sclk_name, sclk_fimd clock.
and
if (pd->pclk_name)
sfb->lcd_clk->parent = clk_get(dev, pd->pclk_name);
by adding the code above,
we could get appropriate clock rate through clk_get_rate(sfb->lcd_clk) call
at s3c_fb_calc_pixclk function.
(clk_get_rate function gets clock rate of parent if lcd_clk->rate is 0)
> > - clk_enable(sfb->bus_clk);
> > -
> > 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),
> > @@ -1334,7 +1379,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));
> > @@ -1413,9 +1458,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);
> > @@ -1442,8 +1493,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;
> > + }
this code above is unnecessary anymore.
> >
> > release_resource(sfb->regs_res);
> > kfree(sfb->regs_res);
> > @@ -1470,6 +1533,7 @@ static int s3c_fb_suspend(struct platform_device
> *pdev,
> > pm_message_t state)
> > }
> >
> > clk_disable(sfb->bus_clk);
> > +
> > return 0;
> > }
> >
> > @@ -1656,6 +1720,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,
clk_type is unnecessary anymore.
> > + },
> > + .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 = {
> > @@ -1703,6 +1798,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,
> > },
> > --
>
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim at samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the linux-arm-kernel
mailing list