void fimg2d_pm_qos_remove(struct fimg2d_control *ctrl) { #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) || \ defined(CONFIG_FIMG2D_USE_BUS_DEVFREQ) struct fimg2d_platdata *pdata; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif #endif #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) if (pdata->cpu_min) pm_qos_remove_request(&ctrl->exynos5_g2d_cpu_qos); if (pdata->kfc_min) pm_qos_remove_request(&ctrl->exynos5_g2d_kfc_qos); #endif #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ if (pdata->mif_min) pm_qos_remove_request(&ctrl->exynos5_g2d_mif_qos); if (pdata->int_min) pm_qos_remove_request(&ctrl->exynos5_g2d_int_qos); #endif }
void fimg2d_pm_qos_add(struct fimg2d_control *ctrl) { #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) || \ defined(CONFIG_FIMG2D_USE_BUS_DEVFREQ) struct fimg2d_platdata *pdata; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif #endif #if defined CONFIG_ARM_EXYNOS_IKS_CPUFREQ pm_qos_add_request(&ctrl->exynos5_g2d_cpu_qos, PM_QOS_CPU_FREQ_MIN, 0); #elif defined CONFIG_ARM_EXYNOS_MP_CPUFREQ pm_qos_add_request(&ctrl->exynos5_g2d_cpu_qos, PM_QOS_CPU_FREQ_MIN, 0); pm_qos_add_request(&ctrl->exynos5_g2d_kfc_qos, PM_QOS_KFC_FREQ_MIN, 0); #endif #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ pm_qos_add_request(&ctrl->exynos5_g2d_mif_qos, PM_QOS_BUS_THROUGHPUT, 0); pm_qos_add_request(&ctrl->exynos5_g2d_int_qos, PM_QOS_DEVICE_THROUGHPUT, 0); #endif }
static int fimg2d_remove(struct platform_device *pdev) { struct fimg2d_platdata *pdata; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif fimg2d_pm_qos_remove(ctrl); misc_deregister(&fimg2d_dev); #ifdef CONFIG_PM_RUNTIME pm_runtime_disable(&pdev->dev); #else fimg2d_clk_off(ctrl); #endif fimg2d_clk_release(ctrl); free_irq(ctrl->irq, NULL); if (ctrl->mem) { iounmap(ctrl->regs); release_resource(ctrl->mem); kfree(ctrl->mem); } #ifdef BLIT_WORKQUE destroy_workqueue(ctrl->work_q); #endif mutex_destroy(&ctrl->drvlock); kfree(ctrl); kfree(pdata); return 0; }
void fimg2d_pm_qos_update(struct fimg2d_control *ctrl, enum fimg2d_qos_status status) { struct fimg2d_platdata *pdata = to_fimg2d_plat(ctrl->dev); if (status == FIMG2D_QOS_ON) { #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ if (pdata->mif_min) pm_qos_update_request(&ctrl->exynos5_g2d_mif_qos, pdata->mif_min); if (pdata->int_min) pm_qos_update_request(&ctrl->exynos5_g2d_int_qos, pdata->int_min); #endif #ifdef CONFIG_ARM_EXYNOS_IKS_CPUFREQ if (pdata->cpu_min) pm_qos_update_request(&ctrl->exynos5_g2d_cpu_qos, pdata->cpu_min); #endif } else if (status == FIMG2D_QOS_OFF) { #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ if (pdata->mif_min) pm_qos_update_request(&ctrl->exynos5_g2d_mif_qos, 0); if (pdata->int_min) pm_qos_update_request(&ctrl->exynos5_g2d_int_qos, 0); #endif #ifdef CONFIG_ARM_EXYNOS_IKS_CPUFREQ if (pdata->cpu_min) pm_qos_update_request(&ctrl->exynos5_g2d_cpu_qos, 0); #endif } fimg2d_debug("Done fimg2d_pm_qos_update(cpu:%d, mif:%d, int:%d)\n", pdata->cpu_min, pdata->mif_min, pdata->int_min); }
void fimg2d_pm_qos_update(struct fimg2d_control *ctrl, enum fimg2d_qos_status status) { #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) || \ defined(CONFIG_FIMG2D_USE_BUS_DEVFREQ) struct fimg2d_platdata *pdata; enum fimg2d_qos_level idx; int ret = 0; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif #endif if (status == FIMG2D_QOS_ON) { if (ctrl->pre_qos_lv != ctrl->qos_lv) { #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ idx = ctrl->qos_lv; if (idx == 0) ret = set_hmp_boost(true); pm_qos_update_request(&ctrl->exynos5_g2d_mif_qos, g2d_qos_table[idx].freq_mif); pm_qos_update_request(&ctrl->exynos5_g2d_int_qos, g2d_qos_table[idx].freq_int); fimg2d_debug("idx:%d, freq_mif:%d, freq_int:%d, ret:%d\n", idx, g2d_qos_table[idx].freq_mif, g2d_qos_table[idx].freq_int, ret); #endif #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) pm_qos_update_request(&ctrl->exynos5_g2d_cpu_qos, g2d_qos_table[idx].freq_cpu); pm_qos_update_request(&ctrl->exynos5_g2d_kfc_qos, g2d_qos_table[idx].freq_kfc); fimg2d_debug("idx:%d, freq_cpu:%d, freq_kfc:%d\n", idx, g2d_qos_table[idx].freq_cpu, g2d_qos_table[idx].freq_kfc); } #endif } else if (status == FIMG2D_QOS_OFF) { #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ pm_qos_update_request(&ctrl->exynos5_g2d_mif_qos, 0); pm_qos_update_request(&ctrl->exynos5_g2d_int_qos, 0); #endif #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) pm_qos_update_request(&ctrl->exynos5_g2d_cpu_qos, 0); pm_qos_update_request(&ctrl->exynos5_g2d_kfc_qos, 0); #endif idx = ctrl->qos_lv; if (idx == 0) ret = set_hmp_boost(false); } }
void fimg2d_clk_release(struct fimg2d_control *ctrl) { clk_put(ctrl->clock); if (ip_is_g2d_4p()) { struct fimg2d_platdata *pdata; pdata = to_fimg2d_plat(ctrl->dev); clk_put(clk_get(ctrl->dev, pdata->clkname)); clk_put(clk_get(ctrl->dev, pdata->parent_clkname)); } }
static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; struct fimg2d_context *ctx; struct fimg2d_platdata *pdata; union { struct fimg2d_blit *blit; struct fimg2d_version ver; } u; ctx = file->private_data; if (!ctx) { printk(KERN_ERR "[%s] missing ctx\n", __func__); return -EFAULT; } switch (cmd) { case FIMG2D_BITBLT_BLIT: fimg2d_debug("FIMG2D_BITBLT_BLIT ctx: %p\n", ctx); u.blit = (struct fimg2d_blit *)arg; ret = fimg2d_add_command(info, ctx, u.blit); if (!ret) fimg2d_request_bitblt(ctx); #ifdef PERF_PROFILE perf_print(ctx, u.blit->seq_no); perf_clear(ctx); #endif break; case FIMG2D_BITBLT_SYNC: fimg2d_debug("FIMG2D_BITBLT_SYNC ctx: %p\n", ctx); /* FIXME: */ break; case FIMG2D_BITBLT_VERSION: fimg2d_debug("FIMG2D_BITBLT_VERSION ctx: %p\n", ctx); pdata = to_fimg2d_plat(info->dev); u.ver.hw = pdata->hw_ver; u.ver.sw = 0; fimg2d_debug("fimg2d version, hw: 0x%x sw: 0x%x\n", u.ver.hw, u.ver.sw); if (copy_to_user((void *)arg, &u.ver, sizeof(u.ver))) return -EFAULT; break; default: printk(KERN_ERR "[%s] unknown ioctl\n", __func__); ret = -EFAULT; break; } return ret; }
int fimg2d_ip_version_is(void) { struct fimg2d_platdata *pdata; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif return pdata->ip_ver; }
void fimg2d_pm_qos_remove(struct fimg2d_control *ctrl) { struct fimg2d_platdata *pdata = to_fimg2d_plat(ctrl->dev); #ifdef CONFIG_ARM_EXYNOS_IKS_CPUFREQ if (pdata->cpu_min) pm_qos_remove_request(&ctrl->exynos5_g2d_cpu_qos); #endif #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ if (pdata->mif_min) pm_qos_remove_request(&ctrl->exynos5_g2d_mif_qos); if (pdata->int_min) pm_qos_remove_request(&ctrl->exynos5_g2d_int_qos); #endif }
int fimg2d_clk_set_gate(struct fimg2d_control *ctrl) { /* CPLL:666MHz */ struct clk *aclk_333_g2d_sw, *aclk_333_g2d; struct fimg2d_platdata *pdata; int ret = 0; pdata = to_fimg2d_plat(ctrl->dev); aclk_333_g2d_sw = clk_get(NULL, "aclk_333_g2d_sw"); if (IS_ERR(aclk_333_g2d_sw)) { pr_err("failed to get %s clock\n", "aclk_333_g2d_sw"); ret = PTR_ERR(aclk_333_g2d_sw); goto err_g2d_dout; } aclk_333_g2d = clk_get(NULL, "aclk_333_g2d"); /* sclk_fimg2d */ if (IS_ERR(aclk_333_g2d)) { pr_err("failed to get %s clock\n", "aclk_333_g2d"); ret = PTR_ERR(aclk_333_g2d); goto err_g2d_sw; } if (clk_set_parent(aclk_333_g2d, aclk_333_g2d_sw)) pr_err("Unable to set parent %s of clock %s\n", aclk_333_g2d_sw->name, aclk_333_g2d->name); /* clock for gating */ ctrl->clock = clk_get(ctrl->dev, pdata->gate_clkname); if (IS_ERR(ctrl->clock)) { fimg2d_err("failed to get gate clk\n"); ret = -ENOENT; goto err_aclk_g2d; } fimg2d_debug("gate clk: %s\n", pdata->gate_clkname); err_aclk_g2d: if (aclk_333_g2d) clk_put(aclk_333_g2d); err_g2d_sw: if (aclk_333_g2d_sw) clk_put(aclk_333_g2d_sw); err_g2d_dout: return ret; }
void fimg2d_pm_qos_add(struct fimg2d_control *ctrl) { struct fimg2d_platdata *pdata = to_fimg2d_plat(ctrl->dev); #ifdef CONFIG_ARM_EXYNOS_IKS_CPUFREQ if (pdata->cpu_min) pm_qos_add_request(&ctrl->exynos5_g2d_cpu_qos, PM_QOS_CPU_FREQ_MIN, 0); #endif #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ if (pdata->mif_min) pm_qos_add_request(&ctrl->exynos5_g2d_mif_qos, PM_QOS_BUS_THROUGHPUT, 0); if (pdata->int_min) pm_qos_add_request(&ctrl->exynos5_g2d_int_qos, PM_QOS_DEVICE_THROUGHPUT, 0); #endif }
int fimg2d_clk_setup(struct fimg2d_control *ctrl) { struct fimg2d_platdata *pdata; struct clk *parent, *sclk; int ret = 0; sclk = parent = NULL; pdata = to_fimg2d_plat(ctrl->dev); if (ip_is_g2d_5g() || ip_is_g2d_5a()) { fimg2d_info("aclk_acp(%lu) pclk_acp(%lu)\n", clk_get_rate(clk_get(NULL, "aclk_acp")), clk_get_rate(clk_get(NULL, "pclk_acp"))); } else { sclk = clk_get(ctrl->dev, pdata->clkname); if (IS_ERR(sclk)) { fimg2d_err("failed to get fimg2d clk\n"); ret = -ENOENT; goto err_clk1; } fimg2d_info("fimg2d clk name: %s clkrate: %ld\n", pdata->clkname, clk_get_rate(sclk)); } /* clock for gating */ ctrl->clock = clk_get(ctrl->dev, pdata->gate_clkname); if (IS_ERR(ctrl->clock)) { fimg2d_err("failed to get gate clk\n"); ret = -ENOENT; goto err_clk2; } fimg2d_info("gate clk: %s\n", pdata->gate_clkname); return ret; err_clk2: if (sclk) clk_put(sclk); err_clk1: return ret; }
static int fimg2d_probe(struct platform_device *pdev) { struct resource *res; struct fimg2d_platdata *pdata; int ret; pdata = to_fimg2d_plat(&pdev->dev); if (!pdata) { printk(KERN_ERR "FIMG2D failed to get platform data\n"); ret = -ENOMEM; goto err_plat; } /* global structure */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { printk(KERN_ERR "FIMG2D failed to allocate memory for controller\n"); ret = -ENOMEM; goto err_plat; } /* setup global info */ ret = fimg2d_setup_controller(info); if (ret) { printk(KERN_ERR "FIMG2D failed to setup controller\n"); goto err_setup; } info->dev = &pdev->dev; /* memory region */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { printk(KERN_ERR "FIMG2D failed to get resource\n"); ret = -ENOENT; goto err_res; } info->mem = request_mem_region(res->start, resource_size(res), pdev->name); if (!info->mem) { printk(KERN_ERR "FIMG2D failed to request memory region\n"); ret = -ENOMEM; goto err_region; } /* ioremap */ info->regs = ioremap(res->start, resource_size(res)); if (!info->regs) { printk(KERN_ERR "FIMG2D failed to ioremap for SFR\n"); ret = -ENOENT; goto err_map; } fimg2d_debug("device name: %s base address: 0x%lx\n", pdev->name, (unsigned long)res->start); /* irq */ info->irq = platform_get_irq(pdev, 0); if (!info->irq) { printk(KERN_ERR "FIMG2D failed to get irq resource\n"); ret = -ENOENT; goto err_map; } fimg2d_debug("irq: %d\n", info->irq); ret = request_irq(info->irq, fimg2d_irq, IRQF_DISABLED, pdev->name, info); if (ret) { printk(KERN_ERR "FIMG2D failed to request irq\n"); ret = -ENOENT; goto err_irq; } ret = fimg2d_clk_setup(info); if (ret) { printk(KERN_ERR "FIMG2D failed to setup clk\n"); ret = -ENOENT; goto err_clk; } #ifdef CONFIG_PM_RUNTIME pm_runtime_enable(info->dev); fimg2d_debug("enable runtime pm\n"); #endif #ifdef CONFIG_BUSFREQ_OPP #if defined(CONFIG_CPU_EXYNOS4412) /* To lock bus frequency in OPP mode */ info->bus_dev = dev_get("exynos-busfreq"); #endif #endif s5p_sysmmu_set_fault_handler(info->dev, fimg2d_sysmmu_fault_handler); fimg2d_debug("register sysmmu page fault handler\n"); /* misc register */ ret = misc_register(&fimg2d_dev); if (ret) { printk(KERN_ERR "FIMG2D failed to register misc driver\n"); goto err_reg; } printk(KERN_INFO "Samsung Graphics 2D driver, (c) 2011 Samsung Electronics\n"); return 0; err_reg: fimg2d_clk_release(info); err_clk: free_irq(info->irq, NULL); err_irq: iounmap(info->regs); err_map: kfree(info->mem); err_region: release_resource(info->mem); err_res: destroy_workqueue(info->work_q); err_setup: kfree(info); err_plat: return ret; }
static int fimg2d_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; if (!to_fimg2d_plat(&pdev->dev)) { fimg2d_err("failed to get platform data\n"); return -ENOMEM; } /* global structure */ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { fimg2d_err("failed to allocate memory for controller\n"); return -ENOMEM; } /* setup global ctrl */ ret = fimg2d_setup_controller(ctrl); if (ret) { fimg2d_err("failed to setup controller\n"); goto drv_free; } ctrl->dev = &pdev->dev; /* memory region */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { fimg2d_err("failed to get resource\n"); ret = -ENOENT; goto drv_free; } ctrl->mem = request_mem_region(res->start, resource_size(res), pdev->name); if (!ctrl->mem) { fimg2d_err("failed to request memory region\n"); ret = -ENOMEM; goto res_free; } /* ioremap */ ctrl->regs = ioremap(res->start, resource_size(res)); if (!ctrl->regs) { fimg2d_err("failed to ioremap for SFR\n"); ret = -ENOENT; goto mem_free; } fimg2d_info("base address: 0x%lx\n", (unsigned long)res->start); /* irq */ ctrl->irq = platform_get_irq(pdev, 0); if (!ctrl->irq) { fimg2d_err("failed to get irq resource\n"); ret = -ENOENT; goto reg_unmap; } fimg2d_info("irq: %d\n", ctrl->irq); ret = request_irq(ctrl->irq, fimg2d_irq, IRQF_DISABLED, pdev->name, ctrl); if (ret) { fimg2d_err("failed to request irq\n"); ret = -ENOENT; goto reg_unmap; } ret = fimg2d_clk_setup(ctrl); if (ret) { fimg2d_err("failed to setup clk\n"); ret = -ENOENT; goto irq_free; } #ifdef CONFIG_PM_RUNTIME pm_runtime_enable(ctrl->dev); fimg2d_info("enable runtime pm\n"); pm_runtime_get_sync(ctrl->dev); #else fimg2d_clk_on(ctrl); #endif exynos_sysmmu_set_fault_handler(ctrl->dev, fimg2d_sysmmu_fault_handler); fimg2d_info("register sysmmu page fault handler\n"); /* misc register */ ret = misc_register(&fimg2d_dev); if (ret) { fimg2d_err("failed to register misc driver\n"); goto clk_release; } #ifdef CONFIG_ARM_EXYNOS_IKS_CPUFREQ pm_qos_add_request(&exynos5_g2d_cpu_qos, PM_QOS_CPU_FREQ_MIN, 0); pm_qos_add_request(&exynos5_g2d_mif_qos, PM_QOS_BUS_THROUGHPUT, 0); #endif return 0; clk_release: #ifdef CONFIG_PM_RUNTIME pm_runtime_disable(ctrl->dev); #else fimg2d_clk_off(ctrl); #endif fimg2d_clk_release(ctrl); irq_free: free_irq(ctrl->irq, NULL); reg_unmap: iounmap(ctrl->regs); mem_free: kfree(ctrl->mem); res_free: release_resource(ctrl->mem); drv_free: #ifdef BLIT_WORKQUE if (ctrl->work_q) destroy_workqueue(ctrl->work_q); #endif mutex_destroy(&ctrl->drvlock); kfree(ctrl); return ret; }
int fimg2d_ip_version_is(void) { struct fimg2d_platdata *pdata = to_fimg2d_plat(ctrl->dev); return pdata->ip_ver; }
static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; struct fimg2d_context *ctx; struct mm_struct *mm; ctx = file->private_data; switch (cmd) { case FIMG2D_BITBLT_BLIT: mm = get_task_mm(current); if(!mm) { fimg2d_err("no mm for ctx\n"); return -ENXIO; } fimg2d_clk_on(ctrl); g2d_lock(&ctrl->drvlock); ctx->mm = mm; if (atomic_read(&ctrl->drvact) || atomic_read(&ctrl->suspended)) { fimg2d_err("driver is unavailable, do sw fallback\n"); g2d_unlock(&ctrl->drvlock); fimg2d_clk_off(ctrl); mmput(mm); return -EPERM; } ret = fimg2d_add_command(ctrl, ctx, (struct fimg2d_blit __user *)arg); if (ret) { fimg2d_err("add command not allowed.\n"); g2d_unlock(&ctrl->drvlock); fimg2d_clk_off(ctrl); mmput(mm); return ret; } ret = fimg2d_request_bitblt(ctrl, ctx); if (ret) { fimg2d_err("request bitblit not allowed.\n"); g2d_unlock(&ctrl->drvlock); fimg2d_clk_off(ctrl); mmput(mm); return -EBUSY; } g2d_unlock(&ctrl->drvlock); fimg2d_clk_off(ctrl); mmput(mm); break; case FIMG2D_BITBLT_VERSION: { struct fimg2d_version ver; struct fimg2d_platdata *pdata; pdata = to_fimg2d_plat(ctrl->dev); ver.hw = pdata->hw_ver; ver.sw = 0; fimg2d_info("version info. hw(0x%x), sw(0x%x)\n", ver.hw, ver.sw); if (copy_to_user((void *)arg, &ver, sizeof(ver))) return -EFAULT; break; } case FIMG2D_BITBLT_ACTIVATE: { enum driver_act act; if (copy_from_user(&act, (void *)arg, sizeof(act))) return -EFAULT; g2d_lock(&ctrl->drvlock); atomic_set(&ctrl->drvact, act); if (act == DRV_ACT) fimg2d_info("fimg2d driver is activated\n"); else fimg2d_info("fimg2d driver is deactivated\n"); g2d_unlock(&ctrl->drvlock); break; } default: fimg2d_err("unknown ioctl\n"); ret = -EFAULT; break; } return ret; }
static int fimg2d_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; struct fimg2d_platdata *pdata; #ifdef CONFIG_OF struct device *dev = &pdev->dev; int id = 0; #else pdata = to_fimg2d_plat(&pdev->dev); #endif dev_info(&pdev->dev, "++%s\n", __func__); #ifdef CONFIG_OF if (dev->of_node) { id = of_alias_get_id(pdev->dev.of_node, "fimg2d"); } else { id = pdev->id; pdata = dev->platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data\n"); return -EINVAL; } } #else if (!to_fimg2d_plat(&pdev->dev)) { fimg2d_err("failed to get platform data\n"); return -ENOMEM; } #endif /* global structure */ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { fimg2d_err("failed to allocate memory for controller\n"); return -ENOMEM; } #ifdef CONFIG_OF pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { fimg2d_err("failed to allocate memory for controller\n"); kfree(ctrl); return -ENOMEM; } ctrl->pdata = pdata; g2d_parse_dt(dev->of_node, ctrl->pdata); #endif /* setup global ctrl */ ret = fimg2d_setup_controller(ctrl); if (ret) { fimg2d_err("failed to setup controller\n"); goto drv_free; } ctrl->dev = &pdev->dev; /* memory region */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { fimg2d_err("failed to get resource\n"); ret = -ENOENT; goto drv_free; } ctrl->mem = request_mem_region(res->start, resource_size(res), pdev->name); if (!ctrl->mem) { fimg2d_err("failed to request memory region\n"); ret = -ENOMEM; goto drv_free; } /* ioremap */ ctrl->regs = ioremap(res->start, resource_size(res)); if (!ctrl->regs) { fimg2d_err("failed to ioremap for SFR\n"); ret = -ENOENT; goto mem_free; } fimg2d_debug("base address: 0x%lx\n", (unsigned long)res->start); /* irq */ ctrl->irq = platform_get_irq(pdev, 0); if (!ctrl->irq) { fimg2d_err("failed to get irq resource\n"); ret = -ENOENT; goto reg_unmap; } fimg2d_debug("irq: %d\n", ctrl->irq); ret = request_irq(ctrl->irq, fimg2d_irq, IRQF_DISABLED, pdev->name, ctrl); if (ret) { fimg2d_err("failed to request irq\n"); ret = -ENOENT; goto reg_unmap; } ret = fimg2d_clk_setup(ctrl); if (ret) { fimg2d_err("failed to setup clk\n"); ret = -ENOENT; goto irq_free; } spin_lock_init(&ctrl->qoslock); #ifdef CONFIG_PM_RUNTIME pm_runtime_enable(ctrl->dev); fimg2d_info("enable runtime pm\n"); #else fimg2d_clk_on(ctrl); #endif #ifdef FIMG2D_IOVMM_PAGETABLE exynos_create_iovmm(dev, 3, 3); #endif iovmm_set_fault_handler(dev, fimg2d_sysmmu_fault_handler, ctrl); fimg2d_debug("register sysmmu page fault handler\n"); /* misc register */ ret = misc_register(&fimg2d_dev); if (ret) { fimg2d_err("failed to register misc driver\n"); goto clk_release; } fimg2d_pm_qos_add(ctrl); dev_info(&pdev->dev, "fimg2d registered successfully\n"); return 0; clk_release: #ifdef CONFIG_PM_RUNTIME pm_runtime_disable(ctrl->dev); #else fimg2d_clk_off(ctrl); #endif fimg2d_clk_release(ctrl); irq_free: free_irq(ctrl->irq, NULL); reg_unmap: iounmap(ctrl->regs); mem_free: release_mem_region(res->start, resource_size(res)); drv_free: #ifdef BLIT_WORKQUE if (ctrl->work_q) destroy_workqueue(ctrl->work_q); #endif mutex_destroy(&ctrl->drvlock); #ifdef CONFIG_OF kfree(pdata); #endif kfree(ctrl); return ret; }
static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; struct fimg2d_context *ctx; struct mm_struct *mm; struct fimg2d_dma *usr_dst; ctx = file->private_data; switch (cmd) { case FIMG2D_BITBLT_BLIT: mm = get_task_mm(current); if (!mm) { fimg2d_err("no mm for ctx\n"); return -ENXIO; } g2d_lock(&ctrl->drvlock); ctx->mm = mm; if (atomic_read(&ctrl->drvact) || atomic_read(&ctrl->suspended)) { fimg2d_err("driver is unavailable, do sw fallback\n"); g2d_unlock(&ctrl->drvlock); mmput(mm); return -EPERM; } ret = fimg2d_add_command(ctrl, ctx, (struct fimg2d_blit __user *)arg); if (ret) { fimg2d_err("add command not allowed.\n"); g2d_unlock(&ctrl->drvlock); mmput(mm); return ret; } fimg2d_pm_qos_update(ctrl, FIMG2D_QOS_ON); usr_dst = kzalloc(sizeof(struct fimg2d_dma), GFP_KERNEL); if (!usr_dst) { fimg2d_err("failed to allocate memory for fimg2d_dma\n"); g2d_unlock(&ctrl->drvlock); mmput(mm); return -ENOMEM; } ret = store_user_dst((struct fimg2d_blit __user *)arg, usr_dst); if (ret) { fimg2d_err("store_user_dst() not allowed.\n"); g2d_unlock(&ctrl->drvlock); kfree(usr_dst); mmput(mm); return ret; } ret = fimg2d_request_bitblt(ctrl, ctx); if (ret) { fimg2d_info("request bitblit not allowed, " "so passing to s/w fallback.\n"); g2d_unlock(&ctrl->drvlock); kfree(usr_dst); mmput(mm); return -EBUSY; } g2d_unlock(&ctrl->drvlock); fimg2d_debug("addr : %p, size : %zd\n", (void *)usr_dst->addr, usr_dst->size); #ifndef CCI_SNOOP fimg2d_dma_unsync_inner(usr_dst->addr, usr_dst->size, DMA_FROM_DEVICE); #endif kfree(usr_dst); mmput(mm); break; case FIMG2D_BITBLT_VERSION: { struct fimg2d_version ver; struct fimg2d_platdata *pdata; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif ver.hw = pdata->hw_ver; ver.sw = 0; fimg2d_info("version info. hw(0x%x), sw(0x%x)\n", ver.hw, ver.sw); if (copy_to_user((void *)arg, &ver, sizeof(ver))) return -EFAULT; break; } case FIMG2D_BITBLT_ACTIVATE: { enum driver_act act; if (copy_from_user(&act, (void *)arg, sizeof(act))) return -EFAULT; g2d_lock(&ctrl->drvlock); atomic_set(&ctrl->drvact, act); if (act == DRV_ACT) { fimg2d_power_control(ctrl, FIMG2D_PW_OFF); fimg2d_info("fimg2d driver is activated\n"); } else { fimg2d_power_control(ctrl, FIMG2D_PW_ON); fimg2d_info("fimg2d driver is deactivated\n"); } g2d_unlock(&ctrl->drvlock); break; } default: fimg2d_err("unknown ioctl\n"); ret = -EFAULT; break; } return ret; }
void fimg2d_pm_qos_update(struct fimg2d_control *ctrl, enum fimg2d_qos_status status) { #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) || \ defined(CONFIG_FIMG2D_USE_BUS_DEVFREQ) struct fimg2d_platdata *pdata; enum fimg2d_qos_level idx; int ret = 0; unsigned long qflags; #ifdef CONFIG_OF pdata = ctrl->pdata; #else pdata = to_fimg2d_plat(ctrl->dev); #endif #endif g2d_spin_lock(&ctrl->qoslock, qflags); if ((ctrl->qos_lv >= G2D_LV0) && (ctrl->qos_lv < G2D_LV_END)) idx = ctrl->qos_lv; else goto err; g2d_spin_unlock(&ctrl->qoslock, qflags); if (status == FIMG2D_QOS_ON) { if (ctrl->pre_qos_lv != ctrl->qos_lv) { #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ if (idx == 0) ret = set_hmp_boost(true); pm_qos_update_request(&ctrl->exynos5_g2d_mif_qos, g2d_qos_table[idx].freq_mif); pm_qos_update_request(&ctrl->exynos5_g2d_int_qos, g2d_qos_table[idx].freq_int); fimg2d_debug("idx:%d, freq_mif:%d, freq_int:%d, ret:%d\n", idx, g2d_qos_table[idx].freq_mif, g2d_qos_table[idx].freq_int, ret); #endif #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) pm_qos_update_request(&ctrl->exynos5_g2d_cpu_qos, g2d_qos_table[idx].freq_cpu); pm_qos_update_request(&ctrl->exynos5_g2d_kfc_qos, g2d_qos_table[idx].freq_kfc); fimg2d_debug("idx:%d, freq_cpu:%d, freq_kfc:%d\n", idx, g2d_qos_table[idx].freq_cpu, g2d_qos_table[idx].freq_kfc); } #endif } else if (status == FIMG2D_QOS_OFF) { #ifdef CONFIG_FIMG2D_USE_BUS_DEVFREQ pm_qos_update_request(&ctrl->exynos5_g2d_mif_qos, 0); pm_qos_update_request(&ctrl->exynos5_g2d_int_qos, 0); #endif #if defined(CONFIG_ARM_EXYNOS_IKS_CPUFREQ) || \ defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) pm_qos_update_request(&ctrl->exynos5_g2d_cpu_qos, 0); pm_qos_update_request(&ctrl->exynos5_g2d_kfc_qos, 0); #endif if (idx == 0) ret = set_hmp_boost(false); } err: fimg2d_debug("invalid qos_lv:%d\n", ctrl->qos_lv); }
static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; struct fimg2d_context *ctx; struct fimg2d_platdata *pdata; struct fimg2d_blit blit; struct fimg2d_version ver; struct fimg2d_image dst; ctx = file->private_data; if (!ctx) { printk(KERN_ERR "[%s] missing ctx\n", __func__); return -EFAULT; } switch (cmd) { case FIMG2D_BITBLT_BLIT: if (info->secure) return -EFAULT; if (copy_from_user(&blit, (void *)arg, sizeof(blit))) return -EFAULT; if (blit.dst) if (copy_from_user(&dst, (void *)blit.dst, sizeof(dst))) return -EFAULT; #ifdef CONFIG_BUSFREQ_OPP #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) dev_lock(info->bus_dev, info->dev, 160160); #endif #endif if ((blit.dst) && (dst.addr.type == ADDR_USER)) if (!down_write_trylock(&page_alloc_slow_rwsem)) ret = -EAGAIN; if (ret != -EAGAIN) ret = fimg2d_add_command(info, ctx, &blit, dst.addr.type); if (!ret) { fimg2d_request_bitblt(ctx); } #ifdef PERF_PROFILE perf_print(ctx, blit.seq_no); perf_clear(ctx); #endif if ((blit.dst) && (dst.addr.type == ADDR_USER) && ret != -EAGAIN) up_write(&page_alloc_slow_rwsem); #ifdef CONFIG_BUSFREQ_OPP #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) dev_unlock(info->bus_dev, info->dev); #endif #endif break; case FIMG2D_BITBLT_SYNC: fimg2d_debug("FIMG2D_BITBLT_SYNC ctx: %p\n", ctx); /* FIXME: */ break; case FIMG2D_BITBLT_VERSION: pdata = to_fimg2d_plat(info->dev); ver.hw = pdata->hw_ver; ver.sw = 0; fimg2d_debug("fimg2d version, hw: 0x%x sw: 0x%x\n", ver.hw, ver.sw); if (copy_to_user((void *)arg, &ver, sizeof(ver))) return -EFAULT; break; case FIMG2D_BITBLT_SECURE: if (copy_from_user(&info->secure, (unsigned int *)arg, sizeof(unsigned int))) { printk(KERN_ERR "[%s] failed to FIMG2D_BITBLT_SECURE: copy_from_user error\n\n", __func__); return -EFAULT; } while (1) { if (fimg2d_queue_is_empty(&info->cmd_q)) break; mdelay(2); } break; default: printk(KERN_ERR "[%s] unknown ioctl\n", __func__); ret = -EFAULT; break; } return ret; }