Thanks for giving me the comments.I have incorporated all the comments and sending the complete patch for review ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >From Rajesh K krajesh<krajesh@xxxxxx> OMAP FBDEV: VRFB framebuffer rotation support for OMAP SDP This patch provides rotation support OMAP SDP. You will have to append video=omapfb:rotate=0 parameters to your u-boot arguments to get this working. This supports 0,90,180 and 270 degree rotations. Signed-off-by: Rajesh K < krajesh@xxxxxx > Signed-off-by: Iqbal shareef < iqbal@xxxxxx > --- arch/arm/plat-omap/include/mach/omapfb.h | 4 +- drivers/video/omap/dispc.c | 193 +++++++++++++++++++++++++++++- drivers/video/omap/dispc.h | 29 +++++ drivers/video/omap/omapfb_main.c | 37 ++++--- 4 files changed, 243 insertions(+), 20 deletions(-) diff --git a/arch/arm/plat-omap/include/mach/omapfb.h b/arch/arm/plat-omap/include/mach/omapfb.h index a4a84f3..338a11d 100644 --- a/arch/arm/plat-omap/include/mach/omapfb.h +++ b/arch/arm/plat-omap/include/mach/omapfb.h @@ -277,7 +277,7 @@ typedef int (*omapfb_notifier_callback_t)(struct notifier_block *, struct omapfb_mem_region { dma_addr_t paddr; - void *vaddr; + void __iomem *vaddr; unsigned long size; u8 type; /* OMAPFB_PLANE_MEM_* */ unsigned alloc:1; /* allocated by the driver */ @@ -306,7 +306,7 @@ struct lcd_ctrl { int screen_width, int pos_x, int pos_y, int width, int height, int color_mode); - int (*set_rotate) (int angle); + int (*set_rotate) (int plane, int angle); int (*setup_mem) (int plane, size_t size, int mem_type, unsigned long *paddr); int (*mmap) (struct fb_info *info, diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index ce4c4de..94c96dd 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c @@ -149,12 +149,25 @@ #define RESMAP_MASK(_page_nr) \ (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1))) +unsigned long save_paddr; +unsigned long save_vaddr; + struct resmap { unsigned long start; unsigned page_cnt; unsigned long *map; }; +struct { + unsigned long paddr[4]; + void __iomem *vaddr[4]; + u32 xoffset; + u32 yoffset; + unsigned long size_val; + unsigned long control_val; +} vrfb; + +static void omap2_disp_set_vrfb(u32 width, u32 height, u32 bytes_per_pixel); static struct { void __iomem *base; @@ -459,6 +472,170 @@ static int omap_dispc_setup_plane(int plane, int channel_out, return r; } +/* +* pages_per_side : Will provide pages per side +* @ img_side : img_side +* @ page_exp : page_exponential +* Return Value: Returns pages per side value. +*/ + +static inline u32 pages_per_side(u32 img_side, u32 page_exp) +{ + return (img_side + (1<<page_exp) - 1) >> page_exp; +} + +/* +* omap2_disp_set_vrfb : Will configure VRFB Support.Its a rotation engine +* which will supports rotations of 0,90,180,270 degrees. +* @width: Width of the image +* @height : height of the image +* @bytes_per_pixel : color depth of the image +* return value : None +*/ + +static void omap2_disp_set_vrfb(u32 width, u32 height, u32 bytes_per_pixel) +{ + int page_width_exp, page_height_exp, pixel_size_exp; + int context = 0; + vrfb.size_val = 0; + vrfb.control_val = 0; + pixel_size_exp = bytes_per_pixel >> 1; + page_width_exp = PAGE_WIDTH_EXP; + page_height_exp = PAGE_HEIGHT_EXP; + + width = ((1<<page_width_exp) * + (pages_per_side(width * bytes_per_pixel, + page_width_exp))) >> pixel_size_exp; + height = (1<<page_height_exp) * + (pages_per_side(height, page_height_exp)); + + __raw_writel(save_paddr, SMS_ROT0_PHYSICAL_BA(context)); + __raw_writel(0, SMS_ROT0_SIZE(context)); + + vrfb.size_val |= (width << SMS_IMAGEWIDTH_OFFSET)| + (height << SMS_IMAGEHEIGHT_OFFSET); + __raw_writel(vrfb.size_val, SMS_ROT0_SIZE(context)); + __raw_writel(0, SMS_ROT_CONTROL(context)); + vrfb.control_val |= pixel_size_exp << SMS_PS_OFFSET + | (page_width_exp - pixel_size_exp) << SMS_PW_OFFSET + | page_height_exp << SMS_PH_OFFSET; + __raw_writel(vrfb.control_val, SMS_ROT_CONTROL(context)); +} + +/* +* omap_dispc_set_rotate : configuring rotation registers based on angle. +* @ plane: graphics or video pipe line +* @ angle: Rotation angle. +* Return Value: Returns 0 on success + Returns -1 if it fails. +*/ + +int omap_dispc_set_rotate(int plane, int angle) +{ + int width, height; + u32 addr_base; + u32 bpp; + int r = 0; + + width = dispc.fbdev->fb_info[0]->var.xres; + height = dispc.fbdev->fb_info[0]->var.yres; + bpp = dispc.fbdev->fb_info[0]->var.bits_per_pixel / 8; + + if (plane == OMAPFB_PLANE_GFX) { + enable_lcd_clocks(1); + /* clear GOLCD bit */ + MOD_REG_FLD(DISPC_CONTROL, 0x20, 0); + if (omapfb_dispc_rotation == 1) { + omap2_disp_set_vrfb(width, height, bpp); + switch (angle) { + case 0: + addr_base = vrfb.paddr[0]; + dispc_write_reg(DISPC_GFX_BA0, addr_base); + dispc_write_reg(DISPC_GFX_PIXEL_INC, 1); + dispc_write_reg(DISPC_GFX_ROW_INC, + (ROT_LINE_LENGTH - width) * bpp + 1); + break; + case 90: + addr_base = vrfb.paddr[1]; + dispc_write_reg(DISPC_GFX_BA0, addr_base); + dispc_write_reg(DISPC_GFX_PIXEL_INC, 1); + dispc_write_reg(DISPC_GFX_ROW_INC, + (ROT_LINE_LENGTH - height) * bpp + 1); + break; + case 180: + addr_base = vrfb.paddr[2]; + dispc_write_reg(DISPC_GFX_BA0, addr_base); + dispc_write_reg(DISPC_GFX_PIXEL_INC, 1); + dispc_write_reg(DISPC_GFX_ROW_INC, + (ROT_LINE_LENGTH - width) * bpp + 1); + break; + case 270: + addr_base = vrfb.paddr[3]; + dispc_write_reg(DISPC_GFX_BA0, addr_base); + dispc_write_reg(DISPC_GFX_PIXEL_INC, 1); + dispc_write_reg(DISPC_GFX_ROW_INC, + (ROT_LINE_LENGTH - height) * bpp + 1); + break; + } + } else { + return r; + } + /* set GOLCD bit */ + MOD_REG_FLD(DISPC_CONTROL, 0x20, 0x20); + enable_lcd_clocks(0); + } + return r; +} + +static int omap2_alloc_vrfb_mem(struct omapfb_mem_desc *req_vram) +{ + int r = 0; + memset(&vrfb, 0, sizeof(vrfb)); + vrfb.paddr[0] = SMS_ROT_BASE_ADDR(0, 0); + vrfb.paddr[1] = SMS_ROT_BASE_ADDR(0, 90); + vrfb.paddr[2] = SMS_ROT_BASE_ADDR(0, 180); + vrfb.paddr[3] = SMS_ROT_BASE_ADDR(0, 270); + + if (!request_mem_region(vrfb.paddr[0], + req_vram->region[0].size, "omapfb")) { + r = -1; + printk(KERN_ERR "omapfb: can't reserve VRFB0 area\n"); + } + + if (!request_mem_region(vrfb.paddr[1], + req_vram->region[0].size, "omapfb")) { + r = -1; + printk(KERN_ERR "omapfb: can't reserve VRFB90 area\n"); + } + + if (!request_mem_region(vrfb.paddr[2], + req_vram->region[0].size, "omapfb")) { + r = -1; + printk(KERN_ERR "omapfb: can't reserveVRFB180 area\n"); + } + + if (!request_mem_region(vrfb.paddr[3], + req_vram->region[0].size, "omapfb")) { + r = -1; + printk(KERN_ERR "omapfb: can't reserve VRFB270 area\n"); + } + + vrfb.vaddr[0] = ioremap(vrfb.paddr[0], + req_vram->region[0].size); + vrfb.vaddr[1] = ioremap(vrfb.paddr[1], + req_vram->region[0].size); + vrfb.vaddr[2] = ioremap(vrfb.paddr[2], + req_vram->region[0].size); + vrfb.vaddr[3] = ioremap(vrfb.paddr[3], + req_vram->region[0].size); + if ((!vrfb.vaddr[0]) || (!vrfb.vaddr[1]) || (!vrfb.vaddr[2]) + || (!vrfb.vaddr[3])) { + r = -1; + printk(KERN_ERR "omapfb: can't map rotated view(s)\n"); + } + return r; +} + static void write_firh_reg(int plane, int reg, u32 value) { u32 base; @@ -1425,10 +1602,20 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, if ((r = alloc_palette_ram()) < 0) goto fail2; - + if (omapfb_dispc_rotation == 1) { + if (omap2_alloc_vrfb_mem(req_vram) < 0) + printk(KERN_ERR "VRFB memory allocation failed"); + } if ((r = setup_fbmem(req_vram)) < 0) goto fail3; - + if (omapfb_dispc_rotation == 1) { + save_paddr = dispc.mem_desc.region[0].paddr; + save_vaddr = dispc.mem_desc.region[0].vaddr; + dispc.mem_desc.region[0].vaddr = vrfb.vaddr[0]; + dispc.mem_desc.region[0].paddr = vrfb.paddr[0]; + dispc.fbdev->mem_desc.region[0].paddr = vrfb.paddr[0]; + dispc.fbdev->mem_desc.region[0].vaddr = vrfb.vaddr[0]; + } if (!skip_init) { for (i = 0; i < dispc.mem_desc.region_cnt; i++) { memset(dispc.mem_desc.region[i].vaddr, 0, @@ -1478,7 +1665,6 @@ fail0: static void omap_dispc_cleanup(void) { int i; - omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED); /* This will also disable clocks that are on */ for (i = 0; i < dispc.mem_desc.region_cnt; i++) @@ -1507,4 +1693,5 @@ const struct lcd_ctrl omap2_int_ctrl = { .set_color_key = omap_dispc_set_color_key, .get_color_key = omap_dispc_get_color_key, .mmap = omap_dispc_mmap_user, + .set_rotate = omap_dispc_set_rotate, }; diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h index ef720a7..5b29e6f 100644 --- a/drivers/video/omap/dispc.h +++ b/drivers/video/omap/dispc.h @@ -32,6 +32,35 @@ #define DISPC_TFT_DATA_LINES_18 2 #define DISPC_TFT_DATA_LINES_24 3 +/* Rotation using VRFB */ +extern int omapfb_dispc_rotation; +#define SMS_ROT_BASE_ADDR(context, degree) (0x70000000 \ + | 0x4000000 * (context) \ + | 0x1000000 * (degree/90)) +#define PAGE_WIDTH_EXP 5 /* Assuming SDRAM pagesize= 1024 */ +#define PAGE_HEIGHT_EXP 5 /* 1024 = 2^5 * 2^5 */ +#define SMS_IMAGEHEIGHT_OFFSET 16 +#define SMS_IMAGEWIDTH_OFFSET 0 +#define SMS_PH_OFFSET 8 +#define SMS_PW_OFFSET 4 +#define SMS_PS_OFFSET 0 +#define ROT_LINE_LENGTH 2048 + +#define DSS_REG_BASE 0x48050000 +#define DISPC_REG_OFFSET 0x00000400 +#define DISPC_BASE 0x48050400 +#define OMAP_SMS_BASE (0x6C000000) +#define DISPC_GFX_BA0 0x0080 +#define DISPC_GFX_ROW_INC 0x00AC +#define DISPC_GFX_PIXEL_INC 0x00B0 +#define DISPC_CONTROL 0x0040 + +#define SMS_ROT0_PHYSICAL_BA(context) OMAP2_IO_ADDRESS(OMAP_SMS_BASE + 0x188 \ + + 0x10 * context) +#define SMS_ROT_CONTROL(context) OMAP2_IO_ADDRESS(OMAP_SMS_BASE + 0x180 \ + + 0x10 * context) +#define SMS_ROT0_SIZE(context) OMAP2_IO_ADDRESS(OMAP_SMS_BASE + 0x184 \ + + 0x10 * context) extern void omap_dispc_set_lcd_size(int width, int height); extern void omap_dispc_enable_lcd_out(int enable); diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index d176a2c..8f2746c 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -35,7 +35,8 @@ #include "dispc.h" #define MODULE_NAME "omapfb" - +int omapfb_dispc_rotation = -1; +#define ROT_LINE_LENGTH 2048 static unsigned int def_accel; static unsigned long def_vram[OMAPFB_PLANE_NUM]; static unsigned int def_vram_cnt; @@ -219,9 +220,11 @@ static int ctrl_change_mode(struct fb_info *fbi) if (r < 0) return r; - if (fbdev->ctrl->set_rotate != NULL) - if((r = fbdev->ctrl->set_rotate(var->rotate)) < 0) + if (fbdev->ctrl->set_rotate != NULL) { + r = fbdev->ctrl->set_rotate(0, var->rotate); + if (r < 0) return r; + } if ((fbdev->ctrl->set_scale != NULL) && (plane->idx > 0)) r = fbdev->ctrl->set_scale(plane->idx, @@ -425,7 +428,10 @@ static void set_fb_fix(struct fb_info *fbi) break; } fix->accel = FB_ACCEL_OMAP1610; - fix->line_length = var->xres_virtual * bpp / 8; + if (omapfb_dispc_rotation) + fix->line_length = ROT_LINE_LENGTH * bpp / 8; + else if (!omapfb_dispc_rotation) + fix->line_length = var->xres_virtual * bpp / 8; } static int set_color_mode(struct omapfb_plane_struct *plane, @@ -497,14 +503,13 @@ static int set_fb_var(struct fb_info *fbi, bpp = var->bits_per_pixel; if (plane->color_mode == OMAPFB_COLOR_RGB444) bpp = 16; - + xres_min = OMAPFB_PLANE_XRES_MIN; + xres_max = panel->x_res; + yres_min = OMAPFB_PLANE_YRES_MIN; + yres_max = panel->y_res; switch (var->rotate) { case 0: case 180: - xres_min = OMAPFB_PLANE_XRES_MIN; - xres_max = panel->x_res; - yres_min = OMAPFB_PLANE_YRES_MIN; - yres_max = panel->y_res; if (cpu_is_omap15xx()) { var->xres = panel->x_res; var->yres = panel->y_res; @@ -512,10 +517,6 @@ static int set_fb_var(struct fb_info *fbi, break; case 90: case 270: - xres_min = OMAPFB_PLANE_YRES_MIN; - xres_max = panel->y_res; - yres_min = OMAPFB_PLANE_XRES_MIN; - yres_max = panel->x_res; if (cpu_is_omap15xx()) { var->xres = panel->y_res; var->yres = panel->x_res; @@ -1718,7 +1719,11 @@ static int omapfb_do_probe(struct platform_device *pdev, pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); - def_vxres = def_vxres ? : fbdev->panel->x_res; + if (omapfb_dispc_rotation) + def_vxres = ROT_LINE_LENGTH; + else if (!omapfb_dispc_rotation) + def_vxres = def_vxres ? : fbdev->panel->x_res; + def_vyres = def_vyres ? : fbdev->panel->y_res; init_state++; @@ -1909,8 +1914,10 @@ static int __init omapfb_setup(char *options) def_vxres = simple_strtoul(this_opt + 6, NULL, 0); else if (!strncmp(this_opt, "vyres:", 6)) def_vyres = simple_strtoul(this_opt + 6, NULL, 0); - else if (!strncmp(this_opt, "rotate:", 7)) + else if (!strncmp(this_opt, "rotate=", 7)) { + omapfb_dispc_rotation = 1; def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); + } else if (!strncmp(this_opt, "mirror:", 7)) def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); else if (!strncmp(this_opt, "manual_update", 13)) -- 1.5.3.2 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html