From d2e238c49ec73e1b6f125086713b321b63d1938a Mon Sep 17 00:00:00 2001 From: zwl Date: Mon, 12 May 2014 20:02:28 +0800 Subject: [PATCH] rk fb: add support fb rotate by rga --- drivers/video/rockchip/rga2/rga2.h | 2 +- drivers/video/rockchip/rk_fb.c | 345 +++++++++++++++++++--- drivers/video/rockchip/screen/rk_screen.c | 14 + 3 files changed, 321 insertions(+), 40 deletions(-) diff --git a/drivers/video/rockchip/rga2/rga2.h b/drivers/video/rockchip/rga2/rga2.h index 3a05e885b2bb..18d8eb8d928c 100644 --- a/drivers/video/rockchip/rga2/rga2.h +++ b/drivers/video/rockchip/rga2/rga2.h @@ -630,7 +630,7 @@ struct rga2_service_info { #define RGA2_MODE_CTRL 0x100 #define RGA_BLIT_COMPLETE_EVENT 1 -long rga2_ioctl_kernel(struct rga2_req *req); +long rga_ioctl_kernel(struct rga_req *req); #endif /*_RK29_IPP_DRIVER_H_*/ diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 1287404f7e3e..3a57a2c8473a 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -35,6 +35,12 @@ #include "hdmi/rk_hdmi.h" #endif +#if defined(CONFIG_ROCKCHIP_RGA) +#include "rga/rga.h" +#elif defined(CONFIG_ROCKCHIP_RGA2) +#include "rga2/rga2.h" +#endif + #ifdef CONFIG_OF #include #include @@ -783,17 +789,234 @@ static void fb_copy_by_ipp(struct fb_info *dst_info, #endif +#if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2) +static int get_rga_format(int fmt) +{ + int rga_fmt = 0; +#if defined(CONFIG_ROCKCHIP_RGA) + switch (fmt) + { + case XBGR888: + rga_fmt = RK_FORMAT_RGBX_8888; + break; + case ABGR888: + rga_fmt = RK_FORMAT_RGBA_8888; + break; + case ARGB888: + rga_fmt = RK_FORMAT_BGRA_8888; + break; + case RGB888: + rga_fmt = RK_FORMAT_RGB_888; + break; + case RGB565: + rga_fmt = RK_FORMAT_RGB_565; + break; + case YUV422: + rga_fmt = RK_FORMAT_YCbCr_422_SP; + break; + case YUV420: + rga_fmt = RK_FORMAT_YCbCr_420_SP; + break; + default: + rga_fmt = RK_FORMAT_RGBA_8888; + break; + } +#elif defined(CONFIG_ROCKCHIP_RGA2) + switch (fmt) + { + case XBGR888: + rga_fmt = RGA2_FORMAT_RGBX_8888; + break; + case ABGR888: + rga_fmt = RGA2_FORMAT_RGBA_8888; + break; + case ARGB888: + rga_fmt = RGA2_FORMAT_BGRA_8888; + break; + case RGB888 : + rga_fmt = RGA2_FORMAT_RGB_888; + break; + case RGB565: + rga_fmt = RGA2_FORMAT_RGB_565; + break; + case YUV422: + rga_fmt = RGA2_FORMAT_YCbCr_422_SP; + break; + case YUV420: + rga_fmt = RGA2_FORMAT_YCbCr_420_SP; + break; + default: + rga_fmt = RGA2_FORMAT_RGBA_8888; + break; + } +#endif + return rga_fmt; + +} + +static void rga_win_check(struct rk_lcdc_win *dst_win, struct rk_lcdc_win *src_win) +{ + int align32 = 4; + + align32 -= 1; + /*width and height must be aligned by 32 bit*/ + if ((src_win->area[0].xact & align32) != 0) + src_win->area[0].xact = (src_win->area[0].xact + align32) & (~align32); + if ((src_win->area[0].yact & align32) != 0) + src_win->area[0].yact = (src_win->area[0].yact + align32) & (~align32); + if (src_win->area[0].xvir < src_win->area[0].xact) + src_win->area[0].xvir = src_win->area[0].xact; + + if ((dst_win->area[0].xact & align32) != 0) + dst_win->area[0].xact = (dst_win->area[0].xact + align32) & (~align32); + if ((dst_win->area[0].yact & align32) != 0) + dst_win->area[0].yact = (dst_win->area[0].yact + align32) & (~align32); + if (dst_win->area[0].xvir < dst_win->area[0].xact) + dst_win->area[0].xvir = dst_win->area[0].xact; +} + +static void win_copy_by_rga(struct rk_lcdc_win *dst_win, struct rk_lcdc_win *src_win) +{ + struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); + struct rga_req Rga_Request; + long ret = 0; + //int fd = 0; +#if defined(CONFIG_FB_ROTATE) + int orientation = 0; +#endif + + memset(&Rga_Request, 0, sizeof(Rga_Request)); + rga_win_check(dst_win, src_win); +#if defined(CONFIG_FB_ROTATE) + orientation = 270 - CONFIG_ROTATE_ORIENTATION; + switch (orientation) { + case 90: + Rga_Request.rotate_mode = 1; + Rga_Request.sina = 65536; + Rga_Request.cosa = 0; + Rga_Request.dst.x_offset = dst_win->area[0].xact - 1; + Rga_Request.dst.y_offset = 0; + break; + case 180: + Rga_Request.rotate_mode = 1; + Rga_Request.sina = 0; + Rga_Request.cosa = -65536; + Rga_Request.dst.x_offset = dst_win->area[0].xact - 1; + Rga_Request.dst.y_offset = dst_win->area[0].yact - 1; + break; + case 270: + Rga_Request.rotate_mode = 1; + Rga_Request.sina = -65536; + Rga_Request.cosa = 0; + Rga_Request.dst.x_offset = dst_win->area[0].xact - 1; + Rga_Request.dst.y_offset = dst_win->area[0].yact - 1; + break; + default: + Rga_Request.rotate_mode = 0; + Rga_Request.dst.x_offset = dst_win->area[0].xact - 1; + Rga_Request.dst.y_offset = dst_win->area[0].yact - 1; + break; + } +#endif + +#if defined(CONFIG_ROCKCHIP_RGA) + Rga_Request.src.yrgb_addr = src_win->area[0].smem_start + src_win->area[0].y_offset; + Rga_Request.src.uv_addr = 0; + Rga_Request.src.v_addr = 0; + + dst_win->area[0].smem_start = rk_fb->fb[rk_fb->num_fb>>1]->fix.smem_start; + Rga_Request.dst.yrgb_addr = dst_win->area[0].smem_start + dst_win->area[0].y_offset; + Rga_Request.dst.uv_addr = 0; + Rga_Request.dst.v_addr = 0; +#elif defined(CONFIG_ROCKCHIP_RGA2) +/* + fd = ion_share_dma_buf_fd(rk_fb->ion_client, src_win->area[0].ion_hdl); + Rga_Request.src.yrgb_addr = fd; + fd = ion_share_dma_buf_fd(rk_fb->ion_client, dst_win->area[0].ion_hdl); + Rga_Request.dst.yrgb_addr = fd; +*/ + Rga_Request.src.yrgb_addr = 0; + Rga_Request.src.uv_addr = src_win->area[0].smem_start + src_win->area[0].y_offset; + Rga_Request.src.v_addr = 0; + + dst_win->area[0].smem_start = rk_fb->fb[rk_fb->num_fb>>1]->fix.smem_start; + Rga_Request.dst.yrgb_addr = 0; + Rga_Request.dst.uv_addr = dst_win->area[0].smem_start + dst_win->area[0].y_offset; + Rga_Request.dst.v_addr = 0; +#endif + + Rga_Request.src.vir_w = src_win->area[0].xvir; + Rga_Request.src.vir_h = src_win->area[0].yvir; + Rga_Request.src.format = get_rga_format(src_win->format); + Rga_Request.src.act_w = src_win->area[0].xact; + Rga_Request.src.act_h = src_win->area[0].yact; + Rga_Request.src.x_offset = 0; + Rga_Request.src.y_offset = 0; + + Rga_Request.dst.vir_w = dst_win->area[0].xvir; + Rga_Request.dst.vir_h = dst_win->area[0].yvir; + Rga_Request.dst.format = get_rga_format(dst_win->format); + Rga_Request.dst.act_w = dst_win->area[0].xact; + Rga_Request.dst.act_h = dst_win->area[0].yact; + + Rga_Request.clip.xmin = 0; + Rga_Request.clip.xmax = dst_win->area[0].xact - 1; + Rga_Request.clip.ymin = 0; + Rga_Request.clip.ymax = dst_win->area[0].yact - 1; + Rga_Request.scale_mode = 0; + + ret = rga_ioctl_kernel(&Rga_Request); +} + +/***********************************************************************************/ +//This function is used for copying fb by RGA Module +//RGA only support copy RGB to RGB +//RGA2 support copy RGB to RGB and YUV to YUV +/***********************************************************************************/ +static void fb_copy_by_rga(struct fb_info *dst_info, struct fb_info *src_info, int yrgb_offset) +{ + struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)src_info->par; + struct rk_lcdc_driver *ext_dev_drv = (struct rk_lcdc_driver *)dst_info->par; + int win_id = 0, ext_win_id; + struct rk_lcdc_win *src_win, *dst_win; + + win_id = dev_drv->ops->fb_get_win_id(dev_drv, src_info->fix.id); + src_win = dev_drv->win[win_id]; + + ext_win_id = ext_dev_drv->ops->fb_get_win_id(ext_dev_drv, dst_info->fix.id); + dst_win = ext_dev_drv->win[ext_win_id]; + + win_copy_by_rga(dst_win, src_win); +} + +#endif + +#if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER) static int rk_fb_rotate(struct fb_info *dst_info, struct fb_info *src_info, int offset) { #if defined(CONFIG_RK29_IPP) fb_copy_by_ipp(dst_info, src_info, offset); + #elif defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2) + fb_copy_by_rga(dst_info, src_info, offset); + #else + return -1; + #endif + return 0; +} + +static int rk_fb_win_rotate(struct rk_lcdc_win *dst_win, struct rk_lcdc_win *src_win) +{ + #if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2) + win_copy_by_rga(dst_win, src_win); #else return -1; #endif return 0; } +#endif + static int rk_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct rk_fb *rk_fb = dev_get_drvdata(info->device); @@ -1085,7 +1308,9 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win,struct rk_fb_reg_win_dat win->id = reg_win_data->win_id; win->z_order = reg_win_data->z_order; win->area[0].uv_vir_stride = reg_win_data->reg_area_data[0].uv_vir_stride; + #if !defined(RK_FB_ROTATE) && defined(CONFIG_THREE_FB_BUFFER) /* TODO Mofidy if HDMI info is change to hwc */ win->area[0].cbr_start = reg_win_data->reg_area_data[0].cbr_start; + #endif win->area[0].c_offset = reg_win_data->reg_area_data[0].c_offset; win->alpha_en = reg_win_data->alpha_en; win->alpha_mode = reg_win_data->alpha_mode; @@ -1093,7 +1318,9 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win,struct rk_fb_reg_win_dat for(i=0;ireg_area_data[i].smem_start > 0){ + #if !defined(RK_FB_ROTATE) && defined(CONFIG_THREE_FB_BUFFER) win->area[i].smem_start = reg_win_data->reg_area_data[i].smem_start; + #endif win->area[i].xpos = reg_win_data->reg_area_data[i].xpos; win->area[i].ypos = reg_win_data->reg_area_data[i].ypos; win->area[i].xsize = reg_win_data->reg_area_data[i].xsize; @@ -1169,6 +1396,7 @@ static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_da } //hdmi just need set win0 only(win0 have only one area),other win is disable + win = dev_drv->win[0]; ext_win = ext_dev_drv->win[0]; for (j = 0;j < regs->win_num; j++) { if(0 == regs->reg_win_data[j].win_id) @@ -1203,11 +1431,9 @@ static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_da ext_win->area[0].xvir = win->area[0].yact; } - //disable the other win,except win0 - for (i = 1; i < ext_dev_drv->lcdc_win_num; i ++) { - ext_win = ext_dev_drv->win[i]; - ext_win->state = 0; - } + #if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER) + rk_fb_win_rotate(ext_win, win); + #endif ext_dev_drv->ops->set_par(ext_dev_drv, 0); ext_dev_drv->ops->pan_display(ext_dev_drv, 0); ext_dev_drv->ops->cfg_done(ext_dev_drv); @@ -2697,6 +2923,47 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id) } +#if defined(CONFIG_ION_ROCKCHIP) +static int rk_fb_alloc_buffer_by_ion(struct fb_info *fbi, + struct rk_lcdc_win *win, unsigned long fb_mem_size) +{ + struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); + struct ion_handle *handle; + ion_phys_addr_t phy_addr; + size_t len; + + handle = ion_alloc(rk_fb->ion_client, (size_t)fb_mem_size, 0, ION_HEAP(ION_CMA_HEAP_ID), 0); + if (IS_ERR(handle)) { + dev_err(fbi->device, "failed to ion_alloc:%ld\n",PTR_ERR(handle)); + return -ENOMEM; + } + win->area[0].dma_buf = ion_share_dma_buf(rk_fb->ion_client, handle); + if (IS_ERR_OR_NULL(win->area[0].dma_buf)) { + printk("ion_share_dma_buf() failed\n"); + goto err_share_dma_buf; + } + win->area[0].ion_hdl = handle; + fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle); +#ifdef CONFIG_ROCKCHIP_IOMMU + if (dev_drv->iommu_enabled) + ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle, + (unsigned long *)&phy_addr, (unsigned long *)&len); + else + ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); +#else + ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); +#endif + fbi->fix.smem_start = phy_addr; + fbi->fix.smem_len = len; + printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n", phy_addr); + return 0; + +err_share_dma_buf: + ion_free(rk_fb->ion_client, handle); + return -ENOMEM; +} +#endif + static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) { struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); @@ -2705,11 +2972,12 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) int win_id; int ret = 0; unsigned long fb_mem_size; -#if defined(CONFIG_ION_ROCKCHIP) - struct ion_handle *handle; - ion_phys_addr_t phy_addr; - size_t len; +/* +#if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER) + struct resource *res; + struct resource *mem; #endif +*/ win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id); if (win_id < 0) return -ENODEV; @@ -2717,33 +2985,10 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) win = dev_drv->win[win_id]; if (!strcmp(fbi->fix.id, "fb0")) { - fb_mem_size = 3 * (((fbi->var.xres + 31)&(~31))* fbi->var.yres) << 2; - fb_mem_size = ALIGN(fb_mem_size, SZ_1M); + fb_mem_size = get_fb_size(); #if defined(CONFIG_ION_ROCKCHIP) - handle = ion_alloc(rk_fb->ion_client, (size_t)fb_mem_size, 0, ION_HEAP(ION_CMA_HEAP_ID), 0); - if (IS_ERR(handle)) { - dev_err(fbi->device, "failed to ion_alloc:%ld\n",PTR_ERR(handle)); + if(rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0) return -ENOMEM; - } - win->area[0].dma_buf = ion_share_dma_buf(rk_fb->ion_client, handle); - if (IS_ERR_OR_NULL(win->area[0].dma_buf)) { - printk("ion_share_dma_buf() failed\n"); - goto err_share_dma_buf; - } - win->area[0].ion_hdl = handle; - fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle); -#ifdef CONFIG_ROCKCHIP_IOMMU - if (dev_drv->iommu_enabled) - ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle, - (unsigned long *)&phy_addr, (unsigned long *)&len); - else - ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); -#else - ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); -#endif - fbi->fix.smem_start = phy_addr; - fbi->fix.smem_len = len; - printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n",phy_addr); #else dma_addr_t fb_mem_phys; void *fb_mem_virt; @@ -2762,6 +3007,7 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); } else { #if defined(CONFIG_FB_ROTATE) || !defined(CONFIG_THREE_FB_BUFFER) + /* res = platform_get_resource_byname(fb_pdev, IORESOURCE_MEM, "fb2 buf"); if (res == NULL) { @@ -2774,6 +3020,25 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) fb_pdev->name); fbi->screen_base = ioremap(res->start, fbi->fix.smem_len); memset(fbi->screen_base, 0, fbi->fix.smem_len); + */ + fb_mem_size = get_fb_size(); +#if defined(CONFIG_ION_ROCKCHIP) + if(rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0) + return -ENOMEM; +#else + dma_addr_t fb_mem_phys; + void *fb_mem_virt; + fb_mem_virt = dma_alloc_writecombine(fbi->dev, fb_mem_size, + &fb_mem_phys,GFP_KERNEL); + if (!fb_mem_virt) { + pr_err("%s: Failed to allocate framebuffer\n", __func__); + return -ENOMEM; + } + fbi->fix.smem_len = fb_mem_size; + fbi->fix.smem_start = fb_mem_phys; + fbi->screen_base = fb_mem_virt; +#endif + #else /*three buffer no need to copy*/ fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start; fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len; @@ -2791,11 +3056,6 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) } return ret; - -err_share_dma_buf: - ion_free(rk_fb->ion_client, handle); - return -ENOMEM; - } static int rk_release_fb_buffer(struct fb_info *fbi) @@ -3052,6 +3312,13 @@ if (dev_drv->prop == PRMRY) { #endif main_fbi->fbops->fb_pan_display(&main_fbi->var, main_fbi); } +else { +#if !defined(CONFIG_ROCKCHIP_IOMMU) + struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb>>1]; + int extend_fb_id = get_extend_fb_id(extend_fbi); + rk_fb_alloc_buffer(extend_fbi, extend_fb_id); +#endif +} #endif return 0; diff --git a/drivers/video/rockchip/screen/rk_screen.c b/drivers/video/rockchip/screen/rk_screen.c index bd799adcf307..7c0e6869d249 100755 --- a/drivers/video/rockchip/screen/rk_screen.c +++ b/drivers/video/rockchip/screen/rk_screen.c @@ -24,6 +24,20 @@ int rk_fb_set_prmry_screen(struct rk_screen *screen) return 0; } +size_t get_fb_size(void) +{ + size_t size = 0; + int xres = (rk_screen->mode.xres + 31) & (~31); + int yres = rk_screen->mode.yres; + + #if defined(CONFIG_THREE_FB_BUFFER) + size = (xres * yres << 2) * 3; //three buffer + #else + size = (xres * yres << 2) << 1; //two buffer + #endif + return ALIGN(size, SZ_1M); +} + static int rk_screen_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; -- 2.34.1