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) +{ + 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; + } + + return fixed16; +} + +void g2d_cmd_stretch(struct g2d_dev *d, struct g2d_frame *src, + struct g2d_frame *dst) { - 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); + 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 -- 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