blob: 8b8d0e50120b62d99fb76785c8ba6c88f60e2336 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "rdma: " fmt
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/dma-mapping.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/ctype.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/clk.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/reset.h>
#include <linux/amlogic/media/registers/cpu_version.h>
#include <linux/amlogic/media/utils/vdec_reg.h>
#include <linux/amlogic/media/rdma/rdma_mgr.h>
#include <linux/amlogic/media/vpu/vpu.h>
#include "rdma.h"
#define DRIVER_NAME "amlogic-rdma"
#define MODULE_NAME "amlogic-rdma"
#define DEVICE_NAME "rdma"
#define CLASS_NAME "rdma-class"
#define pr_dbg(fmt, args...) pr_info("RDMA: " fmt, ## args)
#define pr_error(fmt, args...) pr_err("RDMA: " fmt, ## args)
#define rdma_io_read(addr) readl(addr)
#define rdma_io_write(addr, val) writel((val), addr)
/* #define SKIP_OSD_CHANNEL */
int has_multi_vpp;
int rdma_mgr_irq_request;
int rdma_reset_tigger_flag;
struct reset_control *rdma_rst;
static int debug_flag;
/* burst size 0=16; 1=24; 2=32; 3=48.*/
static int ctrl_ahb_rd_burst_size = 3;
static int ctrl_ahb_wr_burst_size = 3;
static int rdma_watchdog = 20;
static int reset_count;
static int rdma_watchdog_count;
static int rdma_force_reset = -1;
#define RDMA_NUM 8
#define RDMA_TABLE_SIZE (8 * (PAGE_SIZE))
#define MAX_TRACE_NUM 16
#define RDMA_MGR_CLASS_NAME "rdma_mgr"
static int rdma_trace_num;
static int rdma_trace_enable;
static u32 rdma_trace_reg[MAX_TRACE_NUM];
static int rdma_table_size = RDMA_TABLE_SIZE;
struct rdma_regadr_s {
u32 rdma_ahb_start_addr;
u32 rdma_ahb_start_addr_msb;
u32 rdma_ahb_end_addr;
u32 rdma_ahb_end_addr_msb;
u32 trigger_mask_reg;
u32 trigger_mask_reg_bitpos;
u32 addr_inc_reg;
u32 addr_inc_reg_bitpos;
u32 rw_flag_reg;
u32 rw_flag_reg_bitpos;
u32 clear_irq_bitpos;
u32 irq_status_bitpos;
};
struct rdma_instance_s {
int not_process;
struct rdma_regadr_s *rdma_regadr;
struct rdma_op_s *op;
void *op_arg;
int rdma_table_size;
u32 *reg_buf;
dma_addr_t dma_handle;
u32 *rdma_table_addr;
ulong rdma_table_phy_addr;
int rdma_item_count;
int rdma_write_count;
unsigned char keep_buf;
unsigned char used;
int prev_trigger_type;
int prev_read_count;
};
#define MAX_CONFLICT 32
struct rdma_conflict_regs_s {
u32 adr[MAX_CONFLICT];
u32 val[MAX_CONFLICT];
};
struct rdma_device_info {
const char *device_name;
struct platform_device *rdma_dev;
struct rdma_instance_s rdma_ins[RDMA_NUM];
struct rdma_conflict_regs_s rdma_reg;
};
static struct rdma_device_data_s rdma_meson_dev;
static int support_64bit_addr;
static DEFINE_SPINLOCK(rdma_lock);
static struct rdma_device_info rdma_info;
static struct vpu_dev_s *rdma_vpu_dev;
static struct rdma_regadr_s rdma_regadr[RDMA_NUM] = {
{RDMA_AHB_START_ADDR_MAN,
0,
RDMA_AHB_END_ADDR_MAN,
0,
0, 0,
RDMA_ACCESS_MAN, 1,
RDMA_ACCESS_MAN, 2,
24, 24
},
{RDMA_AHB_START_ADDR_1,
0,
RDMA_AHB_END_ADDR_1,
0,
RDMA_ACCESS_AUTO, 8,
RDMA_ACCESS_AUTO, 1,
RDMA_ACCESS_AUTO, 5,
25, 25
},
{RDMA_AHB_START_ADDR_2,
0,
RDMA_AHB_END_ADDR_2,
0,
RDMA_ACCESS_AUTO, 16,
RDMA_ACCESS_AUTO, 2,
RDMA_ACCESS_AUTO, 6,
26, 26
},
{RDMA_AHB_START_ADDR_3,
0,
RDMA_AHB_END_ADDR_3,
0,
RDMA_ACCESS_AUTO, 24,
RDMA_ACCESS_AUTO, 3,
RDMA_ACCESS_AUTO, 7,
27, 27
},
{RDMA_AHB_START_ADDR_4,
0,
RDMA_AHB_END_ADDR_4,
0,
RDMA_ACCESS_AUTO3, 0,
RDMA_ACCESS_AUTO2, 0,
RDMA_ACCESS_AUTO2, 4,
28, 28
},
{RDMA_AHB_START_ADDR_5,
0,
RDMA_AHB_END_ADDR_5,
0,
RDMA_ACCESS_AUTO3, 8,
RDMA_ACCESS_AUTO2, 1,
RDMA_ACCESS_AUTO2, 5,
29, 29
},
{RDMA_AHB_START_ADDR_6,
0,
RDMA_AHB_END_ADDR_6,
0,
RDMA_ACCESS_AUTO3, 16,
RDMA_ACCESS_AUTO2, 2,
RDMA_ACCESS_AUTO2, 6,
30, 30
},
{RDMA_AHB_START_ADDR_7,
0,
RDMA_AHB_END_ADDR_7,
0,
RDMA_ACCESS_AUTO3, 24,
RDMA_ACCESS_AUTO2, 3,
RDMA_ACCESS_AUTO2, 7,
31, 31
}
};
static struct rdma_regadr_s rdma_regadr_tl1[RDMA_NUM] = {
{RDMA_AHB_START_ADDR_MAN,
0,
RDMA_AHB_END_ADDR_MAN,
0,
0, 0,
RDMA_ACCESS_MAN, 1,
RDMA_ACCESS_MAN, 2,
24, 24
},
{RDMA_AHB_START_ADDR_1,
0,
RDMA_AHB_END_ADDR_1,
0,
RDMA_AUTO_SRC1_SEL, 0,
RDMA_ACCESS_AUTO, 1,
RDMA_ACCESS_AUTO, 5,
25, 25
},
{RDMA_AHB_START_ADDR_2,
0,
RDMA_AHB_END_ADDR_2,
0,
RDMA_AUTO_SRC2_SEL, 0,
RDMA_ACCESS_AUTO, 2,
RDMA_ACCESS_AUTO, 6,
26, 26
},
{RDMA_AHB_START_ADDR_3,
0,
RDMA_AHB_END_ADDR_3,
0,
RDMA_AUTO_SRC3_SEL, 0,
RDMA_ACCESS_AUTO, 3,
RDMA_ACCESS_AUTO, 7,
27, 27
},
{RDMA_AHB_START_ADDR_4,
0,
RDMA_AHB_END_ADDR_4,
0,
RDMA_AUTO_SRC4_SEL, 0,
RDMA_ACCESS_AUTO2, 0,
RDMA_ACCESS_AUTO2, 4,
28, 28
},
{RDMA_AHB_START_ADDR_5,
0,
RDMA_AHB_END_ADDR_5,
0,
RDMA_AUTO_SRC5_SEL, 0,
RDMA_ACCESS_AUTO2, 1,
RDMA_ACCESS_AUTO2, 5,
29, 29
},
{RDMA_AHB_START_ADDR_6,
0,
RDMA_AHB_END_ADDR_6,
0,
RDMA_AUTO_SRC6_SEL, 0,
RDMA_ACCESS_AUTO2, 2,
RDMA_ACCESS_AUTO2, 6,
30, 30
},
{RDMA_AHB_START_ADDR_7,
0,
RDMA_AHB_END_ADDR_7,
0,
RDMA_AUTO_SRC7_SEL, 0,
RDMA_ACCESS_AUTO2, 3,
RDMA_ACCESS_AUTO2, 7,
31, 31
}
};
static struct rdma_regadr_s rdma_regadr_t7[RDMA_NUM] = {
{RDMA_AHB_START_ADDR_MAN,
RDMA_AHB_START_ADDR_MAN_MSB,
RDMA_AHB_END_ADDR_MAN,
RDMA_AHB_END_ADDR_MAN_MSB,
0, 0,
RDMA_ACCESS_MAN, 1,
RDMA_ACCESS_MAN, 2,
24, 24
},
{RDMA_AHB_START_ADDR_1,
RDMA_AHB_START_ADDR_1_MSB,
RDMA_AHB_END_ADDR_1,
RDMA_AHB_END_ADDR_1_MSB,
RDMA_AUTO_SRC1_SEL, 0,
RDMA_ACCESS_AUTO, 1,
RDMA_ACCESS_AUTO, 5,
25, 25
},
{RDMA_AHB_START_ADDR_2,
RDMA_AHB_START_ADDR_2_MSB,
RDMA_AHB_END_ADDR_2,
RDMA_AHB_END_ADDR_2_MSB,
RDMA_AUTO_SRC2_SEL, 0,
RDMA_ACCESS_AUTO, 2,
RDMA_ACCESS_AUTO, 6,
26, 26
},
{RDMA_AHB_START_ADDR_3,
RDMA_AHB_START_ADDR_3_MSB,
RDMA_AHB_END_ADDR_3,
RDMA_AHB_END_ADDR_3_MSB,
RDMA_AUTO_SRC3_SEL, 0,
RDMA_ACCESS_AUTO, 3,
RDMA_ACCESS_AUTO, 7,
27, 27
},
{RDMA_AHB_START_ADDR_4,
RDMA_AHB_START_ADDR_4_MSB,
RDMA_AHB_END_ADDR_4,
RDMA_AHB_END_ADDR_4_MSB,
RDMA_AUTO_SRC4_SEL, 0,
RDMA_ACCESS_AUTO2, 0,
RDMA_ACCESS_AUTO2, 4,
28, 28
},
{RDMA_AHB_START_ADDR_5,
RDMA_AHB_START_ADDR_5_MSB,
RDMA_AHB_END_ADDR_5,
RDMA_AHB_END_ADDR_5_MSB,
RDMA_AUTO_SRC5_SEL, 0,
RDMA_ACCESS_AUTO2, 1,
RDMA_ACCESS_AUTO2, 5,
29, 29
},
{RDMA_AHB_START_ADDR_6,
RDMA_AHB_START_ADDR_6_MSB,
RDMA_AHB_END_ADDR_6,
RDMA_AHB_END_ADDR_6_MSB,
RDMA_AUTO_SRC6_SEL, 0,
RDMA_ACCESS_AUTO2, 2,
RDMA_ACCESS_AUTO2, 6,
30, 30
},
{RDMA_AHB_START_ADDR_7,
RDMA_AHB_START_ADDR_7_MSB,
RDMA_AHB_END_ADDR_7,
RDMA_AHB_END_ADDR_7_MSB,
RDMA_AUTO_SRC7_SEL, 0,
RDMA_ACCESS_AUTO2, 3,
RDMA_ACCESS_AUTO2, 7,
31, 31
}
};
int rdma_register(struct rdma_op_s *rdma_op, void *op_arg, int table_size)
{
int i;
unsigned long flags;
struct rdma_device_info *info = &rdma_info;
dma_addr_t dma_handle;
spin_lock_irqsave(&rdma_lock, flags);
for (i = 1; i < RDMA_NUM; i++) {
/* 0 is reserved for RDMA MANUAL */
if (!info->rdma_ins[i].op &&
info->rdma_ins[i].used == 0) {
info->rdma_ins[i].op = rdma_op;
break;
}
}
spin_unlock_irqrestore(&rdma_lock, flags);
if (i < RDMA_NUM) {
info->rdma_ins[i].not_process = 0;
info->rdma_ins[i].op_arg = op_arg;
info->rdma_ins[i].rdma_item_count = 0;
info->rdma_ins[i].rdma_write_count = 0;
info->rdma_ins[i].prev_read_count = 0;
if (info->rdma_ins[i].rdma_table_size == 0) {
info->rdma_ins[i].rdma_table_addr =
dma_alloc_coherent
(&info->rdma_dev->dev, table_size,
&dma_handle, GFP_KERNEL);
info->rdma_ins[i].rdma_table_phy_addr =
(ulong)(dma_handle);
info->rdma_ins[i].reg_buf =
kmalloc(table_size, GFP_KERNEL);
pr_info("%s, rdma_table_addr %lx phy: %lx reg_buf %lx\n",
__func__,
(unsigned long)
info->rdma_ins[i].rdma_table_addr,
info->rdma_ins[i].rdma_table_phy_addr,
(unsigned long)info->rdma_ins[i].reg_buf);
info->rdma_ins[i].rdma_table_size = table_size;
}
if (!info->rdma_ins[i].rdma_table_addr ||
!info->rdma_ins[i].reg_buf) {
if (!info->rdma_ins[i].keep_buf) {
kfree(info->rdma_ins[i].reg_buf);
info->rdma_ins[i].reg_buf = NULL;
}
if (info->rdma_ins[i].rdma_table_addr) {
dma_free_coherent
(&info->rdma_dev->dev,
table_size,
info->rdma_ins[i].rdma_table_addr,
(dma_addr_t)
info->rdma_ins[i].rdma_table_phy_addr);
info->rdma_ins[i].rdma_table_addr = NULL;
}
info->rdma_ins[i].rdma_table_size = 0;
info->rdma_ins[i].op = NULL;
i = -1;
pr_info("%s: memory allocate fail\n",
__func__);
} else {
pr_info("%s success, handle %d table_size %d\n",
__func__, i, table_size);
}
return i;
}
return -1;
}
EXPORT_SYMBOL(rdma_register);
void rdma_unregister(int i)
{
unsigned long flags;
struct rdma_device_info *info = &rdma_info;
pr_info("%s(%d)\r\n", __func__, i);
if (i > 0 && i < RDMA_NUM && info->rdma_ins[i].op) {
/*rdma_clear(i);*/
info->rdma_ins[i].op_arg = NULL;
if (!info->rdma_ins[i].keep_buf) {
kfree(info->rdma_ins[i].reg_buf);
info->rdma_ins[i].reg_buf = NULL;
}
if (info->rdma_ins[i].rdma_table_addr) {
dma_free_coherent
(&info->rdma_dev->dev,
info->rdma_ins[i].rdma_table_size,
info->rdma_ins[i].rdma_table_addr,
(dma_addr_t)
info->rdma_ins[i].rdma_table_phy_addr);
info->rdma_ins[i].rdma_table_addr = NULL;
}
info->rdma_ins[i].rdma_table_size = 0;
spin_lock_irqsave(&rdma_lock, flags);
info->rdma_ins[i].op = NULL;
spin_unlock_irqrestore(&rdma_lock, flags);
}
}
EXPORT_SYMBOL(rdma_unregister);
static void rdma_reset(unsigned char external_reset)
{
if (debug_flag & 4)
pr_info("%s(%d)\n",
__func__, external_reset);
if (external_reset) {
if (rdma_meson_dev.cpu_type >= CPU_SC2)
reset_control_reset(rdma_rst);
else
WRITE_MPEG_REG
(RESET4_REGISTER,
(1 << 5));
} else {
WRITE_VCBUS_REG(RDMA_CTRL, (0x1 << 1));
WRITE_VCBUS_REG(RDMA_CTRL, (0x1 << 1));
WRITE_VCBUS_REG
(RDMA_CTRL,
(ctrl_ahb_wr_burst_size << 4) |
(ctrl_ahb_rd_burst_size << 2) |
(0x0 << 1));
}
reset_count++;
}
static int rdma_isr_count;
irqreturn_t rdma_mgr_isr(int irq, void *dev_id)
{
struct rdma_device_info *info = &rdma_info;
int retry_count = 0;
u32 rdma_status;
int i;
u32 read_val;
if (debug_flag & 0x10)
return IRQ_HANDLED;
rdma_isr_count++;
QUERY:
retry_count++;
rdma_status = READ_VCBUS_REG(RDMA_STATUS);
if ((debug_flag & 4) && ((rdma_isr_count % 30) == 0))
pr_info("%s: %x\r\n", __func__, rdma_status);
for (i = 0; i < RDMA_NUM; i++) {
struct rdma_instance_s *ins = &info->rdma_ins[i];
if (ins->not_process)
continue;
if (!(rdma_status & (1 << (i + 24))))
continue;
/*bypass osd rdma done case */
#ifdef SKIP_OSD_CHANNEL
if (i == 3)
continue;
#endif
if (rdma_status & (1 << ins->rdma_regadr->irq_status_bitpos)) {
if (debug_flag & 2)
pr_info("%s: process %d\r\n", __func__, i);
if (ins->op && ins->op->irq_cb)
ins->op->irq_cb(ins->op->arg);
WRITE_VCBUS_REG
(RDMA_CTRL,
(1 << ins->rdma_regadr->clear_irq_bitpos));
}
}
rdma_status = READ_VCBUS_REG(RDMA_STATUS);
#ifdef SKIP_OSD_CHANNEL
if ((rdma_status & 0xf7000000) && retry_count < 100)
goto QUERY;
#else
if ((rdma_status & 0xff000000) && retry_count < 100)
goto QUERY;
#endif
for (i = 0; i < MAX_CONFLICT; i++) {
if (info->rdma_reg.adr[i]) {
read_val = READ_VCBUS_REG(info->rdma_reg.adr[i]);
if (read_val == info->rdma_reg.val[i])
info->rdma_reg.adr[i] = 0;
}
}
return IRQ_HANDLED;
}
/*
* trigger_type:
* 0, stop,
* 0x1~0xff, interrupt input trigger mode
* 0x100, RDMA_TRIGGER_MANUAL
* > 0x100, debug mode
*
* return:
* -1, fail
* 0, rdma table is empty, will not have rdma irq
* 1, success
*/
int rdma_config(int handle, u32 trigger_type)
{
int ret = 0;
unsigned long flags;
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
bool auto_start = false;
bool rdma_read = false;
if (handle <= 0 || handle >= RDMA_NUM) {
pr_info
("%s error, (handle == %d) not allowed\n",
__func__, handle);
return -1;
}
spin_lock_irqsave(&rdma_lock, flags);
if (!ins->op) {
spin_unlock_irqrestore(&rdma_lock, flags);
pr_info("%s: handle (%d) not register\n",
__func__, handle);
return -1;
}
if (trigger_type & RDMA_READ_MASK)
rdma_read = true;
trigger_type &= ~RDMA_READ_MASK;
if (trigger_type & RDMA_AUTO_START_MASK)
auto_start = true;
trigger_type &= ~RDMA_AUTO_START_MASK;
if (auto_start) {
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->trigger_mask_reg,
0,
ins->rdma_regadr->trigger_mask_reg_bitpos,
rdma_meson_dev.trigger_mask_len);
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->addr_inc_reg,
0,
ins->rdma_regadr->addr_inc_reg_bitpos,
1);
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->rw_flag_reg,
rdma_read ? 0 : 1,
ins->rdma_regadr->rw_flag_reg_bitpos,
1);
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->trigger_mask_reg,
trigger_type,
ins->rdma_regadr->trigger_mask_reg_bitpos,
rdma_meson_dev.trigger_mask_len);
ret = 1;
ins->rdma_write_count = 0;
} else if (ins->rdma_item_count <= 0 || trigger_type == 0) {
if (trigger_type == RDMA_TRIGGER_MANUAL)
WRITE_VCBUS_REG
(RDMA_ACCESS_MAN,
READ_VCBUS_REG(RDMA_ACCESS_MAN) & (~1));
if (debug_flag & 2) {
pr_info("%s: trigger_type %d : %d\r\n",
__func__,
trigger_type,
ins->rdma_item_count);
}
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->trigger_mask_reg,
0, ins->rdma_regadr->trigger_mask_reg_bitpos,
rdma_meson_dev.trigger_mask_len);
ins->rdma_write_count = 0;
ins->prev_read_count = 0;
ret = 0;
} else {
memcpy(ins->rdma_table_addr, ins->reg_buf,
ins->rdma_item_count *
(rdma_read ? 1 : 2) * sizeof(u32));
ins->prev_read_count = ins->rdma_item_count;
if (trigger_type > 0 &&
trigger_type <= BIT(rdma_meson_dev.trigger_mask_len)) {
ins->rdma_write_count = ins->rdma_item_count;
ins->prev_trigger_type = trigger_type;
if (trigger_type == RDMA_TRIGGER_MANUAL) {
/*manual RDMA */
struct rdma_instance_s *man_ins =
&info->rdma_ins[0];
WRITE_VCBUS_REG
(RDMA_ACCESS_MAN,
READ_VCBUS_REG(RDMA_ACCESS_MAN) & (~1));
if (support_64bit_addr) {
#ifdef CONFIG_ARM64
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_start_addr,
ins->rdma_table_phy_addr & 0xffffffff);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_start_addr_msb,
(ins->rdma_table_phy_addr >> 32) & 0xffffffff);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_end_addr,
(ins->rdma_table_phy_addr + ins->rdma_item_count * 8 - 1)
& 0xffffffff);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_end_addr_msb,
((ins->rdma_table_phy_addr
+ ins->rdma_item_count * 8 - 1) >> 32) & 0xffffffff);
#else
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_start_addr,
ins->rdma_table_phy_addr & 0xffffffff);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_start_addr_msb,
0);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_end_addr,
(ins->rdma_table_phy_addr +
ins->rdma_item_count * 8 - 1)
& 0xffffffff);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_end_addr_msb,
0);
#endif
} else {
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_start_addr,
ins->rdma_table_phy_addr & 0xffffffff);
WRITE_VCBUS_REG
(man_ins->rdma_regadr->rdma_ahb_end_addr,
(ins->rdma_table_phy_addr & 0xffffffff)
+ ins->rdma_item_count * 8 - 1);
}
WRITE_VCBUS_REG_BITS
(man_ins->rdma_regadr->addr_inc_reg,
0,
man_ins->rdma_regadr->addr_inc_reg_bitpos,
1);
WRITE_VCBUS_REG_BITS
(man_ins->rdma_regadr->rw_flag_reg,
rdma_read ? 0 : 1,
man_ins->rdma_regadr->rw_flag_reg_bitpos,
1);
/* Manual-start RDMA*/
WRITE_VCBUS_REG
(RDMA_ACCESS_MAN,
READ_VCBUS_REG(RDMA_ACCESS_MAN) | 1);
if (debug_flag & 2)
pr_info("%s: manual config %d:\r\n",
__func__, ins->rdma_item_count);
} else {
/* interrupt input trigger RDMA */
if (debug_flag & 2)
pr_info("%s: case 3 : %d:\r\n",
__func__, ins->rdma_item_count);
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->trigger_mask_reg,
0,
ins->rdma_regadr->trigger_mask_reg_bitpos,
rdma_meson_dev.trigger_mask_len);
if (support_64bit_addr) {
#ifdef CONFIG_ARM64
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_start_addr,
ins->rdma_table_phy_addr & 0xffffffff);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_start_addr_msb,
(ins->rdma_table_phy_addr >> 32) & 0xffffffff);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_end_addr,
(ins->rdma_table_phy_addr +
ins->rdma_item_count * 8 - 1) & 0xffffffff);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_end_addr_msb,
((ins->rdma_table_phy_addr +
ins->rdma_item_count * 8 - 1) >> 32) & 0xffffffff);
#else
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_start_addr,
ins->rdma_table_phy_addr & 0xffffffff);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_start_addr_msb,
0);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_end_addr,
(ins->rdma_table_phy_addr +
ins->rdma_item_count * 8 - 1) &
0xffffffff);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_end_addr_msb,
0);
#endif
} else {
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_start_addr,
ins->rdma_table_phy_addr & 0xffffffff);
WRITE_VCBUS_REG
(ins->rdma_regadr->rdma_ahb_end_addr,
(ins->rdma_table_phy_addr & 0xffffffff) +
ins->rdma_item_count * 8 - 1);
}
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->addr_inc_reg,
0,
ins->rdma_regadr->addr_inc_reg_bitpos,
1);
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->rw_flag_reg,
rdma_read ? 0 : 1,
ins->rdma_regadr->rw_flag_reg_bitpos,
1);
WRITE_VCBUS_REG_BITS
(ins->rdma_regadr->trigger_mask_reg,
trigger_type,
ins->rdma_regadr->trigger_mask_reg_bitpos,
rdma_meson_dev.trigger_mask_len);
}
} else if (trigger_type == 0x101) { /* debug mode */
int i;
for (i = 0; i < ins->rdma_item_count; i++) {
WRITE_VCBUS_REG
(ins->rdma_table_addr[i << 1],
ins->rdma_table_addr[(i << 1) + 1]);
if (debug_flag & 1)
pr_info("WR(%x)<=%x\n",
ins->rdma_table_addr[i << 1],
ins->rdma_table_addr
[(i << 1) + 1]);
}
ins->rdma_write_count = 0;
} else if (trigger_type == 0x102) { /* debug mode */
int i;
for (i = 0; i < ins->rdma_item_count; i++) {
WRITE_VCBUS_REG(ins->reg_buf[i << 1],
ins->reg_buf[(i << 1) + 1]);
if (debug_flag & 1)
pr_info("WR(%x)<=%x\n",
ins->reg_buf[i << 1],
ins->reg_buf[(i << 1) + 1]);
}
ins->rdma_write_count = 0;
}
ret = 1;
}
/* don't reset rdma_item_count for read function */
if (handle != get_rdma_handle(VSYNC_RDMA_READ))
ins->rdma_item_count = 0;
spin_unlock_irqrestore(&rdma_lock, flags);
if (debug_flag & 2)
pr_info("%s: (%d 0x%x) ret %d\r\n",
__func__, handle, trigger_type, ret);
return ret;
}
EXPORT_SYMBOL(rdma_config);
int rdma_clear(int handle)
{
int ret = 0;
unsigned long flags;
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
spin_lock_irqsave(&rdma_lock, flags);
if (handle <= 0 ||
handle >= RDMA_NUM ||
!ins->op) {
spin_unlock_irqrestore(&rdma_lock, flags);
pr_info("%s error, handle (%d) not register\n",
__func__, handle);
return -1;
}
WRITE_VCBUS_REG_BITS(ins->rdma_regadr->trigger_mask_reg,
0, ins->rdma_regadr->trigger_mask_reg_bitpos,
rdma_meson_dev.trigger_mask_len);
ins->rdma_write_count = 0;
spin_unlock_irqrestore(&rdma_lock, flags);
return ret;
}
EXPORT_SYMBOL(rdma_clear);
u32 rdma_read_reg(int handle, u32 adr)
{
int i, j = 0;
u32 *write_table;
int match = 0;
int match_oth = 0;
int read_from = 0;
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
u32 read_val = READ_VCBUS_REG(adr);
for (i = 0; i < MAX_CONFLICT; i++) {
if (info->rdma_reg.adr[i] == adr) {
read_val = info->rdma_reg.val[i];
match_oth = 1;
read_from = 3;
break;
}
}
if (!match_oth) {
for (i = (ins->rdma_item_count - 1); i >= 0; i--) {
if (ins->reg_buf[i << 1] == adr) {
read_val = ins->reg_buf[(i << 1) + 1];
match = 1;
read_from = 1;
break;
}
}
}
if (!match) {
write_table = ins->rdma_table_addr;
for (i = (ins->rdma_write_count - 1);
i >= 0; i--) {
if (write_table[i << 1] == adr) {
read_val =
write_table[(i << 1) + 1];
read_from = 2;
break;
}
}
}
if (rdma_trace_enable) {
for (j = 0; j < rdma_trace_num; j++) {
if (adr == rdma_trace_reg[j]) {
if (read_from == 3)
pr_info("(%s) handle %d, %04x=0x%08x from conflict table(%d)\n",
__func__,
handle, adr,
read_val,
ins->rdma_write_count);
else if (read_from == 2)
pr_info("(%s) handle %d, %04x=0x%08x from write table(%d)\n",
__func__,
handle, adr,
read_val,
ins->rdma_write_count);
else if (read_from == 1)
pr_info("(%s) handle %d, %04x=0x%08x from item table(%d)\n",
__func__,
handle, adr,
read_val,
ins->rdma_item_count);
else
pr_info("(%s) handle %d, %04x=0x%08x from real reg\n",
__func__,
handle, adr,
read_val);
}
}
}
return read_val;
}
EXPORT_SYMBOL(rdma_read_reg);
int rdma_watchdog_setting(int flag)
{
int ret = 0;
if (flag == 0)
rdma_watchdog_count = 0;
else
rdma_watchdog_count++;
if (debug_flag & 8) {
rdma_force_reset = 1;
debug_flag = 0;
}
if ((rdma_watchdog > 0 &&
rdma_watchdog_count > rdma_watchdog) ||
rdma_force_reset > 0) {
pr_info("%s rdma reset: %d, force flag:%d\n",
__func__,
rdma_watchdog_count,
rdma_force_reset);
rdma_watchdog_count = 0;
rdma_force_reset = 0;
rdma_reset(1);
rdma_reset_tigger_flag = 1;
ret = 1;
}
return ret;
}
EXPORT_SYMBOL(rdma_watchdog_setting);
static bool rdma_check_conflict(int handle, u32 adr, u32 *read_val)
{
struct rdma_instance_s *oth_ins;
int i, j, k, n;
for (i = 0; i < MAX_CONFLICT; i++) {
if (rdma_info.rdma_reg.adr[i] == adr) {
if (read_val)
*read_val = rdma_info.rdma_reg.val[i];
return true;
}
}
for (i = 0; i < RDMA_NUM; i++) {
oth_ins = &rdma_info.rdma_ins[i];
if (!oth_ins->rdma_table_size ||
!oth_ins->rdma_item_count ||
i == handle)
continue;
for (j = 0; j < oth_ins->rdma_item_count; j++) {
if (oth_ins->reg_buf[j << 1] != adr)
continue;
for (n = 0; n < rdma_trace_num; n++) {
if (adr == rdma_trace_reg[n] ||
(debug_flag & 0x20))
pr_info("(%s) handle %d, conflict write %04x=0x%08x (oth handle %d)\n",
__func__,
handle, adr,
oth_ins->reg_buf[(j << 1) + 1],
i);
}
for (k = 0; k < MAX_CONFLICT; k++) {
if (!rdma_info.rdma_reg.adr[i]) {
rdma_info.rdma_reg.adr[k] = adr;
rdma_info.rdma_reg.val[k] =
oth_ins->reg_buf[(j << 1) + 1];
if (read_val)
*read_val = oth_ins->reg_buf
[(j << 1) + 1];
return true;
}
}
}
}
return false;
}
static void rdma_update_conflict(u32 adr, u32 val)
{
int i;
for (i = 0; i < MAX_CONFLICT; i++) {
if (rdma_info.rdma_reg.adr[i] == adr) {
rdma_info.rdma_reg.val[i] = val;
if (debug_flag & 0x20)
pr_info("(%s) %04x=0x%08x\n",
__func__,
adr, val);
break;
}
}
}
int rdma_write_reg(int handle, u32 adr, u32 val)
{
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
int j = 0;
if (ins->rdma_table_size == 0)
return -1;
if (debug_flag & 1)
pr_info("rdma_write(%d) %d(%x)<=%x\n",
handle, ins->rdma_item_count, adr, val);
if (rdma_check_conflict(handle, adr, NULL))
rdma_update_conflict(adr, val);
if (((ins->rdma_item_count << 1) + 1) <
(ins->rdma_table_size / sizeof(u32))) {
ins->reg_buf[ins->rdma_item_count << 1] = adr;
ins->reg_buf[(ins->rdma_item_count << 1) + 1] = val;
ins->rdma_item_count++;
} else {
int i;
pr_info("%s(%d, %x, %x ,%d) buf overflow\n",
__func__, rdma_watchdog_count,
handle, adr, val);
for (i = 0; i < ins->rdma_item_count; i++)
WRITE_VCBUS_REG(ins->reg_buf[i << 1],
ins->reg_buf[(i << 1) + 1]);
ins->rdma_item_count = 0;
ins->rdma_write_count = 0;
ins->reg_buf[ins->rdma_item_count << 1] = adr;
ins->reg_buf[(ins->rdma_item_count << 1) + 1] = val;
ins->rdma_item_count++;
}
if (rdma_trace_enable) {
for (j = 0; j < rdma_trace_num; j++) {
if (adr == rdma_trace_reg[j]) {
pr_info("(%s) handle %d, %04x=0x%08x (%d)\n",
__func__,
handle, adr,
val,
ins->rdma_item_count);
}
}
}
return 0;
}
EXPORT_SYMBOL(rdma_write_reg);
int rdma_write_reg_bits(int handle, u32 adr, u32 val, u32 start, u32 len)
{
int i, j = 0;
u32 *write_table;
int match = 0;
int match_oth = 0;
int read_from = 0;
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
u32 read_val = READ_VCBUS_REG(adr);
u32 oth_val = 0;
u32 write_val;
if (ins->rdma_table_size == 0)
return -1;
if (rdma_check_conflict(handle, adr, &oth_val)) {
match_oth = 1;
read_val = oth_val;
read_from = 3;
}
for (i = (ins->rdma_item_count - 1); i >= 0; i--) {
if (ins->reg_buf[i << 1] == adr) {
match = 1;
if (!match_oth) {
read_val = ins->reg_buf[(i << 1) + 1];
read_from = 1;
}
break;
}
}
if (!match) {
write_table = ins->rdma_table_addr;
for (i = (ins->rdma_write_count - 1);
i >= 0; i--) {
if (write_table[i << 1] == adr) {
if (!match_oth) {
read_val =
write_table[(i << 1) + 1];
read_from = 2;
}
break;
}
}
}
write_val = (read_val & ~(((1L << (len)) - 1) << (start))) |
((unsigned int)(val) << (start));
if (match_oth)
rdma_update_conflict(adr, write_val);
for (j = 0; j < rdma_trace_num; j++) {
if (adr == rdma_trace_reg[j]) {
if (read_from == 3)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from conflict table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_write_count);
else if (read_from == 2)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from write table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_write_count);
else if (read_from == 1)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from item table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_item_count);
else
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from real reg\n",
__func__,
handle, adr,
read_val,
write_val);
}
}
if (match) {
ins->reg_buf[(i << 1) + 1] = write_val;
return 0;
}
if (debug_flag & 1)
pr_info("rdma_write(%d) %d(%x)<=%x\n",
handle, ins->rdma_item_count, adr, write_val);
rdma_write_reg(handle, adr, write_val);
return 0;
}
EXPORT_SYMBOL(rdma_write_reg_bits);
s32 rdma_add_read_reg(int handle, u32 adr)
{
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = NULL;
if (handle > 0 && handle < RDMA_NUM) {
ins = &info->rdma_ins[handle];
if (((ins->rdma_item_count + 1) << 1) <
(ins->rdma_table_size / sizeof(u32))) {
ins->reg_buf[ins->rdma_item_count] = adr;
ins->rdma_item_count++;
return (ins->rdma_item_count - 1);
}
pr_info("%s: out of bound\n", __func__);
return -1;
}
pr_info("%s: handle is error\n", __func__);
return -1;
}
EXPORT_SYMBOL(rdma_add_read_reg);
u32 *rdma_get_read_back_addr(int handle)
{
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = NULL;
u32 *table;
if (handle > 0 && handle < RDMA_NUM) {
ins = &info->rdma_ins[handle];
table = ins->rdma_table_addr;
if (debug_flag & 2)
pr_info("%s, handle: %d, pre_count: %d\n",
__func__, handle, ins->prev_read_count);
return (table + ins->prev_read_count);
}
return NULL;
}
EXPORT_SYMBOL(rdma_get_read_back_addr);
static struct rdma_device_data_s rdma_meson = {
.cpu_type = CPU_NORMAL,
.rdma_ver = RDMA_VER_1,
.trigger_mask_len = 8,
};
static struct rdma_device_data_s rdma_g12b_reva = {
.cpu_type = CPU_G12B_REVA,
.rdma_ver = RDMA_VER_1,
.trigger_mask_len = 8,
};
static struct rdma_device_data_s rdma_g12b_revb = {
.cpu_type = CPU_G12B_REVB,
.rdma_ver = RDMA_VER_1,
.trigger_mask_len = 8,
};
static struct rdma_device_data_s rdma_tl1 = {
.cpu_type = CPU_TL1,
.rdma_ver = RDMA_VER_2,
.trigger_mask_len = 16,
};
static struct rdma_device_data_s rdma_sc2 = {
.cpu_type = CPU_SC2,
.rdma_ver = RDMA_VER_2,
.trigger_mask_len = 16,
};
static struct rdma_device_data_s rdma_t7 = {
.cpu_type = CPU_T7,
.rdma_ver = RDMA_VER_3,
.trigger_mask_len = 24,
};
static struct rdma_device_data_s rdma_t3 = {
.cpu_type = CPU_T7,
.rdma_ver = RDMA_VER_4,
.trigger_mask_len = 25,
};
static const struct of_device_id rdma_dt_match[] = {
{
.compatible = "amlogic, meson, rdma",
.data = &rdma_meson,
},
{
.compatible = "amlogic, meson-g12b-reva, rdma",
.data = &rdma_g12b_reva,
},
{
.compatible = "amlogic, meson-g12b-revb, rdma",
.data = &rdma_g12b_revb,
},
{
.compatible = "amlogic, meson-tl1, rdma",
.data = &rdma_tl1,
},
{
.compatible = "amlogic, meson-sc2, rdma",
.data = &rdma_sc2,
},
{
.compatible = "amlogic, meson-t7, rdma",
.data = &rdma_t7,
},
{
.compatible = "amlogic, meson-t3, rdma",
.data = &rdma_t3,
},
{},
};
u32 is_meson_g12b_revb(void)
{
if (rdma_meson_dev.cpu_type == CPU_G12B_REVB)
return 1;
else
return 0;
}
void vpp1_vsync_rdma_register(void)
{
int handle;
handle = rdma_register(get_rdma_ops(VSYNC_RDMA_VPP1),
NULL, rdma_table_size);
set_rdma_handle(VSYNC_RDMA_VPP1, handle);
}
EXPORT_SYMBOL(vpp1_vsync_rdma_register);
void vpp2_vsync_rdma_register(void)
{
int handle;
handle = rdma_register(get_rdma_ops(VSYNC_RDMA_VPP2),
NULL, rdma_table_size);
set_rdma_handle(VSYNC_RDMA_VPP2, handle);
}
EXPORT_SYMBOL(vpp2_vsync_rdma_register);
void pre_vsync_rdma_register(void)
{
int handle;
handle = rdma_register(get_rdma_ops(PRE_VSYNC_RDMA),
NULL, rdma_table_size);
set_rdma_handle(PRE_VSYNC_RDMA, handle);
}
EXPORT_SYMBOL(pre_vsync_rdma_register);
static ssize_t show_debug_flag(struct class *class,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", debug_flag);
}
static ssize_t store_debug_flag(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
pr_info("debug_flag: %d->%d\n", debug_flag, res);
debug_flag = res;
return count;
}
static ssize_t show_rdma_watchdog(struct class *class,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", rdma_watchdog);
}
static ssize_t store_rdma_watchdog(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
pr_info("rdma_watchdog: %d->%d\n", rdma_watchdog, res);
rdma_watchdog = res;
return count;
}
static ssize_t show_reset_count(struct class *class,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", reset_count);
}
static ssize_t store_reset_count(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
pr_info("reset_count: %d->%d\n", reset_count, res);
reset_count = res;
return count;
}
static ssize_t show_ctrl_ahb_rd_burst_size(struct class *class,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", ctrl_ahb_rd_burst_size);
}
static ssize_t store_ctrl_ahb_rd_burst_size(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
pr_info("ctrl_ahb_rd_burst_size: %d->%d\n",
ctrl_ahb_rd_burst_size, res);
ctrl_ahb_rd_burst_size = res;
return count;
}
static ssize_t show_ctrl_ahb_wr_burst_size(struct class *class,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", ctrl_ahb_wr_burst_size);
}
static ssize_t store_ctrl_ahb_wr_burst_size(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int res = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &res);
pr_info("ctrl_ahb_wr_burst_size: %d->%d\n",
ctrl_ahb_wr_burst_size, res);
ctrl_ahb_wr_burst_size = res;
return count;
}
static int parse_para(const char *para, int para_num, int *result)
{
char *token = NULL;
char *params, *params_base;
int *out = result;
int len = 0, count = 0;
int res = 0;
int ret = 0;
if (!para)
return 0;
params = kstrdup(para, GFP_KERNEL);
params_base = params;
token = params;
if (!token)
return 0;
len = strlen(token);
do {
token = strsep(&params, " ");
while (token && (isspace(*token) ||
!isgraph(*token)) && len) {
token++;
len--;
}
if (len == 0 || !token)
break;
ret = kstrtoint(token, 0, &res);
if (ret < 0)
break;
len = strlen(token);
*out++ = res;
count++;
} while ((token) && (count < para_num) && (len > 0));
kfree(params_base);
return count;
}
static ssize_t rdma_mgr_trace_enable_show(struct class *cla,
struct class_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%x\n", rdma_trace_enable);
}
static ssize_t rdma_mgr_trace_enable_stroe(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
ret = kstrtoint(buf, 0, &rdma_trace_enable);
if (ret < 0)
return -EINVAL;
return count;
}
static ssize_t rdma_mgr_trace_reg_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
int i;
char reg_info[16];
char *trace_info = NULL;
trace_info = kmalloc(rdma_trace_num * 16 + 1, GFP_KERNEL);
if (!trace_info)
return 0;
for (i = 0; i < rdma_trace_num; i++) {
sprintf(reg_info, "0x%x", rdma_trace_reg[i]);
strcat(trace_info, reg_info);
strcat(trace_info, " ");
}
i = snprintf(buf, PAGE_SIZE, "%s\n", trace_info);
kfree(trace_info);
trace_info = NULL;
return i;
}
static ssize_t rdma_mgr_trace_reg_stroe(struct class *cla,
struct class_attribute *attr,
const char *buf, size_t count)
{
int parsed[MAX_TRACE_NUM];
int i = 0, num = 0;
for (i = 0; i < MAX_TRACE_NUM; i++)
rdma_trace_reg[i] = 0;
num = parse_para(buf, MAX_TRACE_NUM, parsed);
if (num <= MAX_TRACE_NUM) {
rdma_trace_num = num;
for (i = 0; i < num; i++) {
rdma_trace_reg[i] = parsed[i];
pr_info("trace reg:0x%x\n", rdma_trace_reg[i]);
}
}
return count;
}
static struct class_attribute rdma_mgr_attrs[] = {
__ATTR(debug_flag, 0664,
show_debug_flag, store_debug_flag),
__ATTR(rdma_watchdog, 0664,
show_rdma_watchdog, store_rdma_watchdog),
__ATTR(reset_count, 0664,
show_reset_count, store_reset_count),
__ATTR(ctrl_ahb_rd_burst_size, 0664,
show_ctrl_ahb_rd_burst_size, store_ctrl_ahb_rd_burst_size),
__ATTR(ctrl_ahb_wr_burst_size, 0664,
show_ctrl_ahb_wr_burst_size, store_ctrl_ahb_wr_burst_size),
__ATTR(trace_enable, 0664,
rdma_mgr_trace_enable_show, rdma_mgr_trace_enable_stroe),
__ATTR(trace_reg, 0664,
rdma_mgr_trace_reg_show, rdma_mgr_trace_reg_stroe),
};
static struct class *rdma_mgr_class;
static int create_rdma_mgr_class(void)
{
int i;
rdma_mgr_class = class_create(THIS_MODULE, RDMA_MGR_CLASS_NAME);
if (IS_ERR_OR_NULL(rdma_mgr_class)) {
pr_err("create rdma_mgr_class failed\n");
return -1;
}
for (i = 0; i < ARRAY_SIZE(rdma_mgr_attrs); i++) {
if (class_create_file(rdma_mgr_class,
&rdma_mgr_attrs[i])) {
pr_err("create rdma mgr attribute %s failed\n",
rdma_mgr_attrs[i].attr.name);
}
}
return 0;
}
static int remove_rdma_mgr_class(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(rdma_mgr_attrs); i++)
class_remove_file(rdma_mgr_class, &rdma_mgr_attrs[i]);
class_destroy(rdma_mgr_class);
rdma_mgr_class = NULL;
return 0;
}
/* static int __devinit rdma_probe(struct platform_device *pdev) */
static int __init rdma_probe(struct platform_device *pdev)
{
int i;
u32 data32;
int int_rdma;
int handle;
const void *prop;
struct rdma_device_info *info = &rdma_info;
int_rdma = platform_get_irq_byname(pdev, "rdma");
if (int_rdma == -ENXIO) {
dev_err(&pdev->dev, "cannot get rdma irq resource\n");
return -ENODEV;
}
if (pdev->dev.of_node) {
const struct of_device_id *match;
struct rdma_device_data_s *rdma_meson;
struct device_node *of_node = pdev->dev.of_node;
match = of_match_node(rdma_dt_match, of_node);
if (match) {
rdma_meson = (struct rdma_device_data_s *)match->data;
if (rdma_meson) {
memcpy(&rdma_meson_dev, rdma_meson,
sizeof(struct rdma_device_data_s));
} else {
pr_err("%s data NOT match\n", __func__);
return -ENODEV;
}
} else {
pr_err("%s NOT match\n", __func__);
return -ENODEV;
}
} else {
pr_err("dev %s NOT found\n", __func__);
return -ENODEV;
}
/* get rdma_table_size resource */
rdma_table_size = RDMA_TABLE_SIZE;
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
rdma_table_size = 16 * PAGE_SIZE;
prop = of_get_property(pdev->dev.of_node, "rdma_table_page_count", NULL);
if (prop)
rdma_table_size = of_read_ulong(prop, 1) * PAGE_SIZE;
}
pr_info("%s,cpu_type:%d, ver:%d, len:%d,rdma_table_size:%d\n", __func__,
rdma_meson_dev.cpu_type,
rdma_meson_dev.rdma_ver, rdma_meson_dev.trigger_mask_len, rdma_table_size);
rdma_vpu_dev = vpu_dev_register(VPU_RDMA, "rdma");
vpu_dev_mem_power_on(rdma_vpu_dev);
WRITE_VCBUS_REG(VPU_VDISP_ASYNC_HOLD_CTRL, 0x18101810);
WRITE_VCBUS_REG(VPU_VPUARB2_ASYNC_HOLD_CTRL, 0x18101810);
rdma_mgr_irq_request = 0;
memset((void *)&info->rdma_reg, 0, sizeof(struct rdma_conflict_regs_s));
for (i = 0; i < RDMA_NUM; i++) {
info->rdma_ins[i].rdma_table_size = 0;
if (rdma_meson_dev.rdma_ver == RDMA_VER_1) {
info->rdma_ins[i].rdma_regadr = &rdma_regadr[i];
} else if (rdma_meson_dev.rdma_ver == RDMA_VER_2) {
info->rdma_ins[i].rdma_regadr = &rdma_regadr_tl1[i];
} else if (rdma_meson_dev.rdma_ver == RDMA_VER_3) {
info->rdma_ins[i].rdma_regadr = &rdma_regadr_t7[i];
support_64bit_addr = 1;
has_multi_vpp = 1;
} else if (rdma_meson_dev.rdma_ver == RDMA_VER_4) {
info->rdma_ins[i].rdma_regadr = &rdma_regadr_t7[i];
support_64bit_addr = 1;
has_multi_vpp = 1;
} else {
info->rdma_ins[i].rdma_regadr = &rdma_regadr[i];
}
info->rdma_ins[i].keep_buf = 1;
/*do not change it in normal case */
info->rdma_ins[i].used = 0;
info->rdma_ins[i].prev_trigger_type = 0;
info->rdma_ins[i].rdma_write_count = 0;
}
if (rdma_meson_dev.cpu_type >= CPU_SC2) {
rdma_rst = devm_reset_control_get(&pdev->dev, "rdma");
if (IS_ERR(rdma_rst)) {
pr_err("failed to get reset: %ld\n", PTR_ERR(rdma_rst));
return PTR_ERR(rdma_rst);
}
reset_control_reset(rdma_rst);
} else {
WRITE_MPEG_REG(RESET4_REGISTER, (1 << 5));
}
#ifdef SKIP_OSD_CHANNEL
info->rdma_ins[3].used = 1; /* OSD driver uses this channel */
#endif
if (request_irq(int_rdma, &rdma_mgr_isr,
IRQF_SHARED, "rdma", (void *)"rdma")) {
dev_err(&pdev->dev, "can't request irq for rdma\n");
return -ENODEV;
}
rdma_mgr_irq_request = 1;
data32 = 0;
data32 |= 1 << 7; /* wrtie ddr urgent */
data32 |= 1 << 6; /* read ddr urgent */
data32 |= ctrl_ahb_wr_burst_size << 4;
data32 |= ctrl_ahb_rd_burst_size << 2;
data32 |= 0 << 1;
data32 |= 0 << 0;
WRITE_VCBUS_REG(RDMA_CTRL, data32);
info->rdma_dev = pdev;
handle = rdma_register(get_rdma_ops(VSYNC_RDMA),
NULL, rdma_table_size);
set_rdma_handle(VSYNC_RDMA, handle);
if (!has_multi_vpp) {
handle = rdma_register(get_rdma_ops(VSYNC_RDMA_READ),
NULL, rdma_table_size);
set_rdma_handle(VSYNC_RDMA_READ, handle);
}
create_rdma_mgr_class();
rdma_init();
return 0;
}
/* static int __devexit rdma_remove(struct platform_device *pdev) */
static int rdma_remove(struct platform_device *pdev)
{
pr_error("RDMA driver removed.\n");
remove_rdma_mgr_class();
rdma_exit();
vpu_dev_mem_power_down(rdma_vpu_dev);
vpu_dev_unregister(rdma_vpu_dev);
return 0;
}
static struct platform_driver rdma_driver = {
.remove = rdma_remove,
.driver = {
.name = "amlogic-rdma",
.of_match_table = rdma_dt_match,
},
};
int __init amrdma_init(void)
{
return platform_driver_probe(&rdma_driver, rdma_probe);
}
void __exit amrdma_exit(void)
{
platform_driver_unregister(&rdma_driver);
}
//MODULE_DESCRIPTION("AMLOGIC RDMA management driver");
//MODULE_LICENSE("GPL");
//MODULE_AUTHOR("Rain Zhang <rain.zhang@amlogic.com>");