X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fvideo%2Frockchip%2Frga%2Frga_drv.c;h=171b09ad7f1b7095cac1543972688b071e91dbf2;hb=c57691331e5e1bb6dc9a9863c3daf9901990098c;hp=29de27af6979d254a64bc29f75df5c7b44c7b098;hpb=2ec6a20c2e743ba924621222f7425eb918f09afa;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 29de27af6979..171b09ad7f1b 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -27,8 +27,8 @@ #include #include #include -#include -#include +//#include +//#include #include #include #include @@ -43,6 +43,11 @@ #include #include +#if defined(CONFIG_ION_ROCKCHIP) +#include +#endif + + #include "rga.h" #include "rga_reg_info.h" #include "rga_mmu_info.h" @@ -79,6 +84,9 @@ ktime_t rga_end; rga_session rga_session_global; +long (*rga_ioctl_kernel_p)(struct rga_req *); + + struct rga_drvdata { struct miscdevice miscdev; struct device dev; @@ -89,13 +97,23 @@ struct rga_drvdata { void (*rga_irq_callback)(int rga_retval); //callback function used by aync call struct wake_lock wake_lock; + struct clk *pd_rga; struct clk *aclk_rga; - struct clk *hclk_rga; - struct clk *pd_rga; + struct clk *hclk_rga; + + //#if defined(CONFIG_ION_ROCKCHIP) + struct ion_client * ion_client; + //#endif }; static struct rga_drvdata *drvdata; rga_service_info rga_service; +struct rga_mmu_buf_t rga_mmu_buf; + + +#if defined(CONFIG_ION_ROCKCHIP) +extern struct ion_client *rockchip_ion_client_create(const char * name); +#endif static int rga_blit_async(rga_session *session, struct rga_req *req); static void rga_del_running_list(void); @@ -104,7 +122,7 @@ static void rga_try_set_reg(void); /* Logging */ -#define RGA_DEBUG 0 +#define RGA_DEBUG 1 #if RGA_DEBUG #define DBG(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args) #define ERR(format, args...) printk(KERN_ERR "%s: " format, DRIVER_NAME, ## args) @@ -126,8 +144,8 @@ static void print_info(struct rga_req *req) req->src.act_w, req->src.act_h, req->src.vir_w, req->src.vir_h); printk("src : x_off = %.8x y_off = %.8x\n", req->src.x_offset, req->src.y_offset); - printk("dst : yrgb_addr = %.8x, dst.uv_addr = %.8x, dst.v_addr = %.8x\n", - req->dst.yrgb_addr, req->dst.uv_addr, req->dst.v_addr); + printk("dst : yrgb_addr = %.8x, dst.uv_addr = %.8x, dst.v_addr = %.8x, format = %d\n", + req->dst.yrgb_addr, req->dst.uv_addr, req->dst.v_addr, req->dst.format); printk("dst : x_off = %.8x y_off = %.8x\n", req->dst.x_offset, req->dst.y_offset); printk("dst : act_w = %d, act_h = %d, vir_w = %d, vir_h = %d\n", req->dst.act_w, req->dst.act_h, req->dst.vir_w, req->dst.vir_h); @@ -135,6 +153,8 @@ static void print_info(struct rga_req *req) printk("clip.xmin = %d, clip.xmax = %d. clip.ymin = %d, clip.ymax = %d\n", req->clip.xmin, req->clip.xmax, req->clip.ymin, req->clip.ymax); + printk("mmu_flag = %.8x\n", req->mmu_info.mmu_flag); + //printk("alpha_rop_flag = %.8x\n", req->alpha_rop_flag); //printk("alpha_rop_mode = %.8x\n", req->alpha_rop_mode); //printk("PD_mode = %.8x\n", req->PD_mode); @@ -231,18 +251,18 @@ static void rga_dump(void) printk("task_running %d\n", running); list_for_each_entry_safe(reg, reg_tmp, &session->waiting, session_link) { - printk("waiting register set 0x%.8x\n", (unsigned int)reg); + printk("waiting register set 0x%.lu\n", (unsigned long)reg); } list_for_each_entry_safe(reg, reg_tmp, &session->running, session_link) { - printk("running register set 0x%.8x\n", (unsigned int)reg); + printk("running register set 0x%.lu\n", (unsigned long)reg); } } } static inline void rga_queue_power_off_work(void) { - queue_delayed_work(system_nrt_wq, &drvdata->power_off_work, RGA_POWER_OFF_DELAY); + queue_delayed_work(system_wq, &drvdata->power_off_work, RGA_POWER_OFF_DELAY); } /* Caller must hold rga_service.lock */ @@ -259,9 +279,9 @@ static void rga_power_on(void) if (rga_service.enable) return; - clk_enable(drvdata->aclk_rga); - clk_enable(drvdata->hclk_rga); - clk_enable(drvdata->pd_rga); + clk_prepare_enable(drvdata->aclk_rga); + clk_prepare_enable(drvdata->hclk_rga); + //clk_prepare_enable(drvdata->pd_rga); wake_lock(&drvdata->wake_lock); rga_service.enable = true; } @@ -283,9 +303,9 @@ static void rga_power_off(void) rga_dump(); } - clk_disable(drvdata->pd_rga); - clk_disable(drvdata->aclk_rga); - clk_disable(drvdata->hclk_rga); + //clk_disable_unprepare(drvdata->pd_rga); + clk_disable_unprepare(drvdata->aclk_rga); + clk_disable_unprepare(drvdata->hclk_rga); wake_unlock(&drvdata->wake_lock); rga_service.enable = false; } @@ -297,896 +317,976 @@ static void rga_power_off_work(struct work_struct *work) mutex_unlock(&rga_service.lock); } else { /* Come back later if the device is busy... */ - rga_queue_power_off_work(); - } -} - -static int rga_flush(rga_session *session, unsigned long arg) -{ - int ret = 0; - int ret_timeout; - - #if RGA_TEST_FLUSH_TIME - ktime_t start; - ktime_t end; - start = ktime_get(); - #endif - - ret_timeout = wait_event_timeout(session->wait, atomic_read(&session->done), RGA_TIMEOUT_DELAY); - - if (unlikely(ret_timeout < 0)) { - //pr_err("flush pid %d wait task ret %d\n", session->pid, ret); - mutex_lock(&rga_service.lock); - rga_del_running_list(); - mutex_unlock(&rga_service.lock); - ret = ret_timeout; - } else if (0 == ret_timeout) { - //pr_err("flush pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running)); - //printk("bus = %.8x\n", rga_read(RGA_INT)); - mutex_lock(&rga_service.lock); - rga_del_running_list_timeout(); - rga_try_set_reg(); - mutex_unlock(&rga_service.lock); - ret = -ETIMEDOUT; - } - - #if RGA_TEST_FLUSH_TIME - end = ktime_get(); - end = ktime_sub(end, start); - printk("one flush wait time %d\n", (int)ktime_to_us(end)); - #endif - - return ret; -} - - -static int rga_get_result(rga_session *session, unsigned long arg) -{ - //printk("rga_get_result %d\n",drvdata->rga_result); - - int ret = 0; - - int num_done; - - num_done = atomic_read(&session->num_done); - - if (unlikely(copy_to_user((void __user *)arg, &num_done, sizeof(int)))) { - printk("copy_to_user failed\n"); - ret = -EFAULT; - } - return ret; -} - - -static int rga_check_param(const struct rga_req *req) -{ - /*RGA can support up to 8192*8192 resolution in RGB format,but we limit the image size to 8191*8191 here*/ - //check src width and height - - if(!((req->render_mode == color_fill_mode) || (req->render_mode == line_point_drawing_mode))) - { - if (unlikely((req->src.act_w <= 0) || (req->src.act_w > 8191) || (req->src.act_h <= 0) || (req->src.act_h > 8191))) - { - printk("invalid source resolution act_w = %d, act_h = %d\n", req->src.act_w, req->src.act_h); - return -EINVAL; - } - } - - if(!((req->render_mode == color_fill_mode) || (req->render_mode == line_point_drawing_mode))) - { - if (unlikely((req->src.vir_w <= 0) || (req->src.vir_w > 8191) || (req->src.vir_h <= 0) || (req->src.vir_h > 8191))) - { - printk("invalid source resolution vir_w = %d, vir_h = %d\n", req->src.vir_w, req->src.vir_h); - return -EINVAL; - } - } - - //check dst width and height - if (unlikely((req->dst.act_w <= 0) || (req->dst.act_w > 2048) || (req->dst.act_h <= 0) || (req->dst.act_h > 2048))) - { - printk("invalid destination resolution act_w = %d, act_h = %d\n", req->dst.act_w, req->dst.act_h); - return -EINVAL; - } - - if (unlikely((req->dst.vir_w <= 0) || (req->dst.vir_w > 4096) || (req->dst.vir_h <= 0) || (req->dst.vir_h > 2048))) - { - printk("invalid destination resolution vir_w = %d, vir_h = %d\n", req->dst.vir_w, req->dst.vir_h); - return -EINVAL; - } - - //check src_vir_w - if(unlikely(req->src.vir_w < req->src.act_w)){ - printk("invalid src_vir_w act_w = %d, vir_w = %d\n", req->src.act_w, req->src.vir_w); - return -EINVAL; - } - - //check dst_vir_w - if(unlikely(req->dst.vir_w < req->dst.act_w)){ - if(req->rotate_mode != 1) - { - printk("invalid dst_vir_w act_h = %d, vir_h = %d\n", req->dst.act_w, req->dst.vir_w); - return -EINVAL; - } - } - - return 0; -} - -static void rga_copy_reg(struct rga_reg *reg, uint32_t offset) -{ - uint32_t i; - uint32_t *cmd_buf; - uint32_t *reg_p; - - if(atomic_read(®->session->task_running) != 0) - { - printk(KERN_ERR "task_running is no zero\n"); - } - - atomic_add(1, &rga_service.cmd_num); - atomic_add(1, ®->session->task_running); - - cmd_buf = (uint32_t *)rga_service.cmd_buff + offset*28; - reg_p = (uint32_t *)reg->cmd_reg; - - for(i=0; i<28; i++) - { - cmd_buf[i] = reg_p[i]; - } - - dsb(); -} - - -static struct rga_reg * rga_reg_init(rga_session *session, struct rga_req *req) -{ - uint32_t ret; - struct rga_reg *reg = kzalloc(sizeof(struct rga_reg), GFP_KERNEL); - if (NULL == reg) { - pr_err("kmalloc fail in rga_reg_init\n"); - return NULL; - } - - reg->session = session; - INIT_LIST_HEAD(®->session_link); - INIT_LIST_HEAD(®->status_link); - - reg->MMU_base = NULL; - - if (req->mmu_info.mmu_en) - { - ret = rga_set_mmu_info(reg, req); - if(ret < 0) - { - printk("%s, [%d] set mmu info error \n", __FUNCTION__, __LINE__); - if(reg != NULL) - { - kfree(reg); - } - return NULL; - } - } - - if(RGA_gen_reg_info(req, (uint8_t *)reg->cmd_reg) == -1) - { - printk("gen reg info error\n"); - if(reg != NULL) - { - kfree(reg); - } - return NULL; - } - - mutex_lock(&rga_service.lock); - list_add_tail(®->status_link, &rga_service.waiting); - list_add_tail(®->session_link, &session->waiting); - mutex_unlock(&rga_service.lock); - - return reg; -} - -static struct rga_reg * rga_reg_init_2(rga_session *session, struct rga_req *req0, struct rga_req *req1) -{ - uint32_t ret; - - struct rga_reg *reg0, *reg1; - - reg0 = NULL; - reg1 = NULL; - - do - { - reg0 = kzalloc(sizeof(struct rga_reg), GFP_KERNEL); - if (NULL == reg0) { - pr_err("%s [%d] kmalloc fail in rga_reg_init\n", __FUNCTION__, __LINE__); - break; - } - - reg1 = kzalloc(sizeof(struct rga_reg), GFP_KERNEL); - if (NULL == reg1) { - pr_err("%s [%d] kmalloc fail in rga_reg_init\n", __FUNCTION__, __LINE__); - break; - } - - reg0->session = session; - INIT_LIST_HEAD(®0->session_link); - INIT_LIST_HEAD(®0->status_link); - - reg1->session = session; - INIT_LIST_HEAD(®1->session_link); - INIT_LIST_HEAD(®1->status_link); - - if(req0->mmu_info.mmu_en) - { - ret = rga_set_mmu_info(reg0, req0); - if(ret < 0) { - printk("%s, [%d] set mmu info error \n", __FUNCTION__, __LINE__); - break; - } - } - - RGA_gen_reg_info(req0, (uint8_t *)reg0->cmd_reg); - - if(req1->mmu_info.mmu_en) - { - ret = rga_set_mmu_info(reg1, req1); - if(ret < 0) { - printk("%s, [%d] set mmu info error \n", __FUNCTION__, __LINE__); - break; - } - } - - RGA_gen_reg_info(req1, (uint8_t *)reg1->cmd_reg); - - mutex_lock(&rga_service.lock); - list_add_tail(®0->status_link, &rga_service.waiting); - list_add_tail(®0->session_link, &session->waiting); - list_add_tail(®1->status_link, &rga_service.waiting); - list_add_tail(®1->session_link, &session->waiting); - mutex_unlock(&rga_service.lock); - - return reg1; - } - while(0); - - if(reg0 != NULL) { - kfree(reg0); - } - - if(reg1 != NULL) { - kfree(reg1); - } - - return NULL; -} - -/* Caller must hold rga_service.lock */ -static void rga_reg_deinit(struct rga_reg *reg) -{ - list_del_init(®->session_link); - list_del_init(®->status_link); - kfree(reg); -} - -/* Caller must hold rga_service.lock */ -static void rga_reg_from_wait_to_run(struct rga_reg *reg) -{ - list_del_init(®->status_link); - list_add_tail(®->status_link, &rga_service.running); - - list_del_init(®->session_link); - list_add_tail(®->session_link, ®->session->running); -} - -/* Caller must hold rga_service.lock */ -static void rga_service_session_clear(rga_session *session) -{ - struct rga_reg *reg, *n; - - list_for_each_entry_safe(reg, n, &session->waiting, session_link) - { - rga_reg_deinit(reg); - } - - list_for_each_entry_safe(reg, n, &session->running, session_link) - { - rga_reg_deinit(reg); - } -} - -/* Caller must hold rga_service.lock */ -static void rga_try_set_reg(void) -{ - struct rga_reg *reg ; - - if (list_empty(&rga_service.running)) - { - if (!list_empty(&rga_service.waiting)) - { - /* RGA is idle */ - reg = list_entry(rga_service.waiting.next, struct rga_reg, status_link); - - rga_power_on(); - udelay(1); - - rga_copy_reg(reg, 0); - rga_reg_from_wait_to_run(reg); - - dmac_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[28]); - outer_flush_range(virt_to_phys(&rga_service.cmd_buff[0]),virt_to_phys(&rga_service.cmd_buff[28])); - - #if defined(CONFIG_ARCH_RK30) - rga_soft_reset(); + + rga_queue_power_off_work(); + } +} + +static int rga_flush(rga_session *session, unsigned long arg) +{ + int ret = 0; + int ret_timeout; + + #if RGA_TEST_FLUSH_TIME + ktime_t start; + ktime_t end; + start = ktime_get(); + #endif + + ret_timeout = wait_event_timeout(session->wait, atomic_read(&session->done), RGA_TIMEOUT_DELAY); + + if (unlikely(ret_timeout < 0)) { + //pr_err("flush pid %d wait task ret %d\n", session->pid, ret); + mutex_lock(&rga_service.lock); + rga_del_running_list(); + mutex_unlock(&rga_service.lock); + ret = ret_timeout; + } else if (0 == ret_timeout) { + //pr_err("flush pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running)); + //printk("bus = %.8x\n", rga_read(RGA_INT)); + mutex_lock(&rga_service.lock); + rga_del_running_list_timeout(); + rga_try_set_reg(); + mutex_unlock(&rga_service.lock); + ret = -ETIMEDOUT; + } + + #if RGA_TEST_FLUSH_TIME + end = ktime_get(); + end = ktime_sub(end, start); + printk("one flush wait time %d\n", (int)ktime_to_us(end)); + #endif + + return ret; +} + + +static int rga_get_result(rga_session *session, unsigned long arg) +{ + //printk("rga_get_result %d\n",drvdata->rga_result); + + int ret = 0; + + int num_done; + + num_done = atomic_read(&session->num_done); + + if (unlikely(copy_to_user((void __user *)arg, &num_done, sizeof(int)))) { + printk("copy_to_user failed\n"); + ret = -EFAULT; + } + return ret; +} + + +static int rga_check_param(const struct rga_req *req) +{ + /*RGA can support up to 8192*8192 resolution in RGB format,but we limit the image size to 8191*8191 here*/ + //check src width and height + + if(!((req->render_mode == color_fill_mode) || (req->render_mode == line_point_drawing_mode))) + { + if (unlikely((req->src.act_w <= 0) || (req->src.act_w > 8191) || (req->src.act_h <= 0) || (req->src.act_h > 8191))) + { + printk("invalid source resolution act_w = %d, act_h = %d\n", req->src.act_w, req->src.act_h); + return -EINVAL; + } + } + + if(!((req->render_mode == color_fill_mode) || (req->render_mode == line_point_drawing_mode))) + { + if (unlikely((req->src.vir_w <= 0) || (req->src.vir_w > 8191) || (req->src.vir_h <= 0) || (req->src.vir_h > 8191))) + { + printk("invalid source resolution vir_w = %d, vir_h = %d\n", req->src.vir_w, req->src.vir_h); + return -EINVAL; + } + } + + //check dst width and height + if (unlikely((req->dst.act_w <= 0) || (req->dst.act_w > 2048) || (req->dst.act_h <= 0) || (req->dst.act_h > 2048))) + { + printk("invalid destination resolution act_w = %d, act_h = %d\n", req->dst.act_w, req->dst.act_h); + return -EINVAL; + } + + if (unlikely((req->dst.vir_w <= 0) || (req->dst.vir_w > 4096) || (req->dst.vir_h <= 0) || (req->dst.vir_h > 2048))) + { + printk("invalid destination resolution vir_w = %d, vir_h = %d\n", req->dst.vir_w, req->dst.vir_h); + return -EINVAL; + } + + //check src_vir_w + if(unlikely(req->src.vir_w < req->src.act_w)){ + printk("invalid src_vir_w act_w = %d, vir_w = %d\n", req->src.act_w, req->src.vir_w); + return -EINVAL; + } + + //check dst_vir_w + if(unlikely(req->dst.vir_w < req->dst.act_w)){ + if(req->rotate_mode != 1) + { + printk("invalid dst_vir_w act_h = %d, vir_h = %d\n", req->dst.act_w, req->dst.vir_w); + return -EINVAL; + } + } + + return 0; +} + +static void rga_copy_reg(struct rga_reg *reg, uint32_t offset) +{ + uint32_t i; + uint32_t *cmd_buf; + uint32_t *reg_p; + + if(atomic_read(®->session->task_running) != 0) + { + printk(KERN_ERR "task_running is no zero\n"); + } + + atomic_add(1, &rga_service.cmd_num); + atomic_add(1, ®->session->task_running); + + cmd_buf = (uint32_t *)rga_service.cmd_buff + offset*32; + reg_p = (uint32_t *)reg->cmd_reg; + + for(i=0; i<32; i++) + cmd_buf[i] = reg_p[i]; + +} + + +static struct rga_reg * rga_reg_init(rga_session *session, struct rga_req *req) +{ + int32_t ret; + struct rga_reg *reg = kzalloc(sizeof(struct rga_reg), GFP_KERNEL); + if (NULL == reg) { + pr_err("kmalloc fail in rga_reg_init\n"); + return NULL; + } + + reg->session = session; + INIT_LIST_HEAD(®->session_link); + INIT_LIST_HEAD(®->status_link); + + reg->MMU_base = NULL; + + if (req->mmu_info.mmu_en) + { + ret = rga_set_mmu_info(reg, req); + if(ret < 0) + { + printk("%s, [%d] set mmu info error \n", __FUNCTION__, __LINE__); + if(reg != NULL) + { + kfree(reg); + } + return NULL; + } + } + + if(RGA_gen_reg_info(req, (uint8_t *)reg->cmd_reg) == -1) + { + printk("gen reg info error\n"); + if(reg != NULL) + { + kfree(reg); + } + return NULL; + } + + mutex_lock(&rga_service.lock); + list_add_tail(®->status_link, &rga_service.waiting); + list_add_tail(®->session_link, &session->waiting); + mutex_unlock(&rga_service.lock); + + return reg; +} + +static struct rga_reg * rga_reg_init_2(rga_session *session, struct rga_req *req0, struct rga_req *req1) +{ + int32_t ret; + + struct rga_reg *reg0, *reg1; + + reg0 = NULL; + reg1 = NULL; + + do + { + reg0 = kzalloc(sizeof(struct rga_reg), GFP_KERNEL); + if (NULL == reg0) { + pr_err("%s [%d] kmalloc fail in rga_reg_init\n", __FUNCTION__, __LINE__); + break; + } + + reg1 = kzalloc(sizeof(struct rga_reg), GFP_KERNEL); + if (NULL == reg1) { + pr_err("%s [%d] kmalloc fail in rga_reg_init\n", __FUNCTION__, __LINE__); + break; + } + + reg0->session = session; + INIT_LIST_HEAD(®0->session_link); + INIT_LIST_HEAD(®0->status_link); + + reg1->session = session; + INIT_LIST_HEAD(®1->session_link); + INIT_LIST_HEAD(®1->status_link); + + req0->mmu_info.mmu_flag &= (~(1 << 10)); + + if(req0->mmu_info.mmu_en) + { + ret = rga_set_mmu_info(reg0, req0); + if(ret < 0) { + printk("%s, [%d] set mmu info error \n", __FUNCTION__, __LINE__); + break; + } + } + + RGA_gen_reg_info(req0, (uint8_t *)reg0->cmd_reg); + + req1->mmu_info.mmu_flag &= (~(1 << 8)); + + if(req1->mmu_info.mmu_en) + { + ret = rga_set_mmu_info(reg1, req1); + if(ret < 0) { + printk("%s, [%d] set mmu info error \n", __FUNCTION__, __LINE__); + break; + } + } + + RGA_gen_reg_info(req1, (uint8_t *)reg1->cmd_reg); + + mutex_lock(&rga_service.lock); + list_add_tail(®0->status_link, &rga_service.waiting); + list_add_tail(®0->session_link, &session->waiting); + list_add_tail(®1->status_link, &rga_service.waiting); + list_add_tail(®1->session_link, &session->waiting); + mutex_unlock(&rga_service.lock); + + return reg1; + } + while(0); + + if(reg0 != NULL) { + kfree(reg0); + } + + if(reg1 != NULL) { + kfree(reg1); + } + + return NULL; +} + +/* Caller must hold rga_service.lock */ +static void rga_reg_deinit(struct rga_reg *reg) +{ + list_del_init(®->session_link); + list_del_init(®->status_link); + kfree(reg); +} + +/* Caller must hold rga_service.lock */ +static void rga_reg_from_wait_to_run(struct rga_reg *reg) +{ + list_del_init(®->status_link); + list_add_tail(®->status_link, &rga_service.running); + + list_del_init(®->session_link); + list_add_tail(®->session_link, ®->session->running); +} + +/* Caller must hold rga_service.lock */ +static void rga_service_session_clear(rga_session *session) +{ + struct rga_reg *reg, *n; + + list_for_each_entry_safe(reg, n, &session->waiting, session_link) + { + rga_reg_deinit(reg); + } + + list_for_each_entry_safe(reg, n, &session->running, session_link) + { + rga_reg_deinit(reg); + } +} + +/* Caller must hold rga_service.lock */ +static void rga_try_set_reg(void) +{ + struct rga_reg *reg ; + + if (list_empty(&rga_service.running)) + { + if (!list_empty(&rga_service.waiting)) + { + /* RGA is idle */ + reg = list_entry(rga_service.waiting.next, struct rga_reg, status_link); + + rga_power_on(); + udelay(1); + + rga_copy_reg(reg, 0); + rga_reg_from_wait_to_run(reg); + + #ifdef CONFIG_ARM + dmac_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[32]); + outer_flush_range(virt_to_phys(&rga_service.cmd_buff[0]),virt_to_phys(&rga_service.cmd_buff[32])); + #elif defined(CONFIG_ARM64) + __dma_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[32]); #endif - - rga_write(0x0, RGA_SYS_CTRL); - rga_write(0, RGA_MMU_CTRL); - - /* CMD buff */ - rga_write(virt_to_phys(rga_service.cmd_buff), RGA_CMD_ADDR); - -#if RGA_TEST - { - //printk(KERN_DEBUG "cmd_addr = %.8x\n", rga_read(RGA_CMD_ADDR)); - uint32_t i; - uint32_t *p; - p = rga_service.cmd_buff; - printk("CMD_REG\n"); - for (i=0; i<7; i++) - printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); - } -#endif - - /* master mode */ - rga_write((0x1<<2)|(0x1<<3), RGA_SYS_CTRL); - - /* All CMD finish int */ - rga_write(rga_read(RGA_INT)|(0x1<<10)|(0x1<<8), RGA_INT); - - #if RGA_TEST_TIME - rga_start = ktime_get(); - #endif - - /* Start proc */ - atomic_set(®->session->done, 0); - rga_write(0x1, RGA_CMD_CTRL); - -#if RGA_TEST - { - uint32_t i; - printk("CMD_READ_BACK_REG\n"); - for (i=0; i<7; i++) - printk("%.8x %.8x %.8x %.8x\n", rga_read(0x100 + i*16 + 0), - rga_read(0x100 + i*16 + 4), rga_read(0x100 + i*16 + 8), rga_read(0x100 + i*16 + 12)); - } -#endif - } - } -} - - - - -/* Caller must hold rga_service.lock */ -static void rga_del_running_list(void) -{ - struct rga_reg *reg; - - while(!list_empty(&rga_service.running)) - { - reg = list_entry(rga_service.running.next, struct rga_reg, status_link); - - if(reg->MMU_base != NULL) - { - kfree(reg->MMU_base); - reg->MMU_base = NULL; - } - atomic_sub(1, ®->session->task_running); - atomic_sub(1, &rga_service.total_running); - - if(list_empty(®->session->waiting)) - { - atomic_set(®->session->done, 1); - wake_up(®->session->wait); - } - - rga_reg_deinit(reg); - } -} - -/* Caller must hold rga_service.lock */ -static void rga_del_running_list_timeout(void) -{ - struct rga_reg *reg; - - while(!list_empty(&rga_service.running)) - { - reg = list_entry(rga_service.running.next, struct rga_reg, status_link); - - if(reg->MMU_base != NULL) - { - kfree(reg->MMU_base); - } - - atomic_sub(1, ®->session->task_running); - atomic_sub(1, &rga_service.total_running); - - //printk("RGA soft reset for timeout process\n"); - rga_soft_reset(); - - - #if 0 - printk("RGA_INT is %.8x\n", rga_read(RGA_INT)); - printk("reg->session->task_running = %d\n", atomic_read(®->session->task_running)); - printk("rga_service.total_running = %d\n", atomic_read(&rga_service.total_running)); - - print_info(®->req); - - { - uint32_t *p, i; - p = reg->cmd_reg; - for (i=0; i<7; i++) - printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); - - } - #endif - - if(list_empty(®->session->waiting)) - { - atomic_set(®->session->done, 1); - wake_up(®->session->wait); - } - - rga_reg_deinit(reg); - } -} - - -static void rga_mem_addr_sel(struct rga_req *req) -{ - switch(req->src.format) - { - case RK_FORMAT_YCbCr_422_SP: - break; - case RK_FORMAT_YCbCr_422_P : - break; - case RK_FORMAT_YCbCr_420_SP : - if((req->src.yrgb_addr > 0xc0000000) && (req->src.uv_addr > 0xc0000000) - && (req->dst.yrgb_addr > 0xc0000000)) - { - req->src.yrgb_addr = req->src.yrgb_addr - 0x60000000; - req->src.uv_addr = req->src.uv_addr - 0x60000000; - req->dst.yrgb_addr = req->dst.yrgb_addr - 0x60000000; - req->mmu_info.mmu_en = 0; - req->mmu_info.mmu_flag &= 0xfffe; - } - break; - case RK_FORMAT_YCbCr_420_P : - break; - case RK_FORMAT_YCrCb_422_SP : - break; - case RK_FORMAT_YCrCb_422_P : - break; - case RK_FORMAT_YCrCb_420_SP : - break; - case RK_FORMAT_YCrCb_420_P : - break; - default : - break; - } - -} - - -static int rga_blit(rga_session *session, struct rga_req *req) -{ - int ret = -1; - int num = 0; - struct rga_reg *reg; - struct rga_req req2; - - uint32_t saw, sah, daw, dah; - - saw = req->src.act_w; - sah = req->src.act_h; - daw = req->dst.act_w; - dah = req->dst.act_h; - - do - { - if((req->render_mode == bitblt_mode) && (((saw>>1) >= daw) || ((sah>>1) >= dah))) - { - /* generate 2 cmd for pre scale */ - - ret = rga_check_param(req); - if(ret == -EINVAL) { - printk("req 0 argument is inval\n"); - break; - } - - ret = RGA_gen_two_pro(req, &req2); - if(ret == -EINVAL) { - break; - } - - ret = rga_check_param(req); - if(ret == -EINVAL) { - printk("req 1 argument is inval\n"); - break; - } - - ret = rga_check_param(&req2); - if(ret == -EINVAL) { - printk("req 2 argument is inval\n"); - break; - } - - reg = rga_reg_init_2(session, req, &req2); - if(reg == NULL) { - break; - } - num = 2; - - } - else - { - /* check value if legal */ - ret = rga_check_param(req); - if(ret == -EINVAL) { - printk("req argument is inval\n"); - break; - } - - if(req->render_mode == bitblt_mode) - { - rga_mem_addr_sel(req); - } - - reg = rga_reg_init(session, req); - if(reg == NULL) { - break; - } - num = 1; - } - - mutex_lock(&rga_service.lock); - atomic_add(num, &rga_service.total_running); - rga_try_set_reg(); - mutex_unlock(&rga_service.lock); - - return 0; - } - while(0); - - return -EFAULT; -} - -static int rga_blit_async(rga_session *session, struct rga_req *req) -{ - int ret = -1; - - #if RGA_TEST - printk("*** rga_blit_async proc ***\n"); - print_info(req); - #endif - atomic_set(&session->done, 0); - ret = rga_blit(session, req); - - return ret; -} - -static int rga_blit_sync(rga_session *session, struct rga_req *req) -{ - int ret = -1; - int ret_timeout = 0; - - #if RGA_TEST - printk("*** rga_blit_sync proc ***\n"); - print_info(req); + + rga_soft_reset(); + + rga_write(0x0, RGA_SYS_CTRL); + rga_write(0, RGA_MMU_CTRL); + + /* CMD buff */ + rga_write(virt_to_phys(rga_service.cmd_buff), RGA_CMD_ADDR); + +#if RGA_TEST + { + //printk(KERN_DEBUG "cmd_addr = %.8x\n", rga_read(RGA_CMD_ADDR)); + uint32_t i; + uint32_t *p; + p = rga_service.cmd_buff; + printk("CMD_REG\n"); + for (i=0; i<7; i++) + printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); + printk("%.8x %.8x\n", p[0 + i*4], p[1+i*4]); + } +#endif + + /* master mode */ + rga_write((0x1<<2)|(0x1<<3), RGA_SYS_CTRL); + + /* All CMD finish int */ + rga_write(rga_read(RGA_INT)|(0x1<<10)|(0x1<<8), RGA_INT); + + #if RGA_TEST_TIME + rga_start = ktime_get(); + #endif + + /* Start proc */ + atomic_set(®->session->done, 0); + rga_write(0x1, RGA_CMD_CTRL); + +#if RGA_TEST + { + uint32_t i; + printk("CMD_READ_BACK_REG\n"); + for (i=0; i<7; i++) + printk("%.8x %.8x %.8x %.8x\n", rga_read(0x100 + i*16 + 0), + rga_read(0x100 + i*16 + 4), rga_read(0x100 + i*16 + 8), rga_read(0x100 + i*16 + 12)); + printk("%.8x %.8x\n", rga_read(0x100 + i*16 + 0), rga_read(0x100 + i*16 + 4)); + } +#endif + } + } +} + + + + +/* Caller must hold rga_service.lock */ +static void rga_del_running_list(void) +{ + struct rga_reg *reg; + + while(!list_empty(&rga_service.running)) + { + reg = list_entry(rga_service.running.next, struct rga_reg, status_link); + + if(reg->MMU_len != 0) + { + if (rga_mmu_buf.back + reg->MMU_len > 2*rga_mmu_buf.size) + rga_mmu_buf.back = reg->MMU_len + rga_mmu_buf.size; + else + rga_mmu_buf.back += reg->MMU_len; + } + + atomic_sub(1, ®->session->task_running); + atomic_sub(1, &rga_service.total_running); + + if(list_empty(®->session->waiting)) + { + atomic_set(®->session->done, 1); + wake_up(®->session->wait); + } + + rga_reg_deinit(reg); + } +} + +/* Caller must hold rga_service.lock */ +static void rga_del_running_list_timeout(void) +{ + struct rga_reg *reg; + + while(!list_empty(&rga_service.running)) + { + reg = list_entry(rga_service.running.next, struct rga_reg, status_link); + + if(reg->MMU_len != 0) + { + if (rga_mmu_buf.back + reg->MMU_len > 2*rga_mmu_buf.size) + rga_mmu_buf.back = reg->MMU_len + rga_mmu_buf.size; + else + rga_mmu_buf.back += reg->MMU_len; + } + + atomic_sub(1, ®->session->task_running); + atomic_sub(1, &rga_service.total_running); + + //printk("RGA soft reset for timeout process\n"); + rga_soft_reset(); + + + #if 0 + printk("RGA_INT is %.8x\n", rga_read(RGA_INT)); + printk("reg->session->task_running = %d\n", atomic_read(®->session->task_running)); + printk("rga_service.total_running = %d\n", atomic_read(&rga_service.total_running)); + + print_info(®->req); + + { + uint32_t *p, i; + p = reg->cmd_reg; + for (i=0; i<7; i++) + printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); + + } + #endif + + if(list_empty(®->session->waiting)) + { + atomic_set(®->session->done, 1); + wake_up(®->session->wait); + } + + rga_reg_deinit(reg); + } +} + + +static void rga_mem_addr_sel(struct rga_req *req) +{ + switch(req->src.format) + { + case RK_FORMAT_YCbCr_422_SP: + break; + case RK_FORMAT_YCbCr_422_P : + break; + case RK_FORMAT_YCbCr_420_SP : + if((req->src.yrgb_addr > 0xc0000000) && (req->src.uv_addr > 0xc0000000) + && (req->dst.yrgb_addr > 0xc0000000)) + { + req->src.yrgb_addr = req->src.yrgb_addr - 0x60000000; + req->src.uv_addr = req->src.uv_addr - 0x60000000; + req->dst.yrgb_addr = req->dst.yrgb_addr - 0x60000000; + req->mmu_info.mmu_en = 0; + req->mmu_info.mmu_flag &= 0xfffe; + } + break; + case RK_FORMAT_YCbCr_420_P : + break; + case RK_FORMAT_YCrCb_422_SP : + break; + case RK_FORMAT_YCrCb_422_P : + break; + case RK_FORMAT_YCrCb_420_SP : + break; + case RK_FORMAT_YCrCb_420_P : + break; + default : + break; + } + +} + +static int rga_convert_dma_buf(struct rga_req *req) +{ + struct ion_handle *hdl; + ion_phys_addr_t phy_addr; + size_t len; + int ret; + uint32_t src_offset, dst_offset; + + req->sg_src = NULL; + req->sg_dst = NULL; + + src_offset = req->line_draw_info.flag; + dst_offset = req->line_draw_info.line_width; + + if(req->src.yrgb_addr) { + hdl = ion_import_dma_buf(drvdata->ion_client, req->src.yrgb_addr); + if (IS_ERR(hdl)) { + ret = PTR_ERR(hdl); + printk("RGA2 ERROR ion buf handle\n"); + return ret; + } + if ((req->mmu_info.mmu_flag >> 8) & 1) { + req->sg_src = ion_sg_table(drvdata->ion_client, hdl); + req->src.yrgb_addr = req->src.uv_addr; + req->src.uv_addr = req->src.yrgb_addr + (req->src.vir_w * req->src.vir_h); + req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h)/4; + } + else { + ion_phys(drvdata->ion_client, hdl, &phy_addr, &len); + req->src.yrgb_addr = phy_addr + src_offset; + req->src.uv_addr = req->src.yrgb_addr + (req->src.vir_w * req->src.vir_h); + req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h)/4; + } + ion_free(drvdata->ion_client, hdl); + } + else { + req->src.yrgb_addr = req->src.uv_addr; + req->src.uv_addr = req->src.yrgb_addr + (req->src.vir_w * req->src.vir_h); + req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h)/4; + } + + if(req->dst.yrgb_addr) { + hdl = ion_import_dma_buf(drvdata->ion_client, req->dst.yrgb_addr); + if (IS_ERR(hdl)) { + ret = PTR_ERR(hdl); + printk("RGA2 ERROR ion buf handle\n"); + return ret; + } + if ((req->mmu_info.mmu_flag >> 10) & 1) { + req->sg_dst = ion_sg_table(drvdata->ion_client, hdl); + req->dst.yrgb_addr = req->dst.uv_addr; + req->dst.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h); + req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4; + } + else { + ion_phys(drvdata->ion_client, hdl, &phy_addr, &len); + req->dst.yrgb_addr = phy_addr + dst_offset; + req->dst.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h); + req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4; + } + ion_free(drvdata->ion_client, hdl); + } + else { + req->dst.yrgb_addr = req->dst.uv_addr; + req->dst.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h); + req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4; + } + + return 0; +} + + +static int rga_blit(rga_session *session, struct rga_req *req) +{ + int ret = -1; + int num = 0; + struct rga_reg *reg; + struct rga_req req2; + + uint32_t saw, sah, daw, dah; + + saw = req->src.act_w; + sah = req->src.act_h; + daw = req->dst.act_w; + dah = req->dst.act_h; + + #if RGA_TEST + print_info(req); + #endif + + if(rga_convert_dma_buf(req)) { + printk("RGA : DMA buf copy error\n"); + return -EFAULT; + } + + do { + if((req->render_mode == bitblt_mode) && (((saw>>1) >= daw) || ((sah>>1) >= dah))) { + /* generate 2 cmd for pre scale */ + + ret = rga_check_param(req); + if(ret == -EINVAL) { + printk("req 0 argument is inval\n"); + break; + } + + ret = RGA_gen_two_pro(req, &req2); + if(ret == -EINVAL) { + break; + } + + ret = rga_check_param(req); + if(ret == -EINVAL) { + printk("req 1 argument is inval\n"); + break; + } + + ret = rga_check_param(&req2); + if(ret == -EINVAL) { + printk("req 2 argument is inval\n"); + break; + } + + reg = rga_reg_init_2(session, req, &req2); + if(reg == NULL) { + break; + } + num = 2; + + } + else { + /* check value if legal */ + ret = rga_check_param(req); + if(ret == -EINVAL) { + printk("req argument is inval\n"); + break; + } + + if(req->render_mode == bitblt_mode) + rga_mem_addr_sel(req); + + reg = rga_reg_init(session, req); + if(reg == NULL) { + break; + } + num = 1; + } + + mutex_lock(&rga_service.lock); + atomic_add(num, &rga_service.total_running); + rga_try_set_reg(); + mutex_unlock(&rga_service.lock); + + return 0; + } + while(0); + + return -EFAULT; +} + +static int rga_blit_async(rga_session *session, struct rga_req *req) +{ + int ret = -1; + + #if RGA_TEST + printk("*** rga_blit_async proc ***\n"); + #endif + + atomic_set(&session->done, 0); + ret = rga_blit(session, req); + return ret; +} + +static int rga_blit_sync(rga_session *session, struct rga_req *req) +{ + int ret = -1; + int ret_timeout = 0; + + #if RGA_TEST + printk("*** rga_blit_sync proc ***\n"); + #endif + + atomic_set(&session->done, 0); + ret = rga_blit(session, req); + if(ret < 0) + return ret; + + ret_timeout = wait_event_timeout(session->wait, atomic_read(&session->done), RGA_TIMEOUT_DELAY); + + if (unlikely(ret_timeout< 0)) { + mutex_lock(&rga_service.lock); + rga_del_running_list(); + mutex_unlock(&rga_service.lock); + ret = ret_timeout; + } + else if (0 == ret_timeout) { + mutex_lock(&rga_service.lock); + rga_del_running_list_timeout(); + rga_try_set_reg(); + mutex_unlock(&rga_service.lock); + ret = -ETIMEDOUT; + } + + #if RGA_TEST_TIME + rga_end = ktime_get(); + rga_end = ktime_sub(rga_end, rga_start); + printk("sync one cmd end time %d\n", (int)ktime_to_us(rga_end)); + #endif + + return ret; +} + + +static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg) +{ + struct rga_req req; + int ret = 0; + rga_session *session; + + mutex_lock(&rga_service.mutex); + + session = (rga_session *)file->private_data; + + if (NULL == session) { + printk("%s [%d] rga thread session is null\n",__FUNCTION__,__LINE__); + mutex_unlock(&rga_service.mutex); + return -EINVAL; + } + + memset(&req, 0x0, sizeof(req)); + + switch (cmd) { + case RGA_BLIT_SYNC: + if (unlikely(copy_from_user(&req, (struct rga_req*)arg, sizeof(struct rga_req)))) + { + ERR("copy_from_user failed\n"); + ret = -EFAULT; + break; + } + ret = rga_blit_sync(session, &req); + break; + case RGA_BLIT_ASYNC: + if (unlikely(copy_from_user(&req, (struct rga_req*)arg, sizeof(struct rga_req)))) + { + ERR("copy_from_user failed\n"); + ret = -EFAULT; + break; + } + + if((atomic_read(&rga_service.total_running) > 16)) + { + ret = rga_blit_sync(session, &req); + } + else + { + ret = rga_blit_async(session, &req); + } + break; + case RGA_FLUSH: + ret = rga_flush(session, arg); + break; + case RGA_GET_RESULT: + ret = rga_get_result(session, arg); + break; + case RGA_GET_VERSION: + ret = copy_to_user((void *)arg, RGA_VERSION, sizeof(RGA_VERSION)); + //ret = 0; + break; + default: + ERR("unknown ioctl cmd!\n"); + ret = -EINVAL; + break; + } + + mutex_unlock(&rga_service.mutex); + + return ret; +} + + +long rga_ioctl_kernel(struct rga_req *req) +{ + int ret = 0; + if (!rga_ioctl_kernel_p) { + printk("rga_ioctl_kernel_p is NULL\n"); + return -1; + } + else { + ret = (*rga_ioctl_kernel_p)(req); + return ret; + } +} + + +long rga_ioctl_kernel_imp(struct rga_req *req) +{ + int ret = 0; + rga_session *session; + + mutex_lock(&rga_service.mutex); + + session = &rga_session_global; + + if (NULL == session) { + printk("%s [%d] rga thread session is null\n",__FUNCTION__,__LINE__); + mutex_unlock(&rga_service.mutex); + return -EINVAL; + } + + ret = rga_blit_sync(session, req); + + mutex_unlock(&rga_service.mutex); + + return ret; +} + + +static int rga_open(struct inode *inode, struct file *file) +{ + rga_session *session = kzalloc(sizeof(rga_session), GFP_KERNEL); + if (NULL == session) { + pr_err("unable to allocate memory for rga_session."); + return -ENOMEM; + } + + session->pid = current->pid; + //printk(KERN_DEBUG "+"); + + INIT_LIST_HEAD(&session->waiting); + INIT_LIST_HEAD(&session->running); + INIT_LIST_HEAD(&session->list_session); + init_waitqueue_head(&session->wait); + mutex_lock(&rga_service.lock); + list_add_tail(&session->list_session, &rga_service.session); + mutex_unlock(&rga_service.lock); + atomic_set(&session->task_running, 0); + atomic_set(&session->num_done, 0); + + file->private_data = (void *)session; + + //DBG("*** rga dev opened by pid %d *** \n", session->pid); + return nonseekable_open(inode, file); + +} + +static int rga_release(struct inode *inode, struct file *file) +{ + int task_running; + rga_session *session = (rga_session *)file->private_data; + if (NULL == session) + return -EINVAL; + //printk(KERN_DEBUG "-"); + task_running = atomic_read(&session->task_running); + + if (task_running) + { + pr_err("rga_service session %d still has %d task running when closing\n", session->pid, task_running); + msleep(100); + /*ͬ²½*/ + } + + wake_up(&session->wait); + mutex_lock(&rga_service.lock); + list_del(&session->list_session); + rga_service_session_clear(session); + kfree(session); + mutex_unlock(&rga_service.lock); + + //DBG("*** rga dev close ***\n"); + return 0; +} + +static irqreturn_t rga_irq_thread(int irq, void *dev_id) +{ + mutex_lock(&rga_service.lock); + if (rga_service.enable) { + rga_del_running_list(); + rga_try_set_reg(); + } + mutex_unlock(&rga_service.lock); + + return IRQ_HANDLED; +} + +static irqreturn_t rga_irq(int irq, void *dev_id) +{ + /*clear INT */ + rga_write(rga_read(RGA_INT) | (0x1<<6) | (0x1<<7) | (0x1<<4), RGA_INT); + + return IRQ_WAKE_THREAD; +} + +struct file_operations rga_fops = { + .owner = THIS_MODULE, + .open = rga_open, + .release = rga_release, + .unlocked_ioctl = rga_ioctl, +}; + +static struct miscdevice rga_dev ={ + .minor = RGA_MAJOR, + .name = "rga", + .fops = &rga_fops, +}; + + +#if defined(CONFIG_OF) +static const struct of_device_id rockchip_rga_dt_ids[] = { + { .compatible = "rockchip,rk312x-rga", }, + {}, +}; +#endif + +static int rga_drv_probe(struct platform_device *pdev) +{ + struct rga_drvdata *data; + struct resource *res; + //struct device_node *np = pdev->dev.of_node; + int ret = 0; + + mutex_init(&rga_service.lock); + mutex_init(&rga_service.mutex); + atomic_set(&rga_service.total_running, 0); + rga_service.enable = false; + + rga_ioctl_kernel_p = rga_ioctl_kernel_imp; + + data = devm_kzalloc(&pdev->dev, sizeof(struct rga_drvdata), GFP_KERNEL); + if(! data) { + ERR("failed to allocate driver data.\n"); + return -ENOMEM; + } + + INIT_DELAYED_WORK(&data->power_off_work, rga_power_off_work); + wake_lock_init(&data->wake_lock, WAKE_LOCK_SUSPEND, "rga"); + + //data->pd_rga = devm_clk_get(&pdev->dev, "pd_rga"); + data->aclk_rga = devm_clk_get(&pdev->dev, "aclk_rga"); + data->hclk_rga = devm_clk_get(&pdev->dev, "hclk_rga"); + + /* map the registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->rga_base = devm_ioremap_resource(&pdev->dev, res); + if (!data->rga_base) { + ERR("rga ioremap failed\n"); + ret = -ENOENT; + goto err_ioremap; + } + + /* get the IRQ */ + data->irq = ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + ERR("failed to get rga irq resource (%d).\n", data->irq); + ret = data->irq; + goto err_irq; + } + + /* request the IRQ */ + //ret = request_threaded_irq(data->irq, rga_irq, rga_irq_thread, 0, "rga", pdev); + ret = devm_request_threaded_irq(&pdev->dev, data->irq, rga_irq, rga_irq_thread, 0, "rga", data); + if (ret) + { + ERR("rga request_irq failed (%d).\n", ret); + goto err_irq; + } + + platform_set_drvdata(pdev, data); + drvdata = data; + + #if defined(CONFIG_ION_ROCKCHIP) + data->ion_client = rockchip_ion_client_create("rga"); + if (IS_ERR(data->ion_client)) { + dev_err(&pdev->dev, "failed to create ion client for rga"); + return PTR_ERR(data->ion_client); + } else { + dev_info(&pdev->dev, "rga ion client create success!\n"); + } #endif - atomic_set(&session->done, 0); - - ret = rga_blit(session, req); - if(ret < 0) - { - return ret; - } - - ret_timeout = wait_event_timeout(session->wait, atomic_read(&session->done), RGA_TIMEOUT_DELAY); - - if (unlikely(ret_timeout< 0)) - { - //pr_err("sync pid %d wait task ret %d\n", session->pid, ret_timeout); - mutex_lock(&rga_service.lock); - rga_del_running_list(); - mutex_unlock(&rga_service.lock); - ret = ret_timeout; - } - else if (0 == ret_timeout) - { - //pr_err("sync pid %d wait %d task done timeout\n", session->pid, atomic_read(&session->task_running)); - mutex_lock(&rga_service.lock); - rga_del_running_list_timeout(); - rga_try_set_reg(); - mutex_unlock(&rga_service.lock); - ret = -ETIMEDOUT; - } - - #if RGA_TEST_TIME - rga_end = ktime_get(); - rga_end = ktime_sub(rga_end, rga_start); - printk("sync one cmd end time %d\n", (int)ktime_to_us(rga_end)); - #endif - - return ret; -} - - -static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg) -{ - struct rga_req req; - int ret = 0; - rga_session *session; - - mutex_lock(&rga_service.mutex); - - session = (rga_session *)file->private_data; - - if (NULL == session) - { - printk("%s [%d] rga thread session is null\n",__FUNCTION__,__LINE__); - mutex_unlock(&rga_service.mutex); - return -EINVAL; - } - - memset(&req, 0x0, sizeof(req)); - - switch (cmd) - { - case RGA_BLIT_SYNC: - if (unlikely(copy_from_user(&req, (struct rga_req*)arg, sizeof(struct rga_req)))) - { - ERR("copy_from_user failed\n"); - ret = -EFAULT; - break; - } - ret = rga_blit_sync(session, &req); - break; - case RGA_BLIT_ASYNC: - if (unlikely(copy_from_user(&req, (struct rga_req*)arg, sizeof(struct rga_req)))) - { - ERR("copy_from_user failed\n"); - ret = -EFAULT; - break; - } - - if((atomic_read(&rga_service.total_running) > 16)) - { - ret = rga_blit_sync(session, &req); - } - else - { - ret = rga_blit_async(session, &req); - } - break; - case RGA_FLUSH: - ret = rga_flush(session, arg); - break; - case RGA_GET_RESULT: - ret = rga_get_result(session, arg); - break; - case RGA_GET_VERSION: - ret = copy_to_user((void *)arg, RGA_VERSION, sizeof(RGA_VERSION)); - //ret = 0; - break; - default: - ERR("unknown ioctl cmd!\n"); - ret = -EINVAL; - break; - } - - mutex_unlock(&rga_service.mutex); - - return ret; -} - - -long rga_ioctl_kernel(struct rga_req *req) -{ - int ret = 0; - rga_session *session; - - mutex_lock(&rga_service.mutex); - - session = &rga_session_global; - - if (NULL == session) - { - printk("%s [%d] rga thread session is null\n",__FUNCTION__,__LINE__); - mutex_unlock(&rga_service.mutex); - return -EINVAL; - } - - switch (RGA_BLIT_SYNC) - { - case RGA_BLIT_SYNC: - ret = rga_blit_sync(session, req); - break; - case RGA_BLIT_ASYNC: - break; - case RGA_FLUSH: - break; - case RGA_GET_RESULT: - break; - case RGA_GET_VERSION: - //ret = 0; - break; - default: - ERR("unknown ioctl cmd!\n"); - ret = -EINVAL; - break; - } - - mutex_unlock(&rga_service.mutex); - - return ret; -} - - -static int rga_open(struct inode *inode, struct file *file) -{ - rga_session *session = kzalloc(sizeof(rga_session), GFP_KERNEL); - if (NULL == session) { - pr_err("unable to allocate memory for rga_session."); - return -ENOMEM; - } - - session->pid = current->pid; - //printk(KERN_DEBUG "+"); - - INIT_LIST_HEAD(&session->waiting); - INIT_LIST_HEAD(&session->running); - INIT_LIST_HEAD(&session->list_session); - init_waitqueue_head(&session->wait); - mutex_lock(&rga_service.lock); - list_add_tail(&session->list_session, &rga_service.session); - mutex_unlock(&rga_service.lock); - atomic_set(&session->task_running, 0); - atomic_set(&session->num_done, 0); - - file->private_data = (void *)session; - - //DBG("*** rga dev opened by pid %d *** \n", session->pid); - return nonseekable_open(inode, file); - -} - -static int rga_release(struct inode *inode, struct file *file) -{ - int task_running; - rga_session *session = (rga_session *)file->private_data; - if (NULL == session) - return -EINVAL; - //printk(KERN_DEBUG "-"); - task_running = atomic_read(&session->task_running); - - if (task_running) - { - pr_err("rga_service session %d still has %d task running when closing\n", session->pid, task_running); - msleep(100); - /*ͬ²½*/ - } - - wake_up(&session->wait); - mutex_lock(&rga_service.lock); - list_del(&session->list_session); - rga_service_session_clear(session); - kfree(session); - mutex_unlock(&rga_service.lock); - - //DBG("*** rga dev close ***\n"); - return 0; -} - -static irqreturn_t rga_irq_thread(int irq, void *dev_id) -{ - mutex_lock(&rga_service.lock); - if (rga_service.enable) { - rga_del_running_list(); - rga_try_set_reg(); - } - mutex_unlock(&rga_service.lock); - - return IRQ_HANDLED; -} - -static irqreturn_t rga_irq(int irq, void *dev_id) -{ - /*clear INT */ - rga_write(rga_read(RGA_INT) | (0x1<<6) | (0x1<<7) | (0x1<<4), RGA_INT); - - return IRQ_WAKE_THREAD; -} - -struct file_operations rga_fops = { - .owner = THIS_MODULE, - .open = rga_open, - .release = rga_release, - .unlocked_ioctl = rga_ioctl, -}; - -static struct miscdevice rga_dev ={ - .minor = RGA_MAJOR, - .name = "rga", - .fops = &rga_fops, -}; - -static int __devinit rga_drv_probe(struct platform_device *pdev) -{ - struct rga_drvdata *data; - int ret = 0; - - INIT_LIST_HEAD(&rga_service.waiting); - INIT_LIST_HEAD(&rga_service.running); - INIT_LIST_HEAD(&rga_service.done); - INIT_LIST_HEAD(&rga_service.session); - mutex_init(&rga_service.lock); - mutex_init(&rga_service.mutex); - atomic_set(&rga_service.total_running, 0); - atomic_set(&rga_service.src_format_swt, 0); - rga_service.last_prc_src_format = 1; /* default is yuv first*/ - rga_service.enable = false; - - data = kzalloc(sizeof(struct rga_drvdata), GFP_KERNEL); - if(NULL == data) - { - ERR("failed to allocate driver data.\n"); - return -ENOMEM; - } - - INIT_DELAYED_WORK(&data->power_off_work, rga_power_off_work); - wake_lock_init(&data->wake_lock, WAKE_LOCK_SUSPEND, "rga"); - - data->pd_rga = clk_get(NULL, "pd_rga"); - data->aclk_rga = clk_get(NULL, "aclk_rga"); - data->hclk_rga = clk_get(NULL, "hclk_rga"); - - /* map the memory */ - if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) - { - pr_info("failed to reserve rga HW regs\n"); - return -EBUSY; - } - - data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); - if (data->rga_base == NULL) - { - ERR("rga ioremap failed\n"); - ret = -ENOENT; - goto err_ioremap; - } - - /* get the IRQ */ - data->irq = platform_get_irq(pdev, 0); - if (data->irq <= 0) - { - ERR("failed to get rga irq resource (%d).\n", data->irq); - ret = data->irq; - goto err_irq; - } - - /* request the IRQ */ - ret = request_threaded_irq(data->irq, rga_irq, rga_irq_thread, 0, "rga", pdev); - if (ret) - { - ERR("rga request_irq failed (%d).\n", ret); - goto err_irq; - } - - platform_set_drvdata(pdev, data); - drvdata = data; - ret = misc_register(&rga_dev); if(ret) { @@ -1204,7 +1304,7 @@ err_irq: iounmap(data->rga_base); err_ioremap: wake_lock_destroy(&data->wake_lock); - kfree(data); + //kfree(data); return ret; } @@ -1219,20 +1319,21 @@ static int rga_drv_remove(struct platform_device *pdev) free_irq(data->irq, &data->miscdev); iounmap((void __iomem *)(data->rga_base)); - clk_put(data->pd_rga); - clk_put(data->aclk_rga); - clk_put(data->hclk_rga); + //clk_put(data->pd_rga); + devm_clk_put(&pdev->dev, data->aclk_rga); + devm_clk_put(&pdev->dev, data->hclk_rga); - kfree(data); + //kfree(data); return 0; } static struct platform_driver rga_driver = { .probe = rga_drv_probe, - .remove = __devexit_p(rga_drv_remove), + .remove = rga_drv_remove, .driver = { .owner = THIS_MODULE, .name = "rga", + .of_match_table = of_match_ptr(rockchip_rga_dt_ids), }, }; @@ -1245,31 +1346,46 @@ static int __init rga_init(void) { int ret; uint32_t *mmu_buf; + unsigned long *mmu_buf_virtual; uint32_t i; uint32_t *buf_p; - + uint32_t *buf; + /* malloc pre scale mid buf mmu table */ mmu_buf = kzalloc(1024*8, GFP_KERNEL); - if(mmu_buf == NULL) - { + mmu_buf_virtual = kzalloc(1024*2*sizeof(unsigned long), GFP_KERNEL); + if(mmu_buf == NULL) { printk(KERN_ERR "RGA get Pre Scale buff failed. \n"); return -1; } - /* malloc 8 M buf */ - for(i=0; i<2048; i++) - { + /* malloc 4 M buf */ + for(i=0; i<1024; i++) { buf_p = (uint32_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO); - if(buf_p == NULL) - { + if(buf_p == NULL) { printk(KERN_ERR "RGA init pre scale buf falied\n"); return -ENOMEM; } - - mmu_buf[i] = virt_to_phys((void *)((uint32_t)buf_p)); + mmu_buf[i] = virt_to_phys((void *)((unsigned long)buf_p)); + mmu_buf_virtual[i] = (unsigned long)buf_p; } rga_service.pre_scale_buf = (uint32_t *)mmu_buf; + rga_service.pre_scale_buf_virtual = (unsigned long *)mmu_buf_virtual; + + buf_p = kmalloc(1024*256, GFP_KERNEL); + rga_mmu_buf.buf_virtual = buf_p; +#if (defined(CONFIG_ARM) && defined(CONFIG_ARM_LPAE)) + buf = (uint32_t *)(uint32_t)virt_to_phys((void *)((unsigned long)buf_p)); +#else + buf = (uint32_t *)virt_to_phys((void *)((unsigned long)buf_p)); +#endif + rga_mmu_buf.buf = buf; + rga_mmu_buf.front = 0; + rga_mmu_buf.back = 64*1024; + rga_mmu_buf.size = 64*1024; + + rga_mmu_buf.pages = kmalloc((32768)* sizeof(struct page *), GFP_KERNEL); if ((ret = platform_driver_register(&rga_driver)) != 0) { @@ -1282,6 +1398,12 @@ static int __init rga_init(void) INIT_LIST_HEAD(&rga_session_global.waiting); INIT_LIST_HEAD(&rga_session_global.running); INIT_LIST_HEAD(&rga_session_global.list_session); + + INIT_LIST_HEAD(&rga_service.waiting); + INIT_LIST_HEAD(&rga_service.running); + INIT_LIST_HEAD(&rga_service.done); + INIT_LIST_HEAD(&rga_service.session); + init_waitqueue_head(&rga_session_global.wait); //mutex_lock(&rga_service.lock); list_add_tail(&rga_session_global.list_session, &rga_service.session); @@ -1290,6 +1412,8 @@ static int __init rga_init(void) atomic_set(&rga_session_global.num_done, 0); } + + #if RGA_TEST_CASE rga_test_0(); #endif @@ -1305,17 +1429,24 @@ static void __exit rga_exit(void) rga_power_off(); - for(i=0; i<2048; i++) + for(i=0; i<1024; i++) { - if((uint32_t *)rga_service.pre_scale_buf[i] != NULL) + if((unsigned long)rga_service.pre_scale_buf_virtual[i]) { - __free_page((void *)rga_service.pre_scale_buf[i]); + __free_page((void *)rga_service.pre_scale_buf_virtual[i]); } } if(rga_service.pre_scale_buf != NULL) { kfree((uint8_t *)rga_service.pre_scale_buf); } + + if (rga_mmu_buf.buf_virtual) + kfree(rga_mmu_buf.buf_virtual); + + if (rga_mmu_buf.pages) + kfree(rga_mmu_buf.pages); + platform_driver_unregister(&rga_driver); } @@ -1471,7 +1602,7 @@ void rga_test_0(void) } #endif -module_init(rga_init); +fs_initcall(rga_init); module_exit(rga_exit); /* Module information */