rk29: rm old vpu driver

This commit is contained in:
黄涛
2011-11-07 18:33:22 +08:00
parent 64268f118f
commit 77facb0000
3 changed files with 1 additions and 957 deletions

View File

@@ -178,19 +178,10 @@ config WIFI_CONTROL_FUNC
menu "RK29 VPU (Video Processing Unit) support"
config RK29_VPU
bool
depends on ARCH_RK29
default y
config RK29_VPU_SERVICE
bool "VPU service driver in kernel"
depends on ARCH_RK29
default y
config RK29_VPU_OLD
bool "Old version for RK29 VPU (Video Processing Unit)"
depends on ARCH_RK29 && !RK29_VPU_SERVICE
config RK29_VPU_DEBUG
bool "RK29 VPU debugging"
depends on RK29_VPU != n

View File

@@ -9,11 +9,9 @@ obj-$(CONFIG_USB_GADGET) += usb_detect.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_DDR_FREQ) += ddrfreq.o
obj-$(CONFIG_RK29_VPU) += vpu_mem.o
obj-$(CONFIG_RK29_VPU) += vpu_mem.o vpu_service.o
obj-$(CONFIG_RK29_I2C_INSRAM) += i2c_sram.o
obj-y += spi_sram.o
obj-$(CONFIG_RK29_VPU_SERVICE) += vpu_service.o
obj-$(CONFIG_RK29_VPU_OLD) += vpu.o
obj-$(CONFIG_RK29_PWM_INSRAM) += pwm_sram.o
obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o board-rk29sdk-power.o
obj-$(CONFIG_MACH_RK29_P91) += board-rk29-p91.o board-rk29-p91-key.o board-rk29sdk-rfkill.o board-rk29sdk-power.o

View File

@@ -1,945 +0,0 @@
/* arch/arm/mach-rk29/vpu.c
*
* Copyright (C) 2010 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifdef CONFIG_RK29_VPU_DEBUG
#define DEBUG
#define pr_fmt(fmt) "VPU: %s: " fmt, __func__
#else
#define pr_fmt(fmt) "VPU: " fmt
#endif
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <mach/irqs.h>
#include <mach/vpu.h>
#include <mach/rk29_iomap.h>
#include <mach/pmu.h>
#include <mach/cru.h>
#define DEC_INTERRUPT_REGISTER 1
#define PP_INTERRUPT_REGISTER 60
#define ENC_INTERRUPT_REGISTER 1
#define DEC_INTERRUPT_BIT 0x100
#define PP_INTERRUPT_BIT 0x100
#define ENC_INTERRUPT_BIT 0x1
#define DEC_IO_SIZE ((100 + 1) * 4) /* bytes */
#define ENC_IO_SIZE (96 * 4) /* bytes */
typedef enum
{
VPU_ENC = 0x0,
VPU_DEC = 0x1,
VPU_PP = 0x2,
VPU_DEC_PP = 0x3,
VPU_TYPE_BUTT ,
} VPU_CLIENT_TYPE;
#define REG_NUM_DEC (60)
#define REG_NUM_PP (41)
#define REG_NUM_ENC (96)
#define REG_NUM_DEC_PP (REG_NUM_DEC+REG_NUM_PP)
#define SIZE_REG(reg) ((reg)*4)
static const u16 dec_hw_ids[] = { 0x8190, 0x8170, 0x9170, 0x9190, 0x6731 };
static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270 };
static u32 regs_enc[REG_NUM_ENC];
static u32 regs_dec[REG_NUM_DEC_PP];
static u32 *regs_pp = &regs_dec[REG_NUM_DEC];
#define VPU_REG_EN_ENC 14
#define VPU_REG_ENC_GATE 2
#define VPU_REG_ENC_GATE_BIT (1<<4)
#define VPU_REG_EN_DEC 1
#define VPU_REG_DEC_GATE 2
#define VPU_REG_DEC_GATE_BIT (1<<10)
#define VPU_REG_EN_PP 0
#define VPU_REG_PP_GATE 1
#define VPU_REG_PP_GATE_BIT (1<<8)
#define VPU_REG_EN_DEC_PP 1
#define VPU_REG_DEC_PP_GATE 61
#define VPU_REG_DEC_PP_GATE_BIT (1<<8)
struct vpu_device {
unsigned long iobaseaddr;
unsigned int iosize;
volatile u32 *hwregs;
unsigned int irq;
};
static struct vpu_device dec_dev;
static struct vpu_device pp_dev;
static struct vpu_device enc_dev;
struct vpu_client {
atomic_t dec_event;
atomic_t enc_event;
struct fasync_struct *async_queue;
wait_queue_head_t wait;
struct file *filp; /* for /proc/vpu */
bool enabled;
};
static struct vpu_client client;
static struct clk *aclk_vepu;
static struct clk *hclk_vepu;
static struct clk *aclk_ddr_vepu;
static struct clk *hclk_cpu_vcodec;
static void vpu_release_io(void);
static void vpu_get_clk(void)
{
aclk_vepu = clk_get(NULL, "aclk_vepu");
hclk_vepu = clk_get(NULL, "hclk_vepu");
aclk_ddr_vepu = clk_get(NULL, "aclk_ddr_vepu");
hclk_cpu_vcodec = clk_get(NULL, "hclk_cpu_vcodec");
}
static void vpu_put_clk(void)
{
clk_put(aclk_vepu);
clk_put(hclk_vepu);
clk_put(aclk_ddr_vepu);
clk_put(hclk_cpu_vcodec);
}
static u32 vpu_is_working(void)
{
u32 irq_status;
u32 vpu_status = 0;
irq_status = readl(dec_dev.hwregs + DEC_INTERRUPT_REGISTER);
vpu_status |= irq_status&1;
irq_status = readl(enc_dev.hwregs + ENC_INTERRUPT_REGISTER);
vpu_status |= irq_status&1;
irq_status = readl(pp_dev.hwregs + PP_INTERRUPT_REGISTER);
vpu_status |= irq_status&1;
return vpu_status;
}
static void vpu_power_on(void)
{
pr_debug("power on\n");
if (client.enabled)
return;
clk_enable(aclk_vepu);
clk_enable(hclk_vepu);
clk_enable(hclk_cpu_vcodec);
udelay(10);
pmu_set_power_domain(PD_VCODEC, true);
udelay(10);
clk_enable(aclk_ddr_vepu);
client.enabled = true;
}
static void vpu_power_off(void)
{
pr_debug("power off\n");
if (!client.enabled)
return;
while (vpu_is_working())
udelay(10);
pmu_set_power_domain(PD_VCODEC, false);
udelay(10);
clk_disable(hclk_cpu_vcodec);
clk_disable(aclk_ddr_vepu);
clk_disable(hclk_vepu);
clk_disable(aclk_vepu);
client.enabled = false;
}
static void vpu_power_test(void)
{
#if 0
if (pmu_power_domain_is_on(PD_VCODEC)) {
printk("power domain is on, test closing\n");
while (vpu_is_working())
msleep(1);
printk("power off\n");
pmu_set_power_domain(PD_VCODEC, false);
printk("clock off hclk_cpu_vcodec\n");
clk_disable(hclk_cpu_vcodec);
printk("clock off hclk_vepu\n");
clk_disable(hclk_vepu);
printk("clock off aclk_ddr_vepu\n");
clk_disable(aclk_ddr_vepu);
printk("clock off aclk_vepu\n");
clk_disable(aclk_vepu);
} else {
printk("power domain is off, test opening\n");
printk("clock on : hclk_vepu\n");
clk_enable(hclk_vepu);
printk("clock on : hclk_cpu_vcodec\n");
clk_enable(hclk_cpu_vcodec);
printk("clock on : aclk_vepu\n");
clk_enable(aclk_vepu);
printk("clock on : aclk_ddr_vepu\n");
clk_enable(aclk_ddr_vepu);
printk("power on\n");
pmu_set_power_domain(PD_VCODEC, true);
#if 1
udelay(100);
printk("clock reset\n");
cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);
cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);
cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);
cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);
printk("clock unreset\n");
cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);
cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);
cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);
cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);
#endif
}
#endif
}
static long vpu_write_dec(u32 *src)
{
int i;
u32 *dst = (u32 *)dec_dev.hwregs;
for (i = REG_NUM_DEC - 1; i > VPU_REG_DEC_GATE; i--)
dst[i] = src[i];
dsb();
dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;
dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC];
return 0;
}
static long vpu_write_dec_pp(u32 *src)
{
int i;
u32 *dst = (u32 *)dec_dev.hwregs;
for (i = VPU_REG_EN_DEC_PP + 1; i < REG_NUM_DEC_PP; i++)
dst[i] = src[i];
dsb();
dst[VPU_REG_DEC_PP_GATE] = src[VPU_REG_DEC_PP_GATE] | VPU_REG_PP_GATE_BIT;
dst[VPU_REG_DEC_GATE] = src[VPU_REG_DEC_GATE] | VPU_REG_DEC_GATE_BIT;
dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC];
return 0;
}
static long vpu_write_enc(u32 *src)
{
int i;
u32 *dst = (u32 *)enc_dev.hwregs;
dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6;
for (i = 0; i < VPU_REG_EN_ENC; i++)
dst[i] = src[i];
for (i = VPU_REG_EN_ENC + 1; i < REG_NUM_ENC; i++)
dst[i] = src[i];
dsb();
dst[VPU_REG_ENC_GATE] = src[VPU_REG_ENC_GATE] | VPU_REG_ENC_GATE_BIT;
dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC];
return 0;
}
static long vpu_write_pp(u32 *src)
{
int i;
u32 *dst = (u32 *)dec_dev.hwregs + PP_INTERRUPT_REGISTER;
dst[VPU_REG_PP_GATE] = src[VPU_REG_PP_GATE] | VPU_REG_PP_GATE_BIT;
for (i = VPU_REG_PP_GATE + 1; i < REG_NUM_PP; i++)
dst[i] = src[i];
dsb();
dst[VPU_REG_EN_PP] = src[VPU_REG_EN_PP];
return 0;
}
static long vpu_read_dec(u32 *dst)
{
int i;
volatile u32 *src = dec_dev.hwregs;
for (i = 0; i < REG_NUM_DEC; i++)
*dst++ = *src++;
return 0;
}
static long vpu_read_dec_pp(u32 *dst)
{
int i;
volatile u32 *src = dec_dev.hwregs;
for (i = 0; i < REG_NUM_DEC_PP; i++)
*dst++ = *src++;
return 0;
}
static long vpu_read_enc(u32 *dst)
{
int i;
volatile u32 *src = enc_dev.hwregs;
for (i = 0; i < REG_NUM_ENC; i++)
*dst++ = *src++;
return 0;
}
static long vpu_read_pp(u32 *dst)
{
int i;
volatile u32 *src = dec_dev.hwregs + PP_INTERRUPT_REGISTER;
for (i = 0; i < REG_NUM_PP; i++)
*dst++ = *src++;
return 0;
}
static long vpu_clear_irqs(VPU_CLIENT_TYPE type)
{
long ret = 0;
switch (type) {
case VPU_ENC : {
writel(0, &enc_dev.hwregs[ENC_INTERRUPT_REGISTER]);
break;
}
case VPU_DEC : {
writel(0, &dec_dev.hwregs[DEC_INTERRUPT_REGISTER]);
break;
}
case VPU_PP : {
writel(0, &pp_dev.hwregs[PP_INTERRUPT_REGISTER]);
break;
}
case VPU_DEC_PP : {
writel(0, &pp_dev.hwregs[PP_INTERRUPT_REGISTER]);
writel(0, &dec_dev.hwregs[DEC_INTERRUPT_REGISTER]);
break;
}
default : {
printk("undefined vpu_clear_irqs case\n");
ret = -1;
}
}
return ret;
}
static long vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
pr_debug("ioctl cmd 0x%08x\n", cmd);
switch (cmd) {
case VPU_IOC_CLOCK_ON: {
vpu_power_on();
break;
}
case VPU_IOC_CLOCK_OFF: {
vpu_power_off();
break;
}
case VPU_IOC_CLOCK_RESET:
case VPU_IOC_CLOCK_UNRESET:
case VPU_IOC_DOMAIN_ON:
case VPU_IOC_DOMAIN_OFF: {
break;
}
case VPU_IOC_TEST: {
vpu_power_test();
break;
}
case VPU_IOC_WR_DEC: {
if (copy_from_user(regs_dec, (void __user *)arg, SIZE_REG(REG_NUM_DEC))) {
printk("VPU_IOC_WR_DEC copy_from_user failed\n");
return -EFAULT;
}
vpu_write_dec(regs_dec);
break;
}
case VPU_IOC_WR_DEC_PP: {
if (copy_from_user(regs_dec, (void __user *)arg, SIZE_REG(REG_NUM_DEC_PP))) {
printk("VPU_IOC_WR_DEC_PP copy_from_user failed\n");
return -EFAULT;
}
vpu_write_dec_pp(regs_dec);
break;
}
case VPU_IOC_WR_ENC: {
if (copy_from_user(regs_enc, (void __user *)arg, SIZE_REG(REG_NUM_ENC))) {
printk("VPU_IOC_WR_ENC copy_from_user failed\n");
return -EFAULT;
}
vpu_write_enc(regs_enc);
break;
}
case VPU_IOC_WR_PP: {
if (copy_from_user(regs_pp, (void __user *)arg, SIZE_REG(REG_NUM_PP))) {
printk("VPU_IOC_WR_PP copy_from_user failed\n");
return -EFAULT;
}
vpu_write_pp(regs_pp);
break;
}
case VPU_IOC_RD_DEC: {
vpu_read_dec(regs_dec);
if (copy_to_user((void __user *)arg, regs_dec, SIZE_REG(REG_NUM_DEC))) {
printk("VPU_IOC_RD_DEC copy_to_user failed\n");
return -EFAULT;
}
break;
}
case VPU_IOC_RD_DEC_PP: {
vpu_read_dec_pp(regs_dec);
if (copy_to_user((void __user *)arg, regs_dec, SIZE_REG(REG_NUM_DEC_PP))) {
printk("VPU_IOC_RD_DEC_PP copy_to_user failed\n");
return -EFAULT;
}
break;
}
case VPU_IOC_RD_ENC: {
vpu_read_enc(regs_enc);
if (copy_to_user((void __user *)arg, regs_enc, SIZE_REG(REG_NUM_ENC))) {
printk("VPU_IOC_RD_ENC copy_to_user failed\n");
return -EFAULT;
}
break;
}
case VPU_IOC_RD_PP: {
vpu_read_pp(regs_pp);
if (copy_to_user((void __user *)arg, regs_pp, SIZE_REG(REG_NUM_PP))) {
printk("VPU_IOC_RD_PP copy_to_user failed\n");
return -EFAULT;
}
break;
}
case VPU_IOC_CLS_IRQ: {
return vpu_clear_irqs(arg);
break;
}
default: {
printk("undefined ioctl cmd\n");
return -ENOTTY;
}
}
return 0;
}
static int vpu_open(struct inode *inode, struct file *filp)
{
if (client.filp) {
printk("vpu is already opened\n");
return -EBUSY;
}
client.filp = filp;
vpu_power_on();
pr_debug("dev opened\n");
return nonseekable_open(inode, filp);
}
static int vpu_fasync(int fd, struct file *filp, int mode)
{
return fasync_helper(fd, filp, mode, &client.async_queue);
}
static int vpu_release(struct inode *inode, struct file *filp)
{
msleep(50);
/* remove this filp from the asynchronusly notified filp's */
vpu_fasync(-1, filp, 0);
client.async_queue = NULL;
client.filp = NULL;
vpu_power_off();
pr_debug("dev closed\n");
return 0;
}
static int vpu_check_hw_id(struct vpu_device * dev, const u16 *hwids, size_t num)
{
u32 hwid = readl(dev->hwregs);
pr_info("HW ID = 0x%08x\n", hwid);
hwid = (hwid >> 16) & 0xFFFF; /* product version only */
while (num--) {
if (hwid == hwids[num]) {
pr_info("Compatible HW found at 0x%08lx\n", dev->iobaseaddr);
return 1;
}
}
pr_info("No Compatible HW found at 0x%08lx\n", dev->iobaseaddr);
return 0;
}
static int vpu_reserve_io(void)
{
if (!request_mem_region(dec_dev.iobaseaddr, dec_dev.iosize, "hx170dec")) {
pr_info("failed to reserve dec HW regs\n");
return -EBUSY;
}
dec_dev.hwregs =
(volatile u32 *)ioremap_nocache(dec_dev.iobaseaddr, dec_dev.iosize);
if (dec_dev.hwregs == NULL) {
pr_info("failed to ioremap dec HW regs\n");
goto err;
}
/* check for correct HW */
if (!vpu_check_hw_id(&dec_dev, dec_hw_ids, ARRAY_SIZE(dec_hw_ids))) {
goto err;
}
if (!request_mem_region(enc_dev.iobaseaddr, enc_dev.iosize, "hx280enc")) {
pr_info("failed to reserve enc HW regs\n");
goto err;
}
enc_dev.hwregs =
(volatile u32 *)ioremap_nocache(enc_dev.iobaseaddr, enc_dev.iosize);
if (enc_dev.hwregs == NULL) {
pr_info("failed to ioremap enc HW regs\n");
goto err;
}
/* check for correct HW */
if (!vpu_check_hw_id(&enc_dev, enc_hw_ids, ARRAY_SIZE(enc_hw_ids))) {
goto err;
}
return 0;
err:
vpu_release_io();
return -EBUSY;
}
static void vpu_release_io(void)
{
if (dec_dev.hwregs)
iounmap((void *)dec_dev.hwregs);
release_mem_region(dec_dev.iobaseaddr, dec_dev.iosize);
if (enc_dev.hwregs)
iounmap((void *)enc_dev.hwregs);
release_mem_region(enc_dev.iobaseaddr, enc_dev.iosize);
}
static void vpu_event_notify(void)
{
wake_up_interruptible(&client.wait);
if (client.async_queue)
kill_fasync(&client.async_queue, SIGIO, POLL_IN);
}
static irqreturn_t hx170dec_isr(int irq, void *dev_id)
{
struct vpu_device *dev = (struct vpu_device *) dev_id;
u32 irq_status_dec;
u32 irq_status_pp;
u32 event = VPU_IRQ_EVENT_DEC_BIT;
pr_debug("dec_isr\n");
/* interrupt status register read */
irq_status_dec = readl(dev->hwregs + DEC_INTERRUPT_REGISTER);
irq_status_pp = readl(dev->hwregs + PP_INTERRUPT_REGISTER);
if (irq_status_dec & DEC_INTERRUPT_BIT) {
/* clear dec IRQ */
writel(irq_status_dec & (~DEC_INTERRUPT_BIT),
dev->hwregs + DEC_INTERRUPT_REGISTER);
event |= VPU_IRQ_EVENT_DEC_IRQ_BIT;
pr_debug("DEC IRQ received!\n");
}
if (irq_status_pp & PP_INTERRUPT_BIT) {
/* clear pp IRQ */
writel(irq_status_pp & (~DEC_INTERRUPT_BIT),
dev->hwregs + PP_INTERRUPT_REGISTER);
event |= VPU_IRQ_EVENT_PP_IRQ_BIT;
pr_debug("PP IRQ received!\n");
}
atomic_set(&client.dec_event, event);
vpu_event_notify();
return IRQ_HANDLED;
}
static irqreturn_t hx280enc_isr(int irq, void *dev_id)
{
struct vpu_device *dev = (struct vpu_device *) dev_id;
u32 irq_status;
u32 event = VPU_IRQ_EVENT_ENC_BIT;
pr_debug("enc_isr\n");
irq_status = readl(dev->hwregs + ENC_INTERRUPT_REGISTER);
if (likely(irq_status & ENC_INTERRUPT_BIT)) {
/* clear enc IRQ */
writel(irq_status & (~ENC_INTERRUPT_BIT),
dev->hwregs + ENC_INTERRUPT_REGISTER);
event |= VPU_IRQ_EVENT_ENC_IRQ_BIT;
pr_debug("ENC IRQ received!\n");
}
atomic_set(&client.enc_event, event);
vpu_event_notify();
return IRQ_HANDLED;
}
static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
{
unsigned long pfn;
/* Only support the simple cases where we map in a register page. */
if (((vm->vm_end - vm->vm_start) > RK29_VCODEC_SIZE) || vm->vm_pgoff)
return -EINVAL;
vm->vm_flags |= VM_IO | VM_RESERVED;
vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
pfn = RK29_VCODEC_PHYS >> PAGE_SHIFT;
pr_debug("size = 0x%x, page no. = 0x%x\n",
(int)(vm->vm_end - vm->vm_start), (int)pfn);
return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
vm->vm_page_prot) ? -EAGAIN : 0;
}
static unsigned int vpu_poll(struct file *filep, poll_table *wait)
{
poll_wait(filep, &client.wait, wait);
if (atomic_read(&client.dec_event) || atomic_read(&client.enc_event))
return POLLIN | POLLRDNORM;
return 0;
}
static ssize_t vpu_read(struct file *filep, char __user *buf,
size_t count, loff_t *ppos)
{
DECLARE_WAITQUEUE(wait, current);
ssize_t retval;
u32 irq_event;
if (count != sizeof(u32))
return -EINVAL;
add_wait_queue(&client.wait, &wait);
do {
set_current_state(TASK_INTERRUPTIBLE);
irq_event = atomic_xchg(&client.dec_event, 0) | atomic_xchg(&client.enc_event, 0);
if (irq_event) {
if (copy_to_user(buf, &irq_event, count))
retval = -EFAULT;
else
retval = count;
break;
}
if (filep->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
schedule();
} while (1);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&client.wait, &wait);
return retval;
}
static const struct file_operations vpu_fops = {
.read = vpu_read,
.poll = vpu_poll,
.unlocked_ioctl = vpu_ioctl,
.mmap = vpu_mmap,
.open = vpu_open,
.release = vpu_release,
.fasync = vpu_fasync,
};
static struct miscdevice vpu_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "vpu",
.fops = &vpu_fops,
};
static void vpu_shutdown(struct platform_device *pdev)
{
pr_info("shutdown...");
vpu_power_off();
pr_cont("done\n");
}
static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
{
bool enabled = client.enabled;
mdelay(50);
vpu_power_off();
client.enabled = enabled;
return 0;
}
static int vpu_resume(struct platform_device *pdev)
{
if (client.enabled) {
client.enabled = false;
vpu_power_on();
}
return 0;
}
static struct platform_device vpu_pm_device = {
.name = "vpu",
.id = -1,
};
static struct platform_driver vpu_pm_driver = {
.driver = {
.name = "vpu",
.owner = THIS_MODULE,
},
.shutdown = vpu_shutdown,
.suspend = vpu_suspend,
.resume = vpu_resume,
};
static int __init vpu_init(void)
{
int ret;
pr_debug("baseaddr = 0x%08x vdpu irq = %d vepu irq = %d\n", RK29_VCODEC_PHYS, IRQ_VDPU, IRQ_VEPU);
dec_dev.iobaseaddr = RK29_VCODEC_PHYS + 0x200;
dec_dev.iosize = DEC_IO_SIZE;
dec_dev.irq = IRQ_VDPU;
enc_dev.iobaseaddr = RK29_VCODEC_PHYS;
enc_dev.iosize = ENC_IO_SIZE;
enc_dev.irq = IRQ_VEPU;
vpu_get_clk();
vpu_power_on();
ret = vpu_reserve_io();
if (ret < 0) {
goto err_reserve_io;
}
pp_dev = dec_dev;
init_waitqueue_head(&client.wait);
atomic_set(&client.dec_event, 0);
atomic_set(&client.enc_event, 0);
/* get the IRQ line */
ret = request_irq(IRQ_VDPU, hx170dec_isr, 0, "hx170dec", (void *)&dec_dev);
if (ret != 0) {
pr_err("can't request vdpu irq %d\n", IRQ_VDPU);
goto err_req_vdpu_irq;
}
ret = request_irq(IRQ_VEPU, hx280enc_isr, 0, "hx280enc", (void *)&enc_dev);
if (ret != 0) {
pr_err("can't request vepu irq %d\n", IRQ_VEPU);
goto err_req_vepu_irq;
}
ret = misc_register(&vpu_misc_device);
if (ret) {
pr_err("misc_register failed\n");
goto err_register;
}
vpu_power_off();
platform_device_register(&vpu_pm_device);
platform_driver_probe(&vpu_pm_driver, NULL);
pr_info("init success\n");
memset(regs_enc, 0, sizeof(regs_enc));
memset(regs_dec, 0, sizeof(regs_dec));
return 0;
err_register:
free_irq(IRQ_VEPU, (void *)&enc_dev);
err_req_vepu_irq:
free_irq(IRQ_VDPU, (void *)&dec_dev);
err_req_vdpu_irq:
vpu_release_io();
err_reserve_io:
vpu_power_off();
vpu_put_clk();
pr_info("init failed\n");
return ret;
}
static void __exit vpu_exit(void)
{
platform_device_unregister(&vpu_pm_device);
platform_driver_unregister(&vpu_pm_driver);
vpu_power_on();
misc_deregister(&vpu_misc_device);
free_irq(IRQ_VEPU, (void *)&enc_dev);
free_irq(IRQ_VDPU, (void *)&dec_dev);
vpu_release_io();
vpu_power_off();
vpu_put_clk();
}
module_init(vpu_init);
module_exit(vpu_exit);
MODULE_LICENSE("GPL");
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static int proc_vpu_show(struct seq_file *s, void *v)
{
unsigned int i, n;
s32 irq_event = atomic_read(&client.dec_event) | atomic_read(&client.enc_event);
seq_printf(s, client.filp ? "Opened\n" : "Closed\n");
seq_printf(s, "irq_event: 0x%08x (%s%s%s%s%s)\n", irq_event,
irq_event & VPU_IRQ_EVENT_DEC_BIT ? "DEC " : "",
irq_event & VPU_IRQ_EVENT_DEC_IRQ_BIT ? "DEC_IRQ " : "",
irq_event & VPU_IRQ_EVENT_PP_IRQ_BIT ? "PP_IRQ " : "",
irq_event & VPU_IRQ_EVENT_ENC_BIT ? "ENC " : "",
irq_event & VPU_IRQ_EVENT_ENC_IRQ_BIT ? "ENC_IRQ" : "");
vpu_power_on();
seq_printf(s, "\nENC Registers:\n");
n = enc_dev.iosize >> 2;
for (i = 0; i < n; i++) {
seq_printf(s, "\tswreg%d = %08X\n", i, readl(enc_dev.hwregs + i));
}
seq_printf(s, "\nDEC Registers:\n");
n = dec_dev.iosize >> 2;
for (i = 0; i < n; i++) {
seq_printf(s, "\tswreg%d = %08X\n", i, readl(dec_dev.hwregs + i));
}
vpu_power_off();
return 0;
}
static int proc_vpu_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_vpu_show, NULL);
}
static const struct file_operations proc_vpu_fops = {
.open = proc_vpu_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init vpu_proc_init(void)
{
proc_create("vpu", 0, NULL, &proc_vpu_fops);
return 0;
}
late_initcall(vpu_proc_init);
#endif /* CONFIG_PROC_FS */