{
u32 _v = readl_relaxed(lcdc_dev->regs+offset);
_v &= msk;
- return (_v >> msk);
+ return (_v?1:0);
}
static inline void lcdc_set_bit(struct lcdc_device *lcdc_dev,u32 offset,u32 msk)
}
+#define WIN_EN(id) \
+static int win##id##_enable(struct lcdc_device *lcdc_dev, int en) \
+{ \
+ u32 msk, val; \
+ spin_lock(&lcdc_dev->reg_lock); \
+ msk = m_WIN##id##_EN; \
+ val = v_WIN##id##_EN(en); \
+ lcdc_msk_reg(lcdc_dev, WIN##id##_CTRL0, msk, val); \
+ lcdc_cfg_done(lcdc_dev); \
+ val = lcdc_read_bit(lcdc_dev, WIN##id##_CTRL0, msk); \
+ while (val != (!!en)) { \
+ val = lcdc_read_bit(lcdc_dev, WIN##id##_CTRL0, msk); \
+ } \
+ spin_unlock(&lcdc_dev->reg_lock); \
+ return 0; \
+}
+
+WIN_EN(0);
+WIN_EN(1);
+WIN_EN(2);
+WIN_EN(3);
+/*enable/disable win directly*/
+static int rk3288_lcdc_win_direct_en
+ (struct rk_lcdc_driver *drv, int win_id , int en)
+{
+ struct lcdc_device *lcdc_dev = container_of(drv,
+ struct lcdc_device, driver);
+ if (win_id == 0)
+ win0_enable(lcdc_dev, en);
+ else if (win_id == 1)
+ win1_enable(lcdc_dev, en);
+ else if (win_id == 2)
+ win2_enable(lcdc_dev, en);
+ else if (win_id == 3)
+ win3_enable(lcdc_dev, en);
+ else
+ dev_err(lcdc_dev->dev, "invalid win number:%d\n", win_id);
+ return 0;
+
+}
+
+#define SET_WIN_ADDR(id) \
+static int set_win##id##_addr(struct lcdc_device *lcdc_dev, u32 addr) \
+{ \
+ u32 msk, val; \
+ spin_lock(&lcdc_dev->reg_lock); \
+ lcdc_writel(lcdc_dev,WIN##id##_YRGB_MST,addr); \
+ msk = m_WIN##id##_EN; \
+ val = v_WIN0_EN(1); \
+ lcdc_msk_reg(lcdc_dev, WIN##id##_CTRL0, msk,val); \
+ lcdc_cfg_done(lcdc_dev); \
+ spin_unlock(&lcdc_dev->reg_lock); \
+ return 0; \
+}
+
+SET_WIN_ADDR(0);
+SET_WIN_ADDR(1);
+int rk3288_lcdc_direct_set_win_addr
+ (struct rk_lcdc_driver *dev_drv, int win_id, u32 addr)
+{
+ struct lcdc_device *lcdc_dev = container_of(dev_drv,
+ struct lcdc_device, driver);
+ if (win_id == 0)
+ set_win0_addr(lcdc_dev, addr);
+ else
+ set_win1_addr(lcdc_dev, addr);
+
+ return 0;
+}
+
+static void lcdc_read_reg_defalut_cfg(struct lcdc_device *lcdc_dev)
+{
+ int reg = 0;
+ u32 val = 0;
+ struct rk_lcdc_win *win0 = lcdc_dev->driver.win[0];
+
+ spin_lock(&lcdc_dev->reg_lock);
+ for (reg = 0; reg < 0x1a0; reg+= 4) {
+ val = lcdc_readl(lcdc_dev, reg);
+ switch (reg) {
+ case WIN0_ACT_INFO:
+ win0->area[0].xact = (val & m_WIN0_ACT_WIDTH)+1;
+ win0->area[0].yact = ((val & m_WIN0_ACT_HEIGHT)>>16)+1;
+ default:
+ break;
+ }
+ }
+ spin_unlock(&lcdc_dev->reg_lock);
+
+}
+
/********do basic init*********/
static int rk3288_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
{
rk3288_lcdc_clk_enable(lcdc_dev);
/*backup reg config at uboot*/
- for (i = 0; i < 0x1a0;) {
- lcdc_readl(lcdc_dev,i);
- i += 4;
- }
+ lcdc_read_reg_defalut_cfg(lcdc_dev);
#ifndef CONFIG_RK_FPGA
if (lcdc_dev->pwr18 == true) {
v = 0x00010001; /*bit14: 1,1.8v;0,3.3v*/
mask = m_AUTO_GATING_EN;
val = v_AUTO_GATING_EN(0);
lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask,val);
-
lcdc_cfg_done(lcdc_dev);
+ if (dev_drv->iommu_enabled) /*disable win0 to workaround iommu pagefault*/
+ win0_enable(lcdc_dev, 0);
lcdc_dev->pre_init = true;
u32 uv_addr;
y_addr = win->area[0].smem_start+win->area[0].y_offset;/*win->smem_start + win->y_offset;*/
uv_addr = win->area[0].cbr_start + win->area[0].c_offset;
- DBG(2, "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",
- lcdc_dev->id, __func__, y_addr, uv_addr);
+ DBG(2, "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x>>offset:%d\n",
+ lcdc_dev->id, __func__, y_addr, uv_addr,win->area[0].y_offset);
spin_lock(&lcdc_dev->reg_lock);
if (likely(lcdc_dev->clk_on)) {
win->area[0].y_addr = y_addr;
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,
.set_par = rk3288_lcdc_set_par,
.pan_display = rk3288_lcdc_pan_display,
+ .direct_set_addr = rk3288_lcdc_direct_set_win_addr,
.lcdc_reg_update = rk3288_lcdc_reg_update,
.blank = rk3288_lcdc_blank,
.ioctl = rk3288_lcdc_ioctl,
static inline u32 lcdc_read_bit(struct lcdc_device *lcdc_dev,u32 offset,u32 msk)
{
- u32 _v = readl_relaxed(lcdc_dev->regs+offset);
+ u32 *_pv = (u32*)lcdc_dev->regsbak;
+ u32 _v = readl_relaxed(lcdc_dev->regs+offset);
+ _pv += (offset >> 2);
+ *_pv = _v;
_v &= msk;
- return (_v >> msk);
+ return (_v?1:0);
}
static inline void lcdc_set_bit(struct lcdc_device *lcdc_dev,u32 offset,u32 msk)
#include <linux/rockchip/iovmm.h>
#include <linux/rockchip/sysmmu.h>
#include <linux/dma-buf.h>
+#include <linux/highmem.h>
#endif
printk("error waiting on fence\n");
}
+static int rk_fb_copy_from_loader(struct fb_info *info)
+{
+ struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
+ void *dst = info->screen_base;
+ u32 dsp_addr[4];
+ u32 src;
+ u32 i;
+ struct rk_lcdc_win *win = dev_drv->win[0];
+ u32 size = (win->area[0].xact) * (win->area[0].yact) << 2;
+ dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr);
+ src = dsp_addr[0];
+ dev_info(info->dev, "copy fb data %d x %d from dst_addr:%08x\n",
+ win->area[0].xact, win->area[0].yact, src);
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ void *page = phys_to_page(i + src);
+ void *from_virt = kmap(page);
+ void *to_virt = dst + i;
+ memcpy(to_virt, from_virt, PAGE_SIZE);
+ }
+ return 0;
+}
+
+
#ifdef CONFIG_ROCKCHIP_IOMMU
static int g_last_addr[4];
int g_last_timeout;
g_last_addr[2],
g_last_addr[3]);
printk("last freed buffer:\n");
- for (i = 0; freed_addr[i] != 0xfefefefe; i++)
+ for (i = 0; (freed_addr[i] != 0xfefefefe) && freed_addr[i]; i++)
printk("%d:0x%08x\n",i, freed_addr[i]);
printk("last timeout:%d\n", g_last_timeout);
dev_drv->ops->get_disp_info(dev_drv, buf,0) ;
struct fb_fix_screeninfo *fix = &info->fix;
struct rk_lcdc_driver * dev_drv = (struct rk_lcdc_driver * )info->par;
struct rk_screen *screen = dev_drv->cur_screen;
-
+ struct fb_info *fbi = rk_fb->fb[0];
int i,ion_fd,acq_fence_fd;
u32 xvir,yvir;
u32 xoffset,yoffset;
u8 is_pic_yuv=0;
u8 ppixel_a=0,global_a=0;
ion_phys_addr_t phy_addr;
-
reg_win_data->reg_area_data[0].smem_start = -1;
reg_win_data->area_num = 0;
+ fbi = rk_fb->fb[reg_win_data->win_id];
if(win_par->area_par[0].phy_addr == 0){
for(i=0;i<RK_WIN_MAX_AREA;i++){
ion_fd = win_par->area_par[i].ion_fd;
/*return -EINVAL;*/
break;
}
+ fbi->screen_base = ion_map_kernel(rk_fb->ion_client,hdl);
reg_win_data->area_num++;
reg_win_data->reg_area_data[i].ion_handle = hdl;
#ifndef CONFIG_ROCKCHIP_IOMMU
reg_win_data->reg_area_data[0].smem_start =
win_par->area_par[0].phy_addr;
reg_win_data->area_num = 1;
+ fbi->screen_base = phys_to_virt(win_par->area_par[0].phy_addr);
}
if(reg_win_data->area_num == 0){
win = dev_drv->win[win_id];
if (win->format == RGB565)
- total_size = win->area[0].xact*win->area[0].yact<<1; /*only read the current frame buffer*/
- else
- total_size = win->area[0].xact*win->area[0].yact<<2;
+ total_size = win->area[0].y_vir_stride * win->area[0].yact << 1; /*only read the current frame buffer*/
+ else if( win->format == YUV420) {
+ total_size = (win->area[0].y_vir_stride * win->area[0].yact * 6);
+ } else
+ total_size = win->area[0].y_vir_stride * win->area[0].yact << 2;
if (p >= total_size)
}
+
int rk_fb_register(struct rk_lcdc_driver *dev_drv,
struct rk_lcdc_win *win, int id)
{
}
rkfb_create_sysfs(fbi);
rk_fb->fb[rk_fb->num_fb] = fbi;
- dev_info(&fb_pdev->dev, "rockchip framebuffer registerd:%s\n",
+ dev_info(fbi->dev, "rockchip framebuffer registerd:%s\n",
fbi->fix.id);
rk_fb->num_fb++;
struct fb_info *main_fbi = rk_fb->fb[0];
main_fbi->fbops->fb_open(main_fbi, 1);
#if defined(CONFIG_ROCKCHIP_IOMMU)
- if (dev_drv->iommu_enabled) {/* only alloc memory for main fb*/
+ if (dev_drv->iommu_enabled) {
mmu_dev = rockchip_get_sysmmu_device_by_compatible(dev_drv->mmu_dts_name);
if (mmu_dev) {
platform_set_sysmmu(mmu_dev, dev_drv->dev);
dev_err(dev_drv->dev, "failed to get rockchip iommu device\n");
}
#endif
- rk_fb_alloc_buffer(main_fbi, 0);
- if(support_uboot_display())
+ rk_fb_alloc_buffer(main_fbi, 0); /* only alloc memory for main fb*/
+ if(support_uboot_display()) {
+ if (dev_drv->iommu_enabled) {
+ rk_fb_copy_from_loader(main_fbi);
+ dev_drv->ops->direct_set_addr(dev_drv,0, main_fbi->fix.smem_start);
+ }
return 0;
+ }
main_fbi->fbops->fb_set_par(main_fbi);
#if defined(CONFIG_LOGO_LINUX_BMP)
if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) {
struct rk_lcdc_drv_ops {
int (*open) (struct rk_lcdc_driver * dev_drv, int layer_id, bool open);
+ int (*win_direct_en)(struct rk_lcdc_driver *dev_drv, int win_id, int en);
int (*init_lcdc) (struct rk_lcdc_driver * dev_drv);
int (*ioctl) (struct rk_lcdc_driver * dev_drv, unsigned int cmd,
unsigned long arg, int layer_id);
int blank_mode);
int (*set_par) (struct rk_lcdc_driver * dev_drv, int layer_id);
int (*pan_display) (struct rk_lcdc_driver * dev_drv, int layer_id);
+ int (*direct_set_addr)(struct rk_lcdc_driver *drv, int win_id, u32 addr);
int (*lcdc_reg_update) (struct rk_lcdc_driver * dev_drv);
- ssize_t(*get_disp_info) (struct rk_lcdc_driver * dev_drv, char *buf,
+ 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_win_state) (struct rk_lcdc_driver * dev_drv, int layer_id);