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
}
Beispiel #3
0
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));
	}
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
int fimg2d_ip_version_is(void)
{
	struct fimg2d_platdata *pdata = to_fimg2d_plat(ctrl->dev);

	return pdata->ip_ver;
}
Beispiel #16
0
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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
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);
}
Beispiel #20
0
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;
}