diff options
-rwxr-xr-x | drivers/video/rockchip/lcdc/rk312x_lcdc.c | 48 | ||||
-rwxr-xr-x | drivers/video/rockchip/lcdc/rk3288_lcdc.c | 48 | ||||
-rwxr-xr-x | drivers/video/rockchip/rk_fb.c | 98 | ||||
-rwxr-xr-x | include/linux/rk_fb.h | 6 | ||||
-rw-r--r-- | 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); Binary files differ |