rk3288 lcdc: add support iommu

This commit is contained in:
hjc
2014-04-18 11:18:27 +08:00
parent e4147baddd
commit ee4ae20744
2 changed files with 68 additions and 109 deletions

View File

@@ -45,12 +45,10 @@
#if defined(CONFIG_ION_ROCKCHIP)
#include <linux/rockchip_ion.h>
#ifdef USE_ION_MMU
#include <linux/rockchip/iovmm.h>
#include <linux/rockchip/sysmmu.h>
#include <linux/dma-buf.h>
#endif
#endif
#define H_USE_FENCE 1
static int hdmi_switch_complete;
static struct platform_device *fb_pdev;
@@ -61,6 +59,8 @@ int (*video_data_to_mirroring)(struct fb_info *info, u32 yuv_phy[2]);
EXPORT_SYMBOL(video_data_to_mirroring);
#endif
struct rk_fb_reg_win_data g_reg_win_data[4];
static int g_first_buf = 1;
static struct rk_fb_trsm_ops *trsm_lvds_ops;
static struct rk_fb_trsm_ops *trsm_edp_ops;
@@ -997,59 +997,19 @@ void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv,
printk("error waiting on fence\n");
}
#ifdef USE_ION_MMU
static unsigned int rk_fb_map_ion_handle(struct fb_info *info,
struct rk_fb_reg_area_data *reg_area_data,
struct ion_handle *ion_handle,struct dma_buf *buf)
{
struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
reg_area_data->dma_buf = buf;
reg_area_data->attachment =
dma_buf_attach(reg_area_data->dma_buf, dev_drv->dev);
if (IS_ERR_OR_NULL(reg_area_data->attachment)) {
dev_err(dev_drv->dev, "dma_buf_attach() failed: %ld\n",
PTR_ERR(reg_area_data->attachment));
goto err_buf_map_attach;
}
reg_area_data->sg_table = dma_buf_map_attachment(reg_area_data->attachment,
DMA_BIDIRECTIONAL);
if (IS_ERR_OR_NULL(reg_area_data->sg_table)) {
dev_err(dev_drv->dev, "dma_buf_map_attachment() failed: %ld\n",
PTR_ERR(reg_area_data->sg_table));
goto err_buf_map_attachment;
}
reg_area_data->dma_addr = iovmm_map(dev_drv->dev, reg_area_data->sg_table->sgl, 0,
buf->size);
if (!reg_area_data->dma_addr || IS_ERR_VALUE(reg_area_data->dma_addr)) {
dev_err(dev_drv->dev, "iovmm_map() failed: %d\n", reg_area_data->dma_addr);
goto err_iovmm_map;
}
reg_area_data->ion_handle = ion_handle;
return reg_area_data->dma_buf->size;
err_iovmm_map:
dma_buf_unmap_attachment(reg_area_data->attachment,
reg_area_data->sg_table,DMA_BIDIRECTIONAL);
err_buf_map_attachment:
dma_buf_detach(buf, reg_area_data->attachment);
err_buf_map_attach:
return 0;
}
#ifdef CONFIG_ROCKCHIP_IOMMU
int rk_fb_sysmmu_fault_handler(struct device *dev,
enum rk_sysmmu_inttype itype, unsigned long pgtable_base,
unsigned long fault_addr,unsigned int statu)
unsigned long fault_addr,unsigned int status)
{
/*struct fb_info *fbi = dev_get_drvdata(dev);
struct fb_info *fbi = dev_get_drvdata(dev);
struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
pr_err("PAGE FAULT occurred at 0x%lx (Page table base: 0x%lx),status=%d\n",
fault_addr, pgtable_base,statu);
fault_addr, pgtable_base,status);
dev_drv->ops->dump_reg(dev_drv);
pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
BUG();*/
BUG();
return 0;
}
@@ -1060,22 +1020,13 @@ void rk_fb_free_dma_buf(struct device *dev,struct rk_fb_reg_win_data *reg_win_da
int i,index_buf;
struct rk_fb_reg_area_data *area_data;
struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
#ifdef H_USE_FENCE
for(i=0;i<RK_WIN_MAX_AREA;i++){
if(reg_win_data->reg_area_data[i].acq_fence)
sync_fence_put(reg_win_data->reg_area_data[i].acq_fence);
}
#endif
for(i=0;i<reg_win_data->area_num;i++){
area_data = &reg_win_data->reg_area_data[i];
index_buf = area_data->index_buf;
#ifdef USE_ION_MMU
iovmm_unmap(dev,area_data->dma_addr);
dma_buf_unmap_attachment(area_data->attachment, area_data->sg_table,
DMA_BIDIRECTIONAL);
dma_buf_detach(area_data->dma_buf, area_data->attachment);
dma_buf_put(area_data->dma_buf);
#endif
#ifdef CONFIG_ROCKCHIP_IOMMU
ion_unmap_iommu(dev, rk_fb->ion_client, area_data->ion_handle);
#endif
if(area_data->ion_handle != NULL)
ion_free(rk_fb->ion_client, area_data->ion_handle);
}
@@ -1152,7 +1103,6 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win,struct rk_fb_reg_win_dat
}
static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_data *regs)
{
int i,j,ret=0;
@@ -1264,9 +1214,16 @@ ext_win_exit:
#ifdef H_USE_FENCE
sw_sync_timeline_inc(dev_drv->timeline, 1);
#endif
for(i=0;i<regs->win_num;i++){
rk_fb_free_dma_buf(dev_drv->dev,&regs->reg_win_data[i]);
if(!g_first_buf){
for(i=0;i<regs->win_num;i++){
rk_fb_free_dma_buf(dev_drv->dev,&g_reg_win_data[i]);
}
}
for(i=0;i<regs->win_num;i++){
memcpy(&g_reg_win_data[i], &(regs->reg_win_data[i]), sizeof(struct rk_fb_reg_win_data));
}
g_first_buf = 0;
if (dev_drv->wait_fs == 1)
kfree(regs);
}
@@ -1344,11 +1301,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
u16 uv_x_off,uv_y_off,uv_y_act;
u8 is_pic_yuv=0;
u8 ppixel_a=0,global_a=0;
#ifdef USE_ION_MMU
struct dma_buf *buf;
#else
ion_phys_addr_t phy_addr;
#endif
reg_win_data->reg_area_data[0].smem_start = -1;
reg_win_data->area_num = 0;
if(win_par->area_par[0].phy_addr == 0){
@@ -1364,19 +1318,13 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
}
reg_win_data->area_num++;
reg_win_data->reg_area_data[i].ion_handle = hdl;
#ifndef USE_ION_MMU
#ifndef CONFIG_ROCKCHIP_IOMMU
ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
reg_win_data->reg_area_data[i].smem_start = phy_addr;
#else
buf = ion_share_dma_buf(rk_fb->ion_client, hdl);
if (IS_ERR_OR_NULL(buf)) {
dev_err(info->dev, "ion_share_dma_buf() failed\n");
goto err_share_dma_buf;
}
rk_fb_map_ion_handle(info,&reg_win_data->reg_area_data[i],hdl,buf);
reg_win_data->reg_area_data[i].smem_start =
reg_win_data->reg_area_data[i].dma_addr;
ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl,
(unsigned long *)&phy_addr, (unsigned long *)&len);
#endif
reg_win_data->reg_area_data[i].smem_start = phy_addr;
reg_win_data->area_buf_num++;
reg_win_data->reg_area_data[i].index_buf = 1;
}
@@ -1537,7 +1485,7 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
}
}
return 0;
#ifdef USE_ION_MMU
#ifdef CONFIG_ROCKCHIP_IOMMU
err_share_dma_buf:
ion_free(rk_fb->ion_client, hdl);
return -ENOMEM;
@@ -2247,6 +2195,18 @@ static int fb_setcolreg(unsigned regno,
return 0;
}
static int rk_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
struct rk_lcdc_win *win;
win = dev_drv->win[win_id];
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return dma_buf_mmap(win->area[0].dma_buf, vma, 0);
}
static struct fb_ops fb_ops = {
.owner = THIS_MODULE,
.fb_open = rk_fb_open,
@@ -2626,11 +2586,7 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
#if defined(CONFIG_ION_ROCKCHIP)
struct ion_handle *handle;
ion_phys_addr_t phy_addr;
#ifdef USE_ION_MMU
struct dma_buf *buf;
#else
size_t len;
#endif
#endif
win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
if (win_id < 0)
@@ -2647,26 +2603,25 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
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);
#ifndef USE_ION_MMU
ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
fbi->fix.smem_start = phy_addr;
fbi->fix.smem_len = len;
printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n",phy_addr);
#ifndef CONFIG_ROCKCHIP_IOMMU
ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
#else
buf = ion_share_dma_buf(rk_fb->ion_client, handle);
if (IS_ERR_OR_NULL(buf)) {
dev_err(fbi->device, "ion_share_dma_buf() failed\n");
goto err_share_dma_buf;
}
rk_fb_map_ion_handle(fbi,&dev_drv->reg_area_data,handle,buf);
fbi->fix.smem_start = dev_drv->reg_area_data.dma_addr;
fbi->fix.smem_len = buf->size;
printk(KERN_INFO "alloc_buffer:kernel_vir_addr=0x%x,mmu_vir_addr=0x%x,len=0x%x\n",
fbi->screen_base,fbi->fix.smem_start,fbi->fix.smem_len);
ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
printk("ion_phys: %x,%x\n", phy_addr, len);
ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle,
(unsigned long *)&phy_addr, (unsigned long *)&len);
printk("%s: ion_map_iommu: %x,%x\n", __func__, 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;
@@ -2714,11 +2669,11 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
}
return ret;
#ifdef USE_ION_MMU
err_share_dma_buf:
ion_free(rk_fb->ion_client, handle);
return -ENOMEM;
#endif
}
static int rk_release_fb_buffer(struct fb_info *fbi)
@@ -2845,7 +2800,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
struct fb_info *fbi;
int i = 0, ret = 0, index = 0;
#ifdef USE_ION_MMU
#ifdef CONFIG_ROCKCHIP_IOMMU
struct device *mmu_dev = NULL;
#endif
if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT)
@@ -2884,17 +2839,20 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
fbi->var.width = dev_drv->cur_screen->width;
fbi->var.height = dev_drv->cur_screen->height;
fbi->var.pixclock = dev_drv->pixclock;
#ifdef CONFIG_ROCKCHIP_IOMMU
fb_ops.fb_mmap = rk_fb_mmap;
#endif
fbi->fbops = &fb_ops;
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->pseudo_palette = dev_drv->win[i]->pseudo_pal;
if (i == 0){ /* only alloc memory for main fb*/
#ifdef USE_ION_MMU
mmu_dev =
rockchip_get_sysmmu_device_by_compatible(dev_drv->mmu_dts_name);
platform_set_sysmmu(mmu_dev, dev_drv->dev);
/*rockchip_sysmmu_set_fault_handler(dev_drv->dev,
rk_fb_sysmmu_fault_handler);*/
iovmm_activate(dev_drv->dev);
#ifdef CONFIG_ROCKCHIP_IOMMU
mmu_dev = rockchip_get_sysmmu_device_by_compatible("iommu,vopl_mmu");
if (mmu_dev) {
platform_set_sysmmu(mmu_dev, dev_drv->dev);
rockchip_sysmmu_set_fault_handler(dev_drv->dev, rk_fb_sysmmu_fault_handler);
iovmm_activate(dev_drv->dev);
}
#endif
rk_fb_alloc_buffer(fbi, rk_fb->num_fb);
}

View File

@@ -84,7 +84,7 @@
#define Y_MIRROR 2
#define X_Y_MIRROR 3
/*#define USE_ION_MMU 1*/
//#define USE_ION_MMU 1
#if defined(CONFIG_ION_ROCKCHIP)
extern struct ion_client *rockchip_ion_client_create(const char * name);
#endif
@@ -284,6 +284,7 @@ struct rk_lcdc_win_area{
#if defined(CONFIG_ION_ROCKCHIP)
struct ion_handle *ion_hdl;
int dma_buf_fd;
struct dma_buf *dma_buf;
#endif
u32 dsp_stx;
u32 dsp_sty;