From 2fddf40afc10ab11cef5019aaafccc804122ccd6 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 29 Dec 2014 15:06:25 +0800 Subject: [PATCH] rk_fb: update uboot & kernel logo parse Sometimes we want to display logo at hdmi screen. but hdmi uboot resolution maybe different with framebuffer size, so we need read logo config from regs and decide how to display logo at kernel. now only support uboot logo size = kernel logo size Signed-off-by: Mark Yao --- drivers/video/rockchip/lcdc/rk312x_lcdc.c | 48 +++++++++++ drivers/video/rockchip/lcdc/rk3288_lcdc.c | 48 +++++++++++ drivers/video/rockchip/rk_fb.c | 98 ++++++++++++++++------ include/linux/rk_fb.h | 6 ++ logo.bmp | Bin 17184 -> 170326 bytes 5 files changed, 174 insertions(+), 26 deletions(-) diff --git a/drivers/video/rockchip/lcdc/rk312x_lcdc.c b/drivers/video/rockchip/lcdc/rk312x_lcdc.c index 9edc3e1508af..5f911416c081 100755 --- a/drivers/video/rockchip/lcdc/rk312x_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk312x_lcdc.c @@ -1057,6 +1057,52 @@ static void rk312x_lcdc_select_bcsh(struct rk_lcdc_driver *dev_drv, } } +static int rk312x_get_dspbuf_info(struct rk_lcdc_driver *dev_drv, u16 *xact, + u16 *yact, int *format, u32 *dsp_addr) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + u32 val; + + spin_lock(&lcdc_dev->reg_lock); + + val = lcdc_readl(lcdc_dev, WIN0_ACT_INFO); + *xact = (val & m_ACT_WIDTH)+1; + *yact = ((val & m_ACT_HEIGHT)>>16)+1; + + val = lcdc_readl(lcdc_dev, SYS_CTRL); + + *format = (val & m_WIN0_FORMAT) >> 3; + *dsp_addr = lcdc_readl(lcdc_dev, WIN0_YRGB_MST); + + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int rk312x_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst, + int format, u16 xact, u16 yact, u16 xvir) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + u32 val, mask; + + mask = m_WIN0_FORMAT; + val = v_WIN0_FORMAT(format); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val); + + lcdc_msk_reg(lcdc_dev, WIN0_VIR, m_YRGB_VIR, + v_YRGB_VIR(xvir)); + lcdc_writel(lcdc_dev, WIN0_ACT_INFO, v_ACT_WIDTH(xact) | + v_ACT_HEIGHT(yact)); + + lcdc_writel(lcdc_dev, WIN0_YRGB_MST, rgb_mst); + + lcdc_cfg_done(lcdc_dev); + + return 0; +} + static int rk312x_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen) { u16 face = 0; @@ -2395,6 +2441,8 @@ static int rk312x_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable) static struct rk_lcdc_drv_ops lcdc_drv_ops = { .open = rk312x_lcdc_open, .load_screen = rk312x_load_screen, + .get_dspbuf_info = rk312x_get_dspbuf_info, + .post_dspbuf = rk312x_post_dspbuf, .set_par = rk312x_lcdc_set_par, .pan_display = rk312x_lcdc_pan_display, .direct_set_addr = rk312x_lcdc_direct_set_win_addr, diff --git a/drivers/video/rockchip/lcdc/rk3288_lcdc.c b/drivers/video/rockchip/lcdc/rk3288_lcdc.c index d2431abffef1..51b4eaa8cec0 100755 --- a/drivers/video/rockchip/lcdc/rk3288_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3288_lcdc.c @@ -1063,6 +1063,52 @@ static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv) } +static int rk3288_get_dspbuf_info(struct rk_lcdc_driver *dev_drv, u16 *xact, + u16 *yact, int *format, u32 *dsp_addr) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + u32 val; + + spin_lock(&lcdc_dev->reg_lock); + + val = lcdc_readl(lcdc_dev, WIN0_ACT_INFO); + *xact = (val & m_WIN0_ACT_WIDTH) + 1; + *yact = ((val & m_WIN0_ACT_HEIGHT)>>16) + 1; + + val = lcdc_readl(lcdc_dev, WIN0_CTRL0); + *format = (val & m_WIN0_DATA_FMT) >> 1; + *dsp_addr = lcdc_readl(lcdc_dev, WIN0_YRGB_MST); + + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int rk3288_post_dspbuf(struct rk_lcdc_driver *dev_drv, u32 rgb_mst, + int format, u16 xact, u16 yact, u16 xvir) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + u32 val, mask; + int swap = (format == RGB888) ? 1 : 0; + + mask = m_WIN0_DATA_FMT | m_WIN0_RB_SWAP; + val = v_WIN0_DATA_FMT(format) | v_WIN0_RB_SWAP(swap); + lcdc_msk_reg(lcdc_dev, WIN0_CTRL0, mask, val); + + lcdc_msk_reg(lcdc_dev, WIN0_VIR, m_WIN0_VIR_STRIDE, + v_WIN0_VIR_STRIDE(xvir)); + lcdc_writel(lcdc_dev, WIN0_ACT_INFO, v_WIN0_ACT_WIDTH(xact) | + v_WIN0_ACT_HEIGHT(yact)); + + lcdc_writel(lcdc_dev, WIN0_YRGB_MST, rgb_mst); + + lcdc_cfg_done(lcdc_dev); + + return 0; +} + static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen) { u16 face = 0; @@ -3535,6 +3581,8 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = { .open = rk3288_lcdc_open, .win_direct_en = rk3288_lcdc_win_direct_en, .load_screen = rk3288_load_screen, + .get_dspbuf_info = rk3288_get_dspbuf_info, + .post_dspbuf = rk3288_post_dspbuf, .set_par = rk3288_lcdc_set_par, .pan_display = rk3288_lcdc_pan_display, .direct_set_addr = rk3288_lcdc_direct_set_win_addr, diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index be3e5cf80c4b..041a40b9eefa 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -4151,6 +4151,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, /* show logo for primary display device */ #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) if (dev_drv->prop == PRMRY) { + u16 xact, yact; + int format; + u32 dsp_addr; struct fb_info *main_fbi = rk_fb->fb[0]; main_fbi->fbops->fb_open(main_fbi, 1); @@ -4165,8 +4168,8 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, rk_fb_alloc_buffer(main_fbi, 0); /* only alloc memory for main fb */ dev_drv->uboot_logo = support_uboot_display(); - if (uboot_logo_offset && uboot_logo_base) { - struct rk_lcdc_win *win = dev_drv->win[0]; + if (dev_drv->uboot_logo && + uboot_logo_offset && uboot_logo_base) { int width, height, bits; phys_addr_t start = uboot_logo_base + uboot_logo_offset; unsigned int size = uboot_logo_size - uboot_logo_offset; @@ -4175,6 +4178,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, char *vaddr; int i = 0; + if (dev_drv->ops->get_dspbuf_info) + dev_drv->ops->get_dspbuf_info(dev_drv, &xact, + &yact, &format, &dsp_addr); nr_pages = size >> PAGE_SHIFT; pages = kzalloc(sizeof(struct page) * nr_pages, GFP_KERNEL); @@ -4199,35 +4205,75 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, } kfree(pages); vunmap(vaddr); - if (width > main_fbi->var.xres || - height > main_fbi->var.yres) { - pr_err("ERROR: logo size out of screen range"); + if (dev_drv->uboot_logo && + (width != xact || height != yact)) { + pr_err("can't support uboot kernel logo use different size [%dx%d] != [%dx%d]\n", + xact, yact, width, height); return 0; } - win->area[0].format = rk_fb_data_fmt(0, bits); - win->area[0].y_vir_stride = width * bits >> 5; - win->area[0].xpos = (main_fbi->var.xres - width) >> 1; - win->area[0].ypos = (main_fbi->var.yres - height) >> 1; - win->area[0].xsize = width; - win->area[0].ysize = height; - win->area[0].xact = width; - win->area[0].yact = height; - win->area[0].xvir = win->area[0].y_vir_stride; - win->area[0].yvir = height; - win->area[0].smem_start = main_fbi->fix.smem_start; - win->area[0].y_offset = 0; - - win->area_num = 1; - win->alpha_mode = 4; - win->alpha_en = 0; - win->g_alpha_val = 0; + if (dev_drv->ops->post_dspbuf) { + dev_drv->ops->post_dspbuf(dev_drv, + main_fbi->fix.smem_start, + rk_fb_data_fmt(0, bits), + width, height, width * bits >> 5); + } + if (dev_drv->iommu_enabled) { + rk_fb_poll_wait_frame_complete(); + if (dev_drv->ops->mmu_en) + dev_drv->ops->mmu_en(dev_drv); + freed_index = 0; + } - win->state = 1; - dev_drv->ops->set_par(dev_drv, 0); - dev_drv->ops->pan_display(dev_drv, 0); - dev_drv->ops->cfg_done(dev_drv); + return 0; + } else if (dev_drv->uboot_logo && uboot_logo_base) { + phys_addr_t start = uboot_logo_base; + int logo_len, i=0; + unsigned int nr_pages; + struct page **pages; + char *vaddr; + dev_drv->ops->get_dspbuf_info(dev_drv, &xact, + &yact, &format, + &start); + logo_len = rk_fb_pixel_width(format) * xact * yact >> 3; + if (logo_len > uboot_logo_size || + logo_len > main_fbi->fix.smem_len) { + pr_err("logo size > uboot reserve buffer size\n"); + return -1; + } + + nr_pages = uboot_logo_size >> PAGE_SHIFT; + pages = kzalloc(sizeof(struct page) * nr_pages, + GFP_KERNEL); + while (i < nr_pages) { + pages[i] = phys_to_page(start); + start += PAGE_SIZE; + i++; + } + vaddr = vmap(pages, nr_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!vaddr) { + pr_err("failed to vmap phy addr %x\n", + uboot_logo_base); + return -1; + } + + memcpy(main_fbi->screen_base, vaddr, logo_len); + + kfree(pages); + vunmap(vaddr); + + dev_drv->ops->post_dspbuf(dev_drv, + main_fbi->fix.smem_start, + format, xact, yact, + xact * rk_fb_pixel_width(format) >> 5); + if (dev_drv->iommu_enabled) { + rk_fb_poll_wait_frame_complete(); + if (dev_drv->ops->mmu_en) + dev_drv->ops->mmu_en(dev_drv); + freed_index = 0; + } return 0; } #if defined(CONFIG_LOGO) diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index e6331e8b234e..657fbef59aa6 100755 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -428,6 +428,12 @@ struct rk_lcdc_drv_ops { ssize_t(*get_disp_info) (struct rk_lcdc_driver *dev_drv, char *buf, int layer_id); int (*load_screen) (struct rk_lcdc_driver *dev_drv, bool initscreen); + int (*get_dspbuf_info) (struct rk_lcdc_driver *dev_drv, + u16 *xact, u16 *yact, int *format, + u32 *dsp_addr); + int (*post_dspbuf)(struct rk_lcdc_driver *dev_drv, u32 rgb_mst, + int format, u16 xact, u16 yact, u16 xvir); + int (*get_win_state) (struct rk_lcdc_driver *dev_drv, int layer_id); int (*ovl_mgr) (struct rk_lcdc_driver *dev_drv, int swap, bool set); /*overlay manager*/ int (*fps_mgr) (struct rk_lcdc_driver *dev_drv, int fps, bool set); diff --git a/logo.bmp b/logo.bmp index a5e4c9211c5d2850916ecf2d8196dc3759f1d44f..13a761f90b804a412f3e5349713f4c0b0879cc48 100644 GIT binary patch literal 170326 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 literal 17184 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 -- 2.34.1