1
0
Files
kernel-49/drivers/net/rt_rdm/rdm.c
2023-02-17 04:28:36 +07:00

233 lines
5.9 KiB
C

#include <linux/init.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include "rdm.h"
#ifdef CONFIG_MIPS
#include <asm/rt2880/rt_mmap.h>
#endif
#ifdef CONFIG_ARCH_MEDIATEK
#include <linux/io.h>
struct bus_desc {
void __iomem *base_map;
u32 base;
u32 size;
};
#if defined(CONFIG_MACH_MT7622)
#include "rdm_mt7622.h"
static struct bus_desc mtk_bus_desc[] = {
{ NULL, MEDIATEK_TOPRGU_BASE, MEDIATEK_TOPRGU_SIZE },
{ NULL, MEDIATEK_PHRSYS_BASE, MEDIATEK_PHRSYS_SIZE },
{ NULL, MEDIATEK_WBSYS_BASE, MEDIATEK_WBSYS_SIZE },
{ NULL, MEDIATEK_HIFSYS_BASE, MEDIATEK_HIFSYS_SIZE },
{ NULL, MEDIATEK_HIFAXI_BASE, MEDIATEK_HIFAXI_SIZE },
{ NULL, MEDIATEK_ETHSYS_BASE, MEDIATEK_ETHSYS_SIZE },
};
#elif defined(CONFIG_MACH_MT7981) || defined(CONFIG_MACH_MT7986)
#include "rdm_mt7986.h"
static struct bus_desc mtk_bus_desc[] = {
{ NULL, MEDIATEK_TOPRGU_BASE, MEDIATEK_TOPRGU_SIZE },
{ NULL, MEDIATEK_CIRQ_BASE, MEDIATEK_CIRQ_SIZE },
{ NULL, MEDIATEK_EIP97_BASE, MEDIATEK_EIP97_SIZE },
{ NULL, MEDIATEK_PERISYS_BASE, MEDIATEK_PERISYS_SIZE },
{ NULL, MEDIATEK_HIFSYS_BASE, MEDIATEK_HIFSYS_SIZE },
{ NULL, MEDIATEK_PHRSYS_BASE, MEDIATEK_PHRSYS_SIZE },
{ NULL, MEDIATEK_ETHSYS_BASE, MEDIATEK_ETHSYS_SIZE },
{ NULL, MEDIATEK_WBSYS_BASE, MEDIATEK_WBSYS_SIZE },
};
#else
#error "please define MACH for CONFIG_ARCH_MEDIATEK"
#endif
#endif /* CONFIG_ARCH_MEDIATEK */
#define RDM_SYSCTL_ADDR RALINK_SYSCTL_BASE // system control
#define RDM_WIRELESS_ADDR RALINK_11N_MAC_BASE // wireless control
#define RDM_DEVNAME "rdm0"
#define RDM_MAJOR 223
static int rdm_major = RDM_MAJOR;
static unsigned long register_control = RDM_SYSCTL_ADDR;
static u32 register_bus = RDM_SYSCTL_ADDR;
static long rdm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned long baseaddr, addr = 0;
u32 rtvalue, offset, count = 0;
#ifdef CONFIG_ARCH_MEDIATEK
size_t i;
#endif
baseaddr = register_control;
if (cmd == RT_RDM_CMD_SHOW) {
offset = *(u32 *)arg;
rtvalue = (u32)(*(volatile u32 *)(baseaddr + offset));
printk("0x%x\n", rtvalue);
} else if (cmd == RT_RDM_CMD_DUMP) {
for (count=0; count < RT_RDM_DUMP_RANGE ; count++) {
offset = *(u32 *)arg + (count * 16);
addr = baseaddr + offset;
printk("%08X: ", register_bus + offset);
printk("%08X %08X %08X %08X\n",
(u32)(*(volatile u32 *)(addr)),
(u32)(*(volatile u32 *)(addr+4)),
(u32)(*(volatile u32 *)(addr+8)),
(u32)(*(volatile u32 *)(addr+12)));
}
} else if (cmd == RT_RDM_CMD_READ) {
offset = *(u32 *)arg;
rtvalue = (u32)(*(volatile u32 *)(baseaddr + offset));
put_user(rtvalue, (int __user *)arg);
} else if (cmd == RT_RDM_CMD_SET_BASE_SYS) {
#ifdef CONFIG_ARCH_MEDIATEK
register_control = (unsigned long)mtk_bus_desc[ETHSYS].base_map;
#else
register_control = RDM_SYSCTL_ADDR;
#endif
register_bus = RDM_SYSCTL_ADDR;
printk("switch register base addr to system register 0x%08x\n", register_bus);
} else if (cmd == RT_RDM_CMD_SET_BASE_WLAN) {
#ifdef CONFIG_ARCH_MEDIATEK
register_control = (unsigned long)mtk_bus_desc[WBSYS].base_map;
#else
register_control = RDM_WIRELESS_ADDR;
#endif
register_bus = RDM_WIRELESS_ADDR;
printk("switch register base addr to wireless register 0x%08x\n", register_bus);
} else if (cmd == RT_RDM_CMD_SHOW_BASE) {
printk("current register base addr is 0x%08x\n", register_bus);
} else if (cmd == RT_RDM_CMD_SET_BASE) {
register_bus = *(u32 *)arg;
#ifdef CONFIG_ARCH_MEDIATEK
offset = 0;
if (register_bus < mtk_bus_desc[0].base)
register_bus = mtk_bus_desc[0].base;
for (i = ARRAY_SIZE(mtk_bus_desc) - 1; i >= 0; i--) {
struct bus_desc *bd = &mtk_bus_desc[i];
if (register_bus >= bd->base) {
offset = register_bus - bd->base;
if (offset > bd->size - 4)
offset = bd->size - 4;
register_control = (unsigned long)(bd->base_map + offset);
break;
}
}
#else
register_control = (unsigned long)register_bus;
#endif
printk("switch register base addr to 0x%08x\n", register_bus);
} else if (((cmd & 0xffff) == RT_RDM_CMD_WRITE) || ((cmd & 0xffff) == RT_RDM_CMD_WRITE_SILENT)) {
offset = cmd >> 16;
*(volatile u32 *)(baseaddr + offset) = *(u32 *)arg;
if ((cmd & 0xffff) == RT_RDM_CMD_WRITE)
printk("write offset 0x%x, value 0x%x\n", offset, *(u32 *)arg);
} else {
return -EOPNOTSUPP;
}
return 0;
}
static int rdm_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
return 0;
}
static int rdm_release(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return 0;
}
static const struct file_operations rdm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = rdm_ioctl,
.open = rdm_open,
.release = rdm_release,
};
static void free_bus_resources(void)
{
#ifdef CONFIG_ARCH_MEDIATEK
size_t i;
/* iounmap registers */
for (i = 0; i < ARRAY_SIZE(mtk_bus_desc); i++) {
struct bus_desc *bd = &mtk_bus_desc[i];
if (bd->base_map) {
iounmap(bd->base_map);
bd->base_map = NULL;
}
}
#endif
}
int __init rdm_init(void)
{
int result;
#ifdef CONFIG_ARCH_MEDIATEK
size_t i;
/* iomap registers */
for (i = 0; i < ARRAY_SIZE(mtk_bus_desc); i++) {
struct bus_desc *bd = &mtk_bus_desc[i];
bd->base_map = ioremap(bd->base, bd->size);
if (!bd->base_map) {
free_bus_resources();
return -ENOMEM;
}
}
register_control = (unsigned long)mtk_bus_desc[ETHSYS].base_map;
#endif
result = register_chrdev(rdm_major, RDM_DEVNAME, &rdm_fops);
if (result < 0) {
printk(KERN_WARNING "ps: can't get major %d\n", rdm_major);
free_bus_resources();
return result;
}
if (rdm_major == 0)
rdm_major = result; /* dynamic */
return 0;
}
void __exit rdm_exit(void)
{
free_bus_resources();
unregister_chrdev(rdm_major, RDM_DEVNAME);
}
module_init(rdm_init);
module_exit(rdm_exit);
module_param (rdm_major, int, 0);
MODULE_LICENSE("GPL");