Hi, On Wed, Sep 17, 2008 at 11:43 AM, <nskamat@xxxxxx> wrote: > From: Rajesh K <krajesh@xxxxxx> > > OMAP FBDEV: VRFB framebuffer rotation support > > This patch provides rotation support for OMAP2/3. You will have to append > video=omapfb:rotation=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 | 189 +++++++++++++++++++++++++++++- > drivers/video/omap/dispc.h | 33 +++++- > drivers/video/omap/omapfb_main.c | 32 +++--- > 4 files changed, 236 insertions(+), 22 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..1f5a7a5 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; sav_vaddr is defined but nowhere used. > +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 (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,16 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, > > if ((r = alloc_palette_ram()) < 0) > goto fail2; > - > + if (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 (rotation == 1) { > + save_paddr = dispc.mem_desc.region[0].paddr; Here you are missing these 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]; Because set_fb_fix will be using those to fill up struct fb_fix_screeninfo see below rg = &plane->fbdev->mem_desc.region[plane->idx]; fbi->screen_base = (char __iomem *)rg->vaddr; fix->smem_start = rg->paddr; fix->smem_len = rg->size; > + 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 +1661,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 +1689,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..506e4c6 100644 > --- a/drivers/video/omap/dispc.h > +++ b/drivers/video/omap/dispc.h > @@ -2,7 +2,7 @@ > #define _DISPC_H > > #include <linux/interrupt.h> > - > +#include <mach/hardware.h> > #define DISPC_PLANE_GFX 0 > #define DISPC_PLANE_VID1 1 > #define DISPC_PLANE_VID2 2 > @@ -32,6 +32,37 @@ > #define DISPC_TFT_DATA_LINES_18 2 > #define DISPC_TFT_DATA_LINES_24 3 > > +/* Rotation using VRFB */ > +extern int rotation; > +#define SMS_ROT_BASE_ADDR(context, degree) (0x70000000 \ > + | 0x4000000 * (context) \ > + | 0x1000000 * (degree/90)) > +#define BITS_PER_PIXEL 16 /* RGB value */ > +#define VRFB_SIZE (2048 * 640 * (BITS_PER_PIXEL/8)) VRFB_SIZE deifned but not used > +#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..1d2ceb8 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 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,7 @@ static void set_fb_fix(struct fb_info *fbi) > break; > } > fix->accel = FB_ACCEL_OMAP1610; > - fix->line_length = var->xres_virtual * bpp / 8; > + fix->line_length = ROT_LINE_LENGTH * bpp / 8; or if (rotation) fix->line_length = ROT_LINE_LENGTH * bpp / 8; else fix->line_length = var->xres_virtual * bpp / 8; > } > > static int set_color_mode(struct omapfb_plane_struct *plane, > @@ -497,14 +500,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 +514,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 +1716,7 @@ 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; > + def_vxres = ROT_LINE_LENGTH; Or if (rotation) def_vxres = ROT_LINE_LENGTH; else def_vxres = def_vxres ? : fbdev->panel->x_res; > def_vyres = def_vyres ? : fbdev->panel->y_res; > > init_state++; > @@ -1909,8 +1907,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)) > - def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); > + else if (!strncmp(this_opt, "rotation=", 9)) { > + rotation = 1; > + def_rotate = (simple_strtoul(this_opt + 9, 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 > -- 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