blob: 6481d9c3cbb83b39323d7ecc2df71bcd72f5178b [file] [log] [blame]
/*
* drivers/amlogic/media/common/ge2d/ge2d_main.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
/* Linux Headers */
#include <linux/module.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/list.h>
#include <linux/uaccess.h>
#include <linux/sysfs.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/reset.h>
#include <linux/clk.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif
/* Amlogic Headers */
#include <linux/amlogic/media/ge2d/ge2d.h>
#include <linux/amlogic/media/ge2d/ge2d_cmd.h>
#include <linux/amlogic/media/registers/regs/ao_regs.h>
#include <linux/amlogic/media/vpu/vpu.h>
#include <linux/amlogic/cpu_version.h>
#ifdef CONFIG_AMLOGIC_ION
#include <meson_ion.h>
#endif
/* Local Headers */
#include "ge2dgen.h"
#include "ge2d_log.h"
#include "ge2d_wq.h"
#include "ge2d_dmabuf.h"
#define GE2D_CLASS_NAME "ge2d"
#define MAX_GE2D_CLK 500000000
#define HHI_MEM_PD_REG0 0x40
#define RESET2_LEVEL 0x422
struct ge2d_device_s {
char name[20];
atomic_t open_count;
int major;
unsigned int dbg_enable;
struct class *cla;
struct device *dev;
};
void __iomem *ge2d_reg_map;
static struct ge2d_device_s ge2d_device;
static DEFINE_MUTEX(ge2d_mutex);
unsigned int ge2d_log_level;
unsigned int ge2d_dump_reg_enable;
unsigned int ge2d_dump_reg_cnt;
#ifdef CONFIG_AMLOGIC_ION
struct ion_client *ge2d_ion_client;
#endif
struct ge2d_device_data_s ge2d_meson_dev;
static int init_ge2d_device(void);
static int remove_ge2d_device(void);
static int ge2d_open(struct inode *inode, struct file *file);
static long ge2d_ioctl(struct file *filp, unsigned int cmd,
unsigned long args);
#ifdef CONFIG_COMPAT
static long ge2d_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long args);
#endif
static int ge2d_release(struct inode *inode, struct file *file);
static ssize_t log_level_show(struct class *cla,
struct class_attribute *attr,
char *buf);
static ssize_t log_level_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count);
static ssize_t dump_reg_enable_show(struct class *cla,
struct class_attribute *attr,
char *buf);
static ssize_t dump_reg_enable_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count);
static ssize_t dump_reg_cnt_show(struct class *cla,
struct class_attribute *attr,
char *buf);
static ssize_t dump_reg_cnt_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count);
static const struct file_operations ge2d_fops = {
.owner = THIS_MODULE,
.open = ge2d_open,
.unlocked_ioctl = ge2d_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ge2d_compat_ioctl,
#endif
.release = ge2d_release,
};
static struct class_attribute ge2d_class_attrs[] = {
__ATTR(wq_status, 0644,
work_queue_status_show, NULL),
__ATTR(fq_status, 0644,
free_queue_status_show, NULL),
__ATTR(log_level, 0644,
log_level_show, log_level_store),
__ATTR(dump_reg_enable, 0644,
dump_reg_enable_show, dump_reg_enable_store),
__ATTR(dump_reg_cnt, 0644,
dump_reg_cnt_show, dump_reg_cnt_store),
__ATTR_NULL
};
static struct class ge2d_class = {
.name = GE2D_CLASS_NAME,
.class_attrs = ge2d_class_attrs,
};
static ssize_t dump_reg_enable_show(struct class *cla,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", ge2d_dump_reg_enable);
}
static ssize_t dump_reg_enable_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
ge2d_log_info("ge2d dump_reg_enbale: %d->%d\n",
ge2d_dump_reg_enable, res);
ge2d_dump_reg_enable = res;
return count;
}
static ssize_t dump_reg_cnt_show(struct class *cla,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", ge2d_dump_reg_cnt);
}
static ssize_t dump_reg_cnt_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
ge2d_log_info("ge2d dump_reg: %d->%d\n", ge2d_dump_reg_cnt, res);
ge2d_dump_reg_cnt = res;
return count;
}
static ssize_t log_level_show(struct class *cla,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", ge2d_log_level);
}
static ssize_t log_level_store(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
ge2d_log_info("ge2d log_level: %d->%d\n", ge2d_log_level, res);
ge2d_log_level = res;
return count;
}
static int ge2d_open(struct inode *inode, struct file *file)
{
struct ge2d_context_s *context = NULL;
/* we create one ge2d workqueue for this file handler. */
context = create_ge2d_work_queue();
if (!context) {
ge2d_log_err("can't create work queue\n");
return -1;
}
file->private_data = context;
atomic_inc(&ge2d_device.open_count);
return 0;
}
static int ge2d_ioctl_config_ex_mem(struct ge2d_context_s *context,
unsigned int cmd, unsigned long args)
{
struct config_para_ex_memtype_s *ge2d_config_ex_mem;
struct config_ge2d_para_ex_s ge2d_para_config;
int ret = 0;
#ifdef CONFIG_COMPAT
struct compat_config_para_ex_memtype_s __user *uf_ex_mem;
struct compat_config_ge2d_para_ex_s __user *uf_ge2d_para;
int r = 0;
int i, j;
#endif
void __user *argp = (void __user *)args;
memset(&ge2d_para_config, 0, sizeof(struct config_ge2d_para_ex_s));
switch (cmd) {
case GE2D_CONFIG_EX_MEM:
ret = copy_from_user(&ge2d_para_config, argp,
sizeof(struct config_ge2d_para_ex_s));
ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype);
ret = ge2d_context_config_ex_mem(context, ge2d_config_ex_mem);
break;
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32_MEM:
uf_ge2d_para = (struct compat_config_ge2d_para_ex_s *)argp;
r |= get_user(ge2d_para_config.para_config_memtype.ge2d_magic,
&uf_ge2d_para->para_config_memtype.ge2d_magic);
ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype);
if (ge2d_para_config.para_config_memtype.ge2d_magic
== sizeof(struct config_para_ex_memtype_s)) {
struct config_para_ex_ion_s *pge2d_config_ex;
uf_ex_mem =
(struct compat_config_para_ex_memtype_s *)argp;
pge2d_config_ex =
&(ge2d_config_ex_mem->_ge2d_config_ex);
r = copy_from_user(
&pge2d_config_ex->src_para,
&uf_ex_mem->_ge2d_config_ex.src_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(
&pge2d_config_ex->src2_para,
&uf_ex_mem->_ge2d_config_ex.src2_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(
&pge2d_config_ex->dst_para,
&uf_ex_mem->_ge2d_config_ex.dst_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(&pge2d_config_ex->src_key,
&uf_ex_mem->_ge2d_config_ex.src_key,
sizeof(struct src_key_ctrl_s));
r |= copy_from_user(&pge2d_config_ex->src2_key,
&uf_ex_mem->_ge2d_config_ex.src2_key,
sizeof(struct src_key_ctrl_s));
r |= get_user(pge2d_config_ex->src1_cmult_asel,
&uf_ex_mem->_ge2d_config_ex.src1_cmult_asel);
r |= get_user(pge2d_config_ex->src2_cmult_asel,
&uf_ex_mem->_ge2d_config_ex.src2_cmult_asel);
r |= get_user(pge2d_config_ex->alu_const_color,
&uf_ex_mem->_ge2d_config_ex.alu_const_color);
r |= get_user(pge2d_config_ex->src1_gb_alpha_en,
&uf_ex_mem->_ge2d_config_ex.src1_gb_alpha_en);
r |= get_user(pge2d_config_ex->src1_gb_alpha,
&uf_ex_mem->_ge2d_config_ex.src1_gb_alpha);
#ifdef CONFIG_GE2D_SRC2
r |= get_user(pge2d_config_ex->src2_gb_alpha_en,
&uf_ex_mem->_ge2d_config_ex.src2_gb_alpha_en);
r |= get_user(pge2d_config_ex->src2_gb_alpha,
&uf_ex_mem->_ge2d_config_ex.src2_gb_alpha);
#endif
r |= get_user(pge2d_config_ex->op_mode,
&uf_ex_mem->_ge2d_config_ex.op_mode);
r |= get_user(pge2d_config_ex->bitmask_en,
&uf_ex_mem->_ge2d_config_ex.bitmask_en);
r |= get_user(pge2d_config_ex->bytemask_only,
&uf_ex_mem->_ge2d_config_ex.bytemask_only);
r |= get_user(pge2d_config_ex->bitmask,
&uf_ex_mem->_ge2d_config_ex.bitmask);
r |= get_user(pge2d_config_ex->dst_xy_swap,
&uf_ex_mem->_ge2d_config_ex.dst_xy_swap);
r |= get_user(pge2d_config_ex->hf_init_phase,
&uf_ex_mem->_ge2d_config_ex.hf_init_phase);
r |= get_user(pge2d_config_ex->hf_rpt_num,
&uf_ex_mem->_ge2d_config_ex.hf_rpt_num);
r |= get_user(pge2d_config_ex->hsc_start_phase_step,
&uf_ex_mem->_ge2d_config_ex
.hsc_start_phase_step);
r |= get_user(pge2d_config_ex->hsc_phase_slope,
&uf_ex_mem->_ge2d_config_ex.hsc_phase_slope);
r |= get_user(pge2d_config_ex->vf_init_phase,
&uf_ex_mem->_ge2d_config_ex.vf_init_phase);
r |= get_user(pge2d_config_ex->vf_rpt_num,
&uf_ex_mem->_ge2d_config_ex.vf_rpt_num);
r |= get_user(pge2d_config_ex->vsc_start_phase_step,
&uf_ex_mem->_ge2d_config_ex
.vsc_start_phase_step);
r |= get_user(pge2d_config_ex->vsc_phase_slope,
&uf_ex_mem->_ge2d_config_ex.vsc_phase_slope);
r |= get_user(
pge2d_config_ex->src1_vsc_phase0_always_en,
&uf_ex_mem->_ge2d_config_ex
.src1_vsc_phase0_always_en);
r |= get_user(
pge2d_config_ex->src1_hsc_phase0_always_en,
&uf_ex_mem->_ge2d_config_ex
.src1_hsc_phase0_always_en);
r |= get_user(
pge2d_config_ex->src1_hsc_rpt_ctrl,
&uf_ex_mem->_ge2d_config_ex.src1_hsc_rpt_ctrl);
r |= get_user(
pge2d_config_ex->src1_vsc_rpt_ctrl,
&uf_ex_mem->_ge2d_config_ex.src1_vsc_rpt_ctrl);
for (i = 0; i < 4; i++) {
struct config_planes_ion_s *psrc_planes;
psrc_planes =
&pge2d_config_ex->src_planes[i];
r |= get_user(psrc_planes->addr,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].addr);
r |= get_user(psrc_planes->w,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].w);
r |= get_user(psrc_planes->h,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].h);
r |= get_user(psrc_planes->shared_fd,
&uf_ex_mem->_ge2d_config_ex
.src_planes[i].shared_fd);
}
for (i = 0; i < 4; i++) {
struct config_planes_ion_s *psrc2_planes;
psrc2_planes =
&pge2d_config_ex->src2_planes[i];
r |= get_user(psrc2_planes->addr,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].addr);
r |= get_user(psrc2_planes->w,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].w);
r |= get_user(psrc2_planes->h,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].h);
r |= get_user(psrc2_planes->shared_fd,
&uf_ex_mem->_ge2d_config_ex
.src2_planes[i].shared_fd);
}
for (j = 0; j < 4; j++) {
struct config_planes_ion_s *pdst_planes;
pdst_planes =
&pge2d_config_ex->dst_planes[j];
r |= get_user(pdst_planes->addr,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].addr);
r |= get_user(pdst_planes->w,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].w);
r |= get_user(pdst_planes->h,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].h);
r |= get_user(pdst_planes->shared_fd,
&uf_ex_mem->_ge2d_config_ex
.dst_planes[j].shared_fd);
}
r |= get_user(ge2d_config_ex_mem->src1_mem_alloc_type,
&uf_ex_mem->src1_mem_alloc_type);
r |= get_user(ge2d_config_ex_mem->src2_mem_alloc_type,
&uf_ex_mem->src2_mem_alloc_type);
r |= get_user(ge2d_config_ex_mem->dst_mem_alloc_type,
&uf_ex_mem->dst_mem_alloc_type);
}
if (r) {
pr_err("GE2D_CONFIG_EX32 get parameter failed .\n");
return -EFAULT;
}
ret = ge2d_context_config_ex_mem(context, ge2d_config_ex_mem);
break;
#endif
}
return ret;
}
static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
struct ge2d_context_s *context = NULL;
struct config_para_s ge2d_config;
struct ge2d_para_s para;
struct config_para_ex_s ge2d_config_ex;
struct config_para_ex_ion_s ge2d_config_ex_ion;
struct ge2d_dmabuf_req_s ge2d_req_buf;
struct ge2d_dmabuf_exp_s ge2d_exp_buf;
int ret = 0;
#ifdef CONFIG_COMPAT
struct compat_config_para_s __user *uf;
struct compat_config_para_ex_s __user *uf_ex;
struct compat_config_para_ex_ion_s __user *uf_ex_ion;
int r = 0;
int i, j;
#endif
int cap_mask = 0;
int index = 0, dma_fd;
void __user *argp = (void __user *)args;
context = (struct ge2d_context_s *)filp->private_data;
memset(&ge2d_config, 0, sizeof(struct config_para_s));
memset(&ge2d_config_ex, 0, sizeof(struct config_para_ex_s));
memset(&ge2d_config_ex_ion, 0, sizeof(struct config_para_ex_ion_s));
memset(&ge2d_req_buf, 0, sizeof(struct ge2d_dmabuf_req_s));
memset(&ge2d_exp_buf, 0, sizeof(struct ge2d_dmabuf_exp_s));
#ifdef CONFIG_AMLOGIC_MEDIA_GE2D_MORE_SECURITY
switch (cmd) {
case GE2D_CONFIG:
case GE2D_CONFIG32:
case GE2D_CONFIG_EX:
case GE2D_CONFIG_EX32:
pr_err("ioctl not support.\n");
return -EINVAL;
}
#endif
switch (cmd) {
case GE2D_GET_CAP:
cap_mask = ge2d_meson_dev.src2_alp & 0x1;
put_user(cap_mask, (int __user *)argp);
break;
case GE2D_CONFIG:
case GE2D_SRCCOLORKEY:
ret = copy_from_user(&ge2d_config,
argp, sizeof(struct config_para_s));
break;
#ifdef CONFIG_COMPAT
case GE2D_SRCCOLORKEY32:
uf = (struct compat_config_para_s *)argp;
r = get_user(ge2d_config.src_dst_type, &uf->src_dst_type);
r |= get_user(ge2d_config.alu_const_color,
&uf->alu_const_color);
r |= get_user(ge2d_config.src_format, &uf->src_format);
r |= get_user(ge2d_config.dst_format, &uf->dst_format);
for (i = 0; i < 4; i++) {
r |= get_user(ge2d_config.src_planes[i].addr,
&uf->src_planes[i].addr);
r |= get_user(ge2d_config.src_planes[i].w,
&uf->src_planes[i].w);
r |= get_user(ge2d_config.src_planes[i].h,
&uf->src_planes[i].h);
}
for (j = 0; j < 4; j++) {
r |= get_user(ge2d_config.dst_planes[j].addr,
&uf->dst_planes[j].addr);
r |= get_user(ge2d_config.dst_planes[j].w,
&uf->dst_planes[j].w);
r |= get_user(ge2d_config.dst_planes[j].h,
&uf->dst_planes[j].h);
}
r |= copy_from_user(&ge2d_config.src_key, &uf->src_key,
sizeof(struct src_key_ctrl_s));
if (r) {
pr_err("GE2D_SRCCOLORKEY32 get parameter failed .\n");
return -EFAULT;
}
break;
#endif
#ifdef CONFIG_COMPAT
case GE2D_CONFIG32:
uf = (struct compat_config_para_s *)argp;
r = get_user(ge2d_config.src_dst_type, &uf->src_dst_type);
r |= get_user(ge2d_config.alu_const_color,
&uf->alu_const_color);
r |= get_user(ge2d_config.src_format, &uf->src_format);
r |= get_user(ge2d_config.dst_format, &uf->dst_format);
for (i = 0; i < 4; i++) {
r |= get_user(ge2d_config.src_planes[i].addr,
&uf->src_planes[i].addr);
r |= get_user(ge2d_config.src_planes[i].w,
&uf->src_planes[i].w);
r |= get_user(ge2d_config.src_planes[i].h,
&uf->src_planes[i].h);
}
for (j = 0; j < 4; j++) {
r |= get_user(ge2d_config.dst_planes[j].addr,
&uf->dst_planes[j].addr);
r |= get_user(ge2d_config.dst_planes[j].w,
&uf->dst_planes[j].w);
r |= get_user(ge2d_config.dst_planes[j].h,
&uf->dst_planes[j].h);
}
r |= copy_from_user(&ge2d_config.src_key, &uf->src_key,
sizeof(struct src_key_ctrl_s));
if (r) {
pr_err("GE2D_CONFIG32 get parameter failed .\n");
return -EFAULT;
}
break;
#endif
case GE2D_CONFIG_EX:
ret = copy_from_user(&ge2d_config_ex, argp,
sizeof(struct config_para_ex_s));
break;
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32:
uf_ex = (struct compat_config_para_ex_s *)argp;
r = copy_from_user(&ge2d_config_ex.src_para, &uf_ex->src_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(&ge2d_config_ex.src2_para,
&uf_ex->src2_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(&ge2d_config_ex.dst_para, &uf_ex->dst_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(&ge2d_config_ex.src_key, &uf_ex->src_key,
sizeof(struct src_key_ctrl_s));
r |= copy_from_user(&ge2d_config_ex.src2_key, &uf_ex->src2_key,
sizeof(struct src_key_ctrl_s));
r |= get_user(ge2d_config_ex.alu_const_color,
&uf_ex->alu_const_color);
r |= get_user(ge2d_config_ex.src1_gb_alpha,
&uf_ex->src1_gb_alpha);
r |= get_user(ge2d_config_ex.op_mode, &uf_ex->op_mode);
r |= get_user(ge2d_config_ex.bitmask_en, &uf_ex->bitmask_en);
r |= get_user(ge2d_config_ex.bytemask_only,
&uf_ex->bytemask_only);
r |= get_user(ge2d_config_ex.bitmask, &uf_ex->bitmask);
r |= get_user(ge2d_config_ex.dst_xy_swap, &uf_ex->dst_xy_swap);
r |= get_user(ge2d_config_ex.hf_init_phase,
&uf_ex->hf_init_phase);
r |= get_user(ge2d_config_ex.hf_rpt_num, &uf_ex->hf_rpt_num);
r |= get_user(ge2d_config_ex.hsc_start_phase_step,
&uf_ex->hsc_start_phase_step);
r |= get_user(ge2d_config_ex.hsc_phase_slope,
&uf_ex->hsc_phase_slope);
r |= get_user(ge2d_config_ex.vf_init_phase,
&uf_ex->vf_init_phase);
r |= get_user(ge2d_config_ex.vf_rpt_num, &uf_ex->vf_rpt_num);
r |= get_user(ge2d_config_ex.vsc_start_phase_step,
&uf_ex->vsc_start_phase_step);
r |= get_user(ge2d_config_ex.vsc_phase_slope,
&uf_ex->vsc_phase_slope);
r |= get_user(ge2d_config_ex.src1_vsc_phase0_always_en,
&uf_ex->src1_vsc_phase0_always_en);
r |= get_user(ge2d_config_ex.src1_hsc_phase0_always_en,
&uf_ex->src1_hsc_phase0_always_en);
r |= get_user(ge2d_config_ex.src1_hsc_rpt_ctrl,
&uf_ex->src1_hsc_rpt_ctrl);
r |= get_user(ge2d_config_ex.src1_vsc_rpt_ctrl,
&uf_ex->src1_vsc_rpt_ctrl);
for (i = 0; i < 4; i++) {
r |= get_user(ge2d_config_ex.src_planes[i].addr,
&uf_ex->src_planes[i].addr);
r |= get_user(ge2d_config_ex.src_planes[i].w,
&uf_ex->src_planes[i].w);
r |= get_user(ge2d_config_ex.src_planes[i].h,
&uf_ex->src_planes[i].h);
}
for (i = 0; i < 4; i++) {
r |= get_user(ge2d_config_ex.src2_planes[i].addr,
&uf_ex->src2_planes[i].addr);
r |= get_user(ge2d_config_ex.src2_planes[i].w,
&uf_ex->src2_planes[i].w);
r |= get_user(ge2d_config_ex.src2_planes[i].h,
&uf_ex->src2_planes[i].h);
}
for (j = 0; j < 4; j++) {
r |= get_user(ge2d_config_ex.dst_planes[j].addr,
&uf_ex->dst_planes[j].addr);
r |= get_user(ge2d_config_ex.dst_planes[j].w,
&uf_ex->dst_planes[j].w);
r |= get_user(ge2d_config_ex.dst_planes[j].h,
&uf_ex->dst_planes[j].h);
}
if (r) {
pr_err("GE2D_CONFIG_EX32 get parameter failed .\n");
return -EFAULT;
}
break;
#endif
case GE2D_CONFIG_EX_ION:
ret = copy_from_user(&ge2d_config_ex_ion, argp,
sizeof(struct config_para_ex_ion_s));
break;
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32_ION:
uf_ex_ion = (struct compat_config_para_ex_ion_s *)argp;
r = copy_from_user(
&ge2d_config_ex_ion.src_para,
&uf_ex_ion->src_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(
&ge2d_config_ex_ion.src2_para,
&uf_ex_ion->src2_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(
&ge2d_config_ex_ion.dst_para,
&uf_ex_ion->dst_para,
sizeof(struct src_dst_para_ex_s));
r |= copy_from_user(&ge2d_config_ex_ion.src_key,
&uf_ex_ion->src_key,
sizeof(struct src_key_ctrl_s));
r |= copy_from_user(&ge2d_config_ex_ion.src2_key,
&uf_ex_ion->src2_key,
sizeof(struct src_key_ctrl_s));
r |= get_user(ge2d_config_ex_ion.src1_cmult_asel,
&uf_ex_ion->src1_cmult_asel);
r |= get_user(ge2d_config_ex_ion.src2_cmult_asel,
&uf_ex_ion->src2_cmult_asel);
r |= get_user(ge2d_config_ex_ion.alu_const_color,
&uf_ex_ion->alu_const_color);
r |= get_user(ge2d_config_ex_ion.src1_gb_alpha_en,
&uf_ex_ion->src1_gb_alpha_en);
r |= get_user(ge2d_config_ex_ion.src1_gb_alpha,
&uf_ex_ion->src1_gb_alpha);
#ifdef CONFIG_GE2D_SRC2
r |= get_user(ge2d_config_ex_ion.src2_gb_alpha_en,
&uf_ex_ion->src2_gb_alpha_en);
r |= get_user(ge2d_config_ex_ion.src2_gb_alpha,
&uf_ex_ion->src2_gb_alpha);
#endif
r |= get_user(ge2d_config_ex_ion.op_mode,
&uf_ex_ion->op_mode);
r |= get_user(ge2d_config_ex_ion.bitmask_en,
&uf_ex_ion->bitmask_en);
r |= get_user(ge2d_config_ex_ion.bytemask_only,
&uf_ex_ion->bytemask_only);
r |= get_user(ge2d_config_ex_ion.bitmask,
&uf_ex_ion->bitmask);
r |= get_user(ge2d_config_ex_ion.dst_xy_swap,
&uf_ex_ion->dst_xy_swap);
r |= get_user(ge2d_config_ex_ion.hf_init_phase,
&uf_ex_ion->hf_init_phase);
r |= get_user(ge2d_config_ex_ion.hf_rpt_num,
&uf_ex_ion->hf_rpt_num);
r |= get_user(ge2d_config_ex_ion.hsc_start_phase_step,
&uf_ex_ion->hsc_start_phase_step);
r |= get_user(ge2d_config_ex_ion.hsc_phase_slope,
&uf_ex_ion->hsc_phase_slope);
r |= get_user(ge2d_config_ex_ion.vf_init_phase,
&uf_ex_ion->vf_init_phase);
r |= get_user(ge2d_config_ex_ion.vf_rpt_num,
&uf_ex_ion->vf_rpt_num);
r |= get_user(ge2d_config_ex_ion.vsc_start_phase_step,
&uf_ex_ion->vsc_start_phase_step);
r |= get_user(ge2d_config_ex_ion.vsc_phase_slope,
&uf_ex_ion->vsc_phase_slope);
r |= get_user(
ge2d_config_ex_ion.src1_vsc_phase0_always_en,
&uf_ex_ion->src1_vsc_phase0_always_en);
r |= get_user(
ge2d_config_ex_ion.src1_hsc_phase0_always_en,
&uf_ex_ion->src1_hsc_phase0_always_en);
r |= get_user(
ge2d_config_ex_ion.src1_hsc_rpt_ctrl,
&uf_ex_ion->src1_hsc_rpt_ctrl);
r |= get_user(
ge2d_config_ex_ion.src1_vsc_rpt_ctrl,
&uf_ex_ion->src1_vsc_rpt_ctrl);
for (i = 0; i < 4; i++) {
struct config_planes_ion_s *psrc_planes;
psrc_planes =
&ge2d_config_ex_ion.src_planes[i];
r |= get_user(psrc_planes->addr,
&uf_ex_ion->src_planes[i].addr);
r |= get_user(psrc_planes->w,
&uf_ex_ion->src_planes[i].w);
r |= get_user(psrc_planes->h,
&uf_ex_ion->src_planes[i].h);
r |= get_user(psrc_planes->shared_fd,
&uf_ex_ion->src_planes[i].shared_fd);
}
for (i = 0; i < 4; i++) {
struct config_planes_ion_s *psrc2_planes;
psrc2_planes =
&ge2d_config_ex_ion.src2_planes[i];
r |= get_user(psrc2_planes->addr,
&uf_ex_ion->src2_planes[i].addr);
r |= get_user(psrc2_planes->w,
&uf_ex_ion->src2_planes[i].w);
r |= get_user(psrc2_planes->h,
&uf_ex_ion->src2_planes[i].h);
r |= get_user(psrc2_planes->shared_fd,
&uf_ex_ion->src2_planes[i].shared_fd);
}
for (j = 0; j < 4; j++) {
struct config_planes_ion_s *pdst_planes;
pdst_planes =
&ge2d_config_ex_ion.dst_planes[j];
r |= get_user(pdst_planes->addr,
&uf_ex_ion->dst_planes[j].addr);
r |= get_user(pdst_planes->w,
&uf_ex_ion->dst_planes[j].w);
r |= get_user(pdst_planes->h,
&uf_ex_ion->dst_planes[j].h);
r |= get_user(pdst_planes->shared_fd,
&uf_ex_ion->dst_planes[j].shared_fd);
}
if (r) {
pr_err("GE2D_CONFIG_EX32 get parameter failed .\n");
return -EFAULT;
}
break;
#endif
case GE2D_SET_COEF:
case GE2D_ANTIFLICKER_ENABLE:
break;
case GE2D_REQUEST_BUFF:
ret = copy_from_user(&ge2d_req_buf, argp,
sizeof(struct ge2d_dmabuf_req_s));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_EXP_BUFF:
ret = copy_from_user(&ge2d_exp_buf, argp,
sizeof(struct ge2d_dmabuf_exp_s));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_FREE_BUFF:
ret = copy_from_user(&index, argp,
sizeof(int));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_SYNC_DEVICE:
case GE2D_SYNC_CPU:
ret = copy_from_user(&dma_fd, argp,
sizeof(int));
if (ret < 0) {
pr_err("Error user param\n");
return -EINVAL;
}
break;
case GE2D_CONFIG_OLD:
case GE2D_CONFIG_EX_OLD:
case GE2D_SRCCOLORKEY_OLD:
pr_err("ioctl not support yed.\n");
return -EINVAL;
default:
ret = copy_from_user(&para, argp, sizeof(struct ge2d_para_s));
break;
}
switch (cmd) {
case GE2D_CONFIG:
#ifdef CONFIG_COMPAT
case GE2D_CONFIG32:
#endif
ret = ge2d_context_config(context, &ge2d_config);
break;
case GE2D_CONFIG_EX:
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32:
#endif
ret = ge2d_context_config_ex(context, &ge2d_config_ex);
break;
case GE2D_CONFIG_EX_ION:
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32_ION:
#endif
ret = ge2d_context_config_ex_ion(context, &ge2d_config_ex_ion);
break;
case GE2D_CONFIG_EX_MEM:
#ifdef CONFIG_COMPAT
case GE2D_CONFIG_EX32_MEM:
#endif
ret = ge2d_ioctl_config_ex_mem(context, cmd, args);
break;
case GE2D_SET_COEF:
ge2d_wq_set_scale_coef(context, args & 0xff, args >> 16);
break;
case GE2D_ANTIFLICKER_ENABLE:
ge2d_antiflicker_enable(context, args);
break;
case GE2D_SRCCOLORKEY:
#ifdef CONFIG_COMPAT
case GE2D_SRCCOLORKEY32:
#endif
ge2d_log_dbg("src colorkey...,key_enable=0x%x,key_color=0x%x,key_mask=0x%x,key_mode=0x%x\n",
ge2d_config.src_key.key_enable,
ge2d_config.src_key.key_color,
ge2d_config.src_key.key_mask,
ge2d_config.src_key.key_mode);
ge2dgen_src_key(context, ge2d_config.src_key.key_enable,
ge2d_config.src_key.key_color,
ge2d_config.src_key.key_mask,
ge2d_config.src_key.key_mode); /* RGBA MODE */
break;
case GE2D_FILLRECTANGLE:
ge2d_log_dbg("fill rect...,x=%d,y=%d,w=%d,h=%d,color=0x%x\n",
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.color);
fillrect(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.color);
break;
case GE2D_FILLRECTANGLE_NOBLOCK:
ge2d_log_dbg("fill rect noblk\t");
ge2d_log_dbg("x=%d,y=%d,w=%d,h=%d,color=0x%x\n",
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.color);
fillrect_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.color);
break;
case GE2D_STRETCHBLIT:
/* stretch blit */
ge2d_log_dbg("stretchblt\t");
ge2d_log_dbg("x=%d,y=%d,w=%d,h=%d,dst.w=%d,dst.h=%d\n",
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.w, para.dst_rect.h);
stretchblt(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h);
break;
case GE2D_STRETCHBLIT_NOBLOCK:
/* stretch blit */
ge2d_log_dbg("stretchblt noblk\t");
ge2d_log_dbg("x=%d,y=%d,w=%d,h=%d,dst.w=%d,dst.h=%d\n",
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.w, para.dst_rect.h);
stretchblt_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h);
break;
case GE2D_BLIT:
/* bitblt */
ge2d_log_dbg("blit...\n");
bitblt(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y);
break;
case GE2D_BLIT_NOBLOCK:
/* bitblt */
ge2d_log_dbg("blit...,noblk\n");
bitblt_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y);
break;
case GE2D_BLEND:
ge2d_log_dbg("blend ...\n");
blend(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.src2_rect.x, para.src2_rect.y,
para.src2_rect.w, para.src2_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h,
para.op);
break;
case GE2D_BLEND_NOBLOCK:
ge2d_log_dbg("blend ...,noblk\n");
blend_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.src2_rect.x, para.src2_rect.y,
para.src2_rect.w, para.src2_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h,
para.op);
break;
case GE2D_BLEND_NOALPHA:
ge2d_log_dbg("blend_noalpha ...\n");
blend_noalpha(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.src2_rect.x, para.src2_rect.y,
para.src2_rect.w, para.src2_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h,
para.op);
break;
case GE2D_BLEND_NOALPHA_NOBLOCK:
ge2d_log_dbg("blend_noalpha ...,noblk\n");
blend_noalpha_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.src2_rect.x, para.src2_rect.y,
para.src2_rect.w, para.src2_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h,
para.op);
break;
case GE2D_BLIT_NOALPHA:
/* bitblt_noalpha */
ge2d_log_dbg("blit_noalpha...\n");
bitblt_noalpha(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y);
break;
case GE2D_BLIT_NOALPHA_NOBLOCK:
/* bitblt_noalpha */
ge2d_log_dbg("blit_noalpha...,noblk\n");
bitblt_noalpha_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y);
break;
case GE2D_STRETCHBLIT_NOALPHA:
/* stretch blit */
ge2d_log_dbg("stretchblt_noalpha\t");
ge2d_log_dbg("x=%d,y=%d,w=%d,h=%d,dst.w=%d,dst.h=%d\n",
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.w, para.dst_rect.h);
stretchblt_noalpha(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h);
break;
case GE2D_STRETCHBLIT_NOALPHA_NOBLOCK:
/* stretch blit */
ge2d_log_dbg("stretchblt_noalpha_noblk\t");
ge2d_log_dbg("x=%d,y=%d,w=%d,h=%d,dst.w=%d,dst.h=%d\n",
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.w, para.dst_rect.h);
stretchblt_noalpha_noblk(context,
para.src1_rect.x, para.src1_rect.y,
para.src1_rect.w, para.src1_rect.h,
para.dst_rect.x, para.dst_rect.y,
para.dst_rect.w, para.dst_rect.h);
break;
case GE2D_REQUEST_BUFF:
ret = ge2d_buffer_alloc(&ge2d_req_buf);
if (ret == 0)
ret = copy_to_user(argp, &ge2d_req_buf,
sizeof(struct ge2d_dmabuf_req_s));
break;
case GE2D_EXP_BUFF:
ret = ge2d_buffer_export(&ge2d_exp_buf);
if (ret == 0)
ret = copy_to_user(argp, &ge2d_exp_buf,
sizeof(struct ge2d_dmabuf_exp_s));
break;
case GE2D_FREE_BUFF:
ret = ge2d_buffer_free(index);
break;
case GE2D_SYNC_DEVICE:
ge2d_buffer_dma_flush(dma_fd);
break;
case GE2D_SYNC_CPU:
ge2d_buffer_cache_flush(dma_fd);
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ge2d_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long args)
{
unsigned long ret;
args = (unsigned long)compat_ptr(args);
ret = ge2d_ioctl(filp, cmd, args);
return ret;
}
#endif
static int ge2d_release(struct inode *inode, struct file *file)
{
struct ge2d_context_s *context = NULL;
context = (struct ge2d_context_s *)file->private_data;
if (context && (destroy_ge2d_work_queue(context) == 0)) {
atomic_dec(&ge2d_device.open_count);
return 0;
}
ge2d_log_dbg("release one ge2d device\n");
return -1;
}
static struct ge2d_ctrl_s default_poweron_ctrl[] = {
/* power up ge2d */
{GEN_PWR_SLEEP0, AO_RTI_GEN_PWR_SLEEP0, 0, 19, 1, 0},
/* Power up memory */
{MEM_PD_REG0, HHI_MEM_PD_REG0, 0, 18, 8, 100},
/* reset */
{CBUS_BASE, RESET2_LEVEL, 0, 6, 1, 0},
/* remove isolation */
{GEN_PWR_ISO0, AO_RTI_GEN_PWR_ISO0, 0, 19, 1, 0},
/* pull up reset */
{CBUS_BASE, RESET2_LEVEL, 1, 6, 1, 0}
};
static struct ge2d_ctrl_s default_poweroff_ctrl[] = {
/* reset */
{CBUS_BASE, RESET2_LEVEL, 0, 6, 1, 0},
/* add isolation */
{GEN_PWR_ISO0, AO_RTI_GEN_PWR_ISO0, 1, 19, 1, 0},
/* Power down memory */
{MEM_PD_REG0, HHI_MEM_PD_REG0, 0xFF, 18, 8, 0},
/* power down ge2d */
{GEN_PWR_SLEEP0, AO_RTI_GEN_PWR_SLEEP0, 1, 19, 1, 0}
};
struct ge2d_power_table_s default_poweron_table = {5, default_poweron_ctrl};
struct ge2d_power_table_s default_poweroff_table = {4, default_poweroff_ctrl};
static struct ge2d_device_data_s ge2d_gxl = {
.ge2d_rate = 400000000,
.src2_alp = 0,
.canvas_status = 0,
.deep_color = 0,
.hang_flag = 0,
.fifo = 0,
.has_self_pwr = 0,
};
static struct ge2d_device_data_s ge2d_gxm = {
.ge2d_rate = 400000000,
.src2_alp = 0,
.canvas_status = 0,
.deep_color = 0,
.hang_flag = 0,
.fifo = 0,
.has_self_pwr = 0,
};
static struct ge2d_device_data_s ge2d_txl = {
.ge2d_rate = 400000000,
.src2_alp = 0,
.canvas_status = 0,
.deep_color = 1,
.hang_flag = 0,
.fifo = 0,
.has_self_pwr = 0,
};
static struct ge2d_device_data_s ge2d_txlx = {
.ge2d_rate = 400000000,
.src2_alp = 0,
.canvas_status = 0,
.deep_color = 1,
.hang_flag = 1,
.fifo = 1,
.has_self_pwr = 0,
};
static struct ge2d_device_data_s ge2d_axg = {
.ge2d_rate = 400000000,
.src2_alp = 0,
.canvas_status = 1,
.deep_color = 1,
.hang_flag = 1,
.fifo = 1,
.has_self_pwr = 0,
};
static struct ge2d_device_data_s ge2d_g12a = {
.ge2d_rate = 500000000,
.src2_alp = 1,
.canvas_status = 0,
.deep_color = 1,
.hang_flag = 1,
.fifo = 1,
.has_self_pwr = 0,
};
static struct ge2d_device_data_s ge2d_sm1 = {
.ge2d_rate = 500000000,
.src2_alp = 1,
.canvas_status = 0,
.deep_color = 1,
.hang_flag = 1,
.fifo = 1,
.has_self_pwr = 1,
.poweron_table = &default_poweron_table,
.poweroff_table = &default_poweroff_table,
};
static const struct of_device_id ge2d_dt_match[] = {
{
.compatible = "amlogic, ge2d-gxl",
.data = &ge2d_gxl,
},
{
.compatible = "amlogic, ge2d-gxm",
.data = &ge2d_gxm,
},
{
.compatible = "amlogic, ge2d-txl",
.data = &ge2d_txl,
},
{
.compatible = "amlogic, ge2d-txlx",
.data = &ge2d_txlx,
},
{
.compatible = "amlogic, ge2d-axg",
.data = &ge2d_axg,
},
{
.compatible = "amlogic, ge2d-g12a",
.data = &ge2d_g12a,
},
{
.compatible = "amlogic, ge2d-sm1",
.data = &ge2d_sm1,
},
{},
};
static int ge2d_probe(struct platform_device *pdev)
{
int ret = 0;
int irq = 0;
struct clk *clk_gate;
struct clk *clk_vapb0;
struct clk *clk;
struct resource res;
init_ge2d_device();
if (pdev->dev.of_node) {
const struct of_device_id *match;
struct ge2d_device_data_s *ge2d_meson;
struct device_node *of_node = pdev->dev.of_node;
match = of_match_node(ge2d_dt_match, of_node);
if (match) {
ge2d_meson = (struct ge2d_device_data_s *)match->data;
if (ge2d_meson)
memcpy(&ge2d_meson_dev, ge2d_meson,
sizeof(struct ge2d_device_data_s));
else {
pr_err("%s data NOT match\n", __func__);
return -ENODEV;
}
} else {
pr_err("%s NOT match\n", __func__);
return -ENODEV;
}
}
/* get interrupt resource */
irq = platform_get_irq_byname(pdev, "ge2d");
if (irq == -ENXIO) {
ge2d_log_err("get ge2d irq resource error\n");
ret = -ENXIO;
goto failed1;
}
clk_gate = devm_clk_get(&pdev->dev, "clk_ge2d_gate");
if (IS_ERR(clk_gate)) {
ge2d_log_err("cannot get clock\n");
clk_gate = NULL;
ret = -ENOENT;
goto failed1;
}
ge2d_log_info("clock source clk_ge2d_gate %p\n", clk_gate);
clk_prepare_enable(clk_gate);
clk = devm_clk_get(&pdev->dev, "clk_ge2d");
if (IS_ERR(clk)) {
ge2d_log_err("cannot get clock\n");
clk = NULL;
ret = -ENOENT;
goto failed1;
}
ge2d_log_info("clock clk_ge2d source %p\n", clk);
clk_prepare_enable(clk);
clk_vapb0 = devm_clk_get(&pdev->dev, "clk_vapb_0");
if (PTR_ERR(clk_vapb0) != -ENOENT) {
int vapb_rate, vpu_rate;
if (!IS_ERR(clk_vapb0)) {
ge2d_log_info("clock source clk_vapb_0 %p\n",
clk_vapb0);
vapb_rate = ge2d_meson_dev.ge2d_rate;
vpu_rate = get_vpu_clk();
ge2d_log_info(
"ge2d init clock is %d HZ, VPU clock is %d HZ\n",
vapb_rate, vpu_rate);
if (vpu_rate >= ge2d_meson_dev.ge2d_rate)
vapb_rate = ge2d_meson_dev.ge2d_rate;
else if (vpu_rate == 333330000)
vapb_rate = 333333333;
else if (vpu_rate == 166660000)
vapb_rate = 166666667;
else if (vapb_rate > vpu_rate)
vapb_rate = vpu_rate;
clk_set_rate(clk_vapb0, vapb_rate);
clk_prepare_enable(clk_vapb0);
vapb_rate = clk_get_rate(clk_vapb0);
ge2d_log_info("ge2d clock is %d MHZ\n",
vapb_rate/1000000);
}
}
ret = of_address_to_resource(pdev->dev.of_node, 0, &res);
if (ret == 0) {
ge2d_log_info("find address resource\n");
if (res.start != 0) {
ge2d_reg_map =
ioremap(res.start, resource_size(&res));
if (ge2d_reg_map) {
ge2d_log_info("map io source 0x%p,size=%d to 0x%p\n",
(void *)res.start,
(int)resource_size(&res),
ge2d_reg_map);
}
} else {
ge2d_reg_map = 0;
ge2d_log_info("ignore io source start %p,size=%d\n",
(void *)res.start, (int)resource_size(&res));
}
}
ret = of_reserved_mem_device_init(&(pdev->dev));
if (ret < 0)
ge2d_log_info("reserved mem init failed\n");
ret = ge2d_wq_init(pdev, irq, clk_gate);
clk_disable_unprepare(clk_gate);
#ifdef CONFIG_AMLOGIC_ION
if (!ge2d_ion_client)
ge2d_ion_client = meson_ion_client_create(-1, "meson-ge2d");
#endif
failed1:
return ret;
}
static int ge2d_remove(struct platform_device *pdev)
{
ge2d_log_info("%s\n", __func__);
ge2d_wq_deinit();
remove_ge2d_device();
return 0;
}
static struct platform_driver ge2d_driver = {
.probe = ge2d_probe,
.remove = ge2d_remove,
.driver = {
.name = "ge2d",
.of_match_table = ge2d_dt_match,
}
};
static int init_ge2d_device(void)
{
int ret = 0;
strcpy(ge2d_device.name, "ge2d");
ret = register_chrdev(0, ge2d_device.name, &ge2d_fops);
if (ret <= 0) {
ge2d_log_err("register ge2d device error\n");
return ret;
}
ge2d_device.major = ret;
ge2d_device.dbg_enable = 0;
ge2d_log_info("ge2d_dev major:%d\n", ret);
ret = class_register(&ge2d_class);
if (ret < 0) {
ge2d_log_err("error create ge2d class\n");
return ret;
}
ge2d_device.cla = &ge2d_class;
ge2d_device.dev = device_create(ge2d_device.cla,
NULL, MKDEV(ge2d_device.major,
0), NULL, ge2d_device.name);
if (IS_ERR(ge2d_device.dev)) {
ge2d_log_err("create ge2d device error\n");
class_unregister(ge2d_device.cla);
return -1;
}
return ret;
}
static int remove_ge2d_device(void)
{
if (!ge2d_device.cla)
return 0;
if (ge2d_device.dev)
device_destroy(ge2d_device.cla, MKDEV(ge2d_device.major, 0));
class_unregister(ge2d_device.cla);
unregister_chrdev(ge2d_device.major, ge2d_device.name);
return 0;
}
static int __init ge2d_init_module(void)
{
ge2d_log_info("%s\n", __func__);
if (platform_driver_register(&ge2d_driver)) {
ge2d_log_err("failed to register ge2d driver!\n");
return -ENODEV;
}
return 0;
}
static void __exit ge2d_remove_module(void)
{
platform_driver_unregister(&ge2d_driver);
ge2d_log_info("%s\n", __func__);
}
module_init(ge2d_init_module);
module_exit(ge2d_remove_module);