Hi Ajay, Thank you for your patch, unfortunately I have no documentation for Exynos5 so please answer my question below. Also I have added other comments. > From: Ajay Kumar [mailto:ajaykumar.rs@xxxxxxxxxxx] > Sent: 14 March 2012 10:34 > > Modify the G2D driver(which initially supported only FIMG2D v3 style H/W) > to support FIMG2D v4 style hardware present on Exynos4x12 and Exynos52x0 > SOC. > > -- Set the SRC and DST type to 'memory' instead of using reset > values. > -- FIMG2D v4 H/W uses different logic for stretching(scaling). > -- Use CACHECTL_REG only with FIMG2D v3. > -- No Source clock for G2D on EXYNOS5. > Only gating clock to be used. > > Signed-off-by: Ajay Kumar <ajaykumar.rs@xxxxxxxxxxx> > --- > drivers/media/video/s5p-g2d/g2d-hw.c | 54 > ++++++++++++++++++++++++++-- > drivers/media/video/s5p-g2d/g2d-regs.h | 4 ++ > drivers/media/video/s5p-g2d/g2d.c | 61 +++++++++++++++++++++++--- > ------ > drivers/media/video/s5p-g2d/g2d.h | 10 +++++- > 4 files changed, 107 insertions(+), 22 deletions(-) > > diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c > b/drivers/media/video/s5p-g2d/g2d-hw.c > index 5b86cbe..7631756 100644 > --- a/drivers/media/video/s5p-g2d/g2d-hw.c > +++ b/drivers/media/video/s5p-g2d/g2d-hw.c > @@ -28,6 +28,8 @@ void g2d_set_src_size(struct g2d_dev *d, struct > g2d_frame *f) > { > u32 n; > > + w(0, SRC_SELECT_REG); > + > w(f->stride & 0xFFFF, SRC_STRIDE_REG); > > n = f->o_height & 0xFFF; > @@ -52,6 +54,8 @@ void g2d_set_dst_size(struct g2d_dev *d, struct > g2d_frame *f) > { > u32 n; > > + w(0, DST_SELECT_REG); > + > w(f->stride & 0xFFFF, DST_STRIDE_REG); > > n = f->o_height & 0xFFF; > @@ -82,10 +86,51 @@ void g2d_set_flip(struct g2d_dev *d, u32 r) > w(r, SRC_MSK_DIRECT_REG); > } > > -u32 g2d_cmd_stretch(u32 e) > +/** > + * scale_factor_to_fixed16 - convert scale factor to fixed pint 16 > + * @n: numerator > + * @d: denominator > + */ > +static unsigned long scale_factor_to_fixed16(int n, int d) I would name it g2d_calc_scale_factor keep the naming policy. > +{ > + int i; > + u32 fixed16; > + > + fixed16 = (n/d) << 16; > + n %= d; > + > + for (i = 0; i < 16; i++) { > + if (!n) > + break; > + n <<= 1; > + if (n/d) > + fixed16 |= 1 << (15-i); > + n %= d; > + } Did you mean (n << 16) / d ? If Exynos5 has the same limits to width and height as 4212 and 4210 (where max is 8000) then there is no need to do such magic. 13+16=29 which is enough bits to fit in u32. > + > + return fixed16; > +} > + > +void g2d_cmd_stretch(struct g2d_dev *d, struct g2d_frame *src, > + struct g2d_frame *dst) Maybe g2d_set_stretch? It has nothing to do with setting command now. > { > - e &= 1; > - return e << 4; > + int src_w, src_h, dst_w, dst_h; > + u32 wcfg, hcfg; > + > + w(DEFAULT_SCALE_MODE, SRC_SCALE_CTRL_REG); > + > + src_w = src->c_width; > + src_h = src->c_height; > + > + dst_w = dst->c_width; > + dst_h = dst->c_height; > + > + /* inversed scaling factor: src is numerator */ > + wcfg = scale_factor_to_fixed16(src_w, dst_w); > + hcfg = scale_factor_to_fixed16(src_h, dst_h); > + > + w(wcfg, SRC_XSCALE_REG); > + w(hcfg, SRC_YSCALE_REG); > } > > void g2d_set_cmd(struct g2d_dev *d, u32 c) > @@ -96,7 +141,8 @@ void g2d_set_cmd(struct g2d_dev *d, u32 c) > void g2d_start(struct g2d_dev *d) > { > /* Clear cache */ > - w(0x7, CACHECTL_REG); > + if (d->device_type == TYPE_G2D_3X) > + w(0x7, CACHECTL_REG); > /* Enable interrupt */ > w(1, INTEN_REG); > /* Start G2D engine */ > diff --git a/drivers/media/video/s5p-g2d/g2d-regs.h > b/drivers/media/video/s5p-g2d/g2d-regs.h > index 02e1cf5..619eb9c 100644 > --- a/drivers/media/video/s5p-g2d/g2d-regs.h > +++ b/drivers/media/video/s5p-g2d/g2d-regs.h > @@ -35,6 +35,9 @@ > #define SRC_COLOR_MODE_REG 0x030C /* Src Image Color Mode reg */ > #define SRC_LEFT_TOP_REG 0x0310 /* Src Left Top Coordinate reg > */ > #define SRC_RIGHT_BOTTOM_REG 0x0314 /* Src Right Bottom Coordinate > reg */ > +#define SRC_SCALE_CTRL_REG 0x0328 /* Src Scaling type select */ > +#define SRC_XSCALE_REG 0x032c /* Src X Scaling ratio */ > +#define SRC_YSCALE_REG 0x0330 /* Src Y Scaling ratio */ > > /* Parameter Setting Registers (Dest) */ > #define DST_SELECT_REG 0x0400 /* Dest Image Selection reg */ > @@ -112,4 +115,5 @@ > > #define DEFAULT_WIDTH 100 > #define DEFAULT_HEIGHT 100 > +#define DEFAULT_SCALE_MODE (2 << 0) > > diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p- > g2d/g2d.c > index 789de74..4bdc227 100644 > --- a/drivers/media/video/s5p-g2d/g2d.c > +++ b/drivers/media/video/s5p-g2d/g2d.c > @@ -582,8 +582,13 @@ static void device_run(void *prv) > g2d_set_flip(dev, ctx->flip); > > if (ctx->in.c_width != ctx->out.c_width || > - ctx->in.c_height != ctx->out.c_height) > - cmd |= g2d_cmd_stretch(1); > + ctx->in.c_height != ctx->out.c_height) { > + if (dev->device_type == TYPE_G2D_3X) > + cmd |= (1 << 4); A magic constant shall not pass. You should define something like CMD_STRETCH_MASK ~(1 << 4) and CMD_STRETCH (1 << 4) and use them to set and clear the command byte. > + else > + g2d_cmd_stretch(dev, &ctx->in, &ctx->out); > + } > + > g2d_set_cmd(dev, cmd); > g2d_start(dev); > > @@ -705,17 +710,20 @@ static int g2d_probe(struct platform_device *pdev) > goto rel_res_regs; > } > > - dev->clk = clk_get(&pdev->dev, "sclk_fimg2d"); > - if (IS_ERR_OR_NULL(dev->clk)) { > - dev_err(&pdev->dev, "failed to get g2d clock\n"); > - ret = -ENXIO; > - goto unmap_regs; > - } > - > - ret = clk_prepare(dev->clk); > - if (ret) { > - dev_err(&pdev->dev, "failed to prepare g2d clock\n"); > - goto put_clk; > + dev->device_type = platform_get_device_id(pdev)->driver_data; > + if (dev->device_type != TYPE_G2D_4_1X) { > + dev->clk = clk_get(&pdev->dev, "sclk_fimg2d"); > + if (IS_ERR_OR_NULL(dev->clk)) { > + dev_err(&pdev->dev, "failed to get g2d clock\n"); > + ret = -ENXIO; > + goto unmap_regs; > + } > + > + ret = clk_prepare(dev->clk); > + if (ret) { > + dev_err(&pdev->dev, "failed to prepare g2d clock\n"); > + goto put_clk; > + } > } > > dev->gate = clk_get(&pdev->dev, "fimg2d"); > @@ -800,9 +808,11 @@ unprep_clk_gate: > put_clk_gate: > clk_put(dev->gate); > unprep_clk: > - clk_unprepare(dev->clk); > + if (dev->device_type != TYPE_G2D_4_1X) > + clk_unprepare(dev->clk); > put_clk: > - clk_put(dev->clk); > + if (dev->device_type != TYPE_G2D_4_1X) > + clk_put(dev->clk); > unmap_regs: > iounmap(dev->regs); > rel_res_regs: > @@ -824,17 +834,34 @@ static int g2d_remove(struct platform_device *pdev) > free_irq(dev->irq, dev); > clk_unprepare(dev->gate); > clk_put(dev->gate); > - clk_unprepare(dev->clk); > - clk_put(dev->clk); > + if (dev->device_type != TYPE_G2D_4_1X) { > + clk_unprepare(dev->clk); > + clk_put(dev->clk); > + } > iounmap(dev->regs); > release_resource(dev->res_regs); > kfree(dev); > return 0; > } > > +static struct platform_device_id g2d_driver_ids[] = { > + { > + .name = "s5p-g2d", > + .driver_data = TYPE_G2D_3X, > + }, { > + .name = "s5p-g2d4x", > + .driver_data = TYPE_G2D_4X, > + }, { > + .name = "s5p-g2d41x", > + .driver_data = TYPE_G2D_4_1X, > + }, { }, > +}; > +MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); > + > static struct platform_driver g2d_pdrv = { > .probe = g2d_probe, > .remove = g2d_remove, > + .id_table = g2d_driver_ids, > .driver = { > .name = G2D_NAME, > .owner = THIS_MODULE, > diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p- > g2d/g2d.h > index 1b82065..4ee9341 100644 > --- a/drivers/media/video/s5p-g2d/g2d.h > +++ b/drivers/media/video/s5p-g2d/g2d.h > @@ -15,6 +15,12 @@ > > #define G2D_NAME "s5p-g2d" > > +enum g2d_type { > + TYPE_G2D_3X, > + TYPE_G2D_4X, > + TYPE_G2D_4_1X, > +}; > + > struct g2d_dev { > struct v4l2_device v4l2_dev; > struct v4l2_m2m_dev *m2m_dev; > @@ -30,6 +36,7 @@ struct g2d_dev { > struct g2d_ctx *curr; > int irq; > wait_queue_head_t irq_queue; > + enum g2d_type device_type; > }; > > struct g2d_frame { > @@ -81,7 +88,8 @@ void g2d_start(struct g2d_dev *d); > void g2d_clear_int(struct g2d_dev *d); > void g2d_set_rop4(struct g2d_dev *d, u32 r); > void g2d_set_flip(struct g2d_dev *d, u32 r); > -u32 g2d_cmd_stretch(u32 e); > +void g2d_cmd_stretch(struct g2d_dev *d, > + struct g2d_frame *src, struct g2d_frame *dst); > void g2d_set_cmd(struct g2d_dev *d, u32 c); > > > -- > 1.7.0.4 Best wishes, -- Kamil Debski Linux Platform Group Samsung Poland R&D Center -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html