sonic-buildimage/platform/broadcom/sonic-platform-modules-ragile/common/modules/lpc_dbg.c

535 lines
13 KiB
C
Raw Normal View History

#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 19, 0)
#include <linux/uaccess.h>
#endif
#include <asm/uaccess.h>
#include <linux/kernel.h> /* Wd're doing kernel work */
#include <linux/module.h> /* specifically, a module */
#include <linux/types.h>
#include <linux/init.h> /* Need for the macros */
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <net/genetlink.h>
#include <linux/netlink.h>
#include <linux/miscdevice.h>
#include "lpc_dbg.h"
typedef struct rg_lpc_device_s {
u16 base;
u16 size;
u8 type;
u8 id;
u8 lpc_pci_addr;
} rg_lpc_device_t;
typedef enum rg_lpc_dev_type_s {
LPC_DEVICE_CPLD = 1,
LPC_DEVICE_FPGA = 2,
} rg_lpc_dev_type_t;
#define MAX_LPC_DEV_NUM (4)
#define LPC_PCI_CFG_BASE(__lgir) ((0x84) + ((__lgir) * 4))
#define MAX_CPLD_REG_SIZE (0x100)
#define MAX_FPGA_REG_SIZE (0x100) //# fix compile actual value 0x10000
#define LPC_GET_CPLD_ID(addr) ((addr >> 16) & 0xff)
#define LPC_GET_CPLD_OFFSET(addr) ((addr) & 0xff)
int lpc_dbg_verbose = 0;
int lpc_dbg_error = 0;
int lpc_dbg_info = 0;
module_param(lpc_dbg_verbose, int, S_IRUGO | S_IWUSR);
module_param(lpc_dbg_error, int, S_IRUGO | S_IWUSR);
module_param(lpc_dbg_info, int, S_IRUGO | S_IWUSR);
#define LPC_DBG_VERBOSE(fmt, args...) do { \
if (lpc_dbg_verbose) { \
printk(KERN_ERR "[LPC_DBG][VERBOSE][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
#define LPC_DBG_ERROR(fmt, args...) do { \
if (lpc_dbg_error) { \
printk(KERN_ERR "[LPC_DBG][ERROR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
#define LPC_DBG_INFO(fmt, args...) do { \
if (lpc_dbg_info) { \
printk(KERN_ERR ""fmt, ## args); \
} \
} while (0)
static rg_lpc_device_t g_rg_lpc_dev_default[] = {
{.base = 0x700, .size = MAX_CPLD_REG_SIZE, .type = LPC_DEVICE_CPLD, .id = 0, .lpc_pci_addr = 0x84},
{.base = 0x900, .size = MAX_CPLD_REG_SIZE, .type = LPC_DEVICE_CPLD, .id = 1, .lpc_pci_addr = 0x88},
{.base = 0xb00, .size = MAX_CPLD_REG_SIZE, .type = LPC_DEVICE_CPLD, .id = 2, .lpc_pci_addr = 0x90},
};
static rg_lpc_device_t *g_rg_lpc_dev = g_rg_lpc_dev_default;
static rg_lpc_device_t* lpc_get_device_info(int type, int id)
{
int i;
int size;
size = ARRAY_SIZE(g_rg_lpc_dev_default);
for (i = 0; i < size; i++) {
if ((g_rg_lpc_dev[i].type == type) && (g_rg_lpc_dev[i].id == id)) {
return &g_rg_lpc_dev[i];
}
}
return NULL;
}
int lpc_cpld_read(int address, u8 *val)
{
int cpld_id;
rg_lpc_device_t *info;
cpld_id = LPC_GET_CPLD_ID(address);
info = lpc_get_device_info(LPC_DEVICE_CPLD, cpld_id);
if (info == NULL) {
LPC_DBG_ERROR("lpc_get_device_info addr 0x%x id %d failed.\r\n", address, cpld_id);
return -1;
}
*val = inb(info->base + LPC_GET_CPLD_OFFSET(address));
LPC_DBG_VERBOSE("Leave info->base 0x%x, addr 0x%x, cpld_id %d, val 0x%x.\r\n", info->base, address, cpld_id, *val);
return 0;
}
int lpc_cpld_write(int address, u8 reg_val)
{
int cpld_id;
rg_lpc_device_t *info;
cpld_id = LPC_GET_CPLD_ID(address);
info = lpc_get_device_info(LPC_DEVICE_CPLD, cpld_id);
if (info == NULL) {
LPC_DBG_ERROR("lpc_get_device_info addr 0x%x id %d failed.\r\n", address, cpld_id);
return -1;
}
outb(reg_val, info->base + LPC_GET_CPLD_OFFSET(address));
LPC_DBG_VERBOSE("Leave info->base 0x%x, addr 0x%x, cpld_id %d, val 0x%x.\r\n", info->base, address, cpld_id, reg_val);
return 0;
}
int lpc_fpga_read(int address, u8 *val)
{
return -1;
}
int lpc_fpga_write(int address, u8 reg_val)
{
return -1;
}
static ssize_t lpc_misc_cpld_dev_read (struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
int ret;
u8 value8[MAX_CPLD_REG_SIZE];
int i;
if ((count > MAX_CPLD_REG_SIZE)
|| ((LPC_GET_CPLD_OFFSET(file->f_pos) + count) > MAX_CPLD_REG_SIZE)) {
return -EFAULT;
}
for (i = 0; i < count; i++) {
ret = lpc_cpld_read((int)(file->f_pos + i), &value8[i]);
if (ret) {
LPC_DBG_ERROR("lpc_cpld_read i %d addr 0x%x failed ret %d.\n",
i, ((unsigned int)file->f_pos + i), ret);
return i;
}
}
if (copy_to_user(buf, value8, count)) {
return -EFAULT;
}
return count;
}
static ssize_t lpc_misc_cpld_dev_write (struct file *file, const char __user *buf, size_t count,
loff_t *offset)
{
u8 value8[MAX_CPLD_REG_SIZE];
int i;
int ret;
if ((count > MAX_CPLD_REG_SIZE)
|| ((LPC_GET_CPLD_OFFSET(file->f_pos) + count) > MAX_CPLD_REG_SIZE)) {
return -EFAULT;
}
if (copy_from_user(value8, buf, count)) {
return -EFAULT;
}
for (i = 0; i < count; i++) {
ret = lpc_cpld_write((int)(file->f_pos + i), value8[i]);
if (ret) {
LPC_DBG_ERROR("lpc_cpld_write i %d addr 0x%x value 0x%x failed ret %d.\n",
i, (unsigned int)file->f_pos + i, value8[i], ret);
return i;
}
}
return count;
}
static loff_t lpc_misc_cpld_dev_llseek(struct file *file, loff_t offset, int origin)
{
loff_t ret;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36)
mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
#else
/* do noting add tjm */
inode_lock(file_inode(file));
#endif
switch (origin) {
case 0:
file->f_pos = offset;
ret = file->f_pos;
break;
case 1:
file->f_pos += offset;
ret = file->f_pos;
break;
default:
ret = -EINVAL;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36)
mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
#else
/* do noting add tjm */
inode_unlock(file_inode(file));
#endif
return ret;
}
static long lpc_misc_cpld_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return -1;
}
static int lpc_misc_cpld_dev_open(struct inode *inode, struct file *file)
{
file->private_data = NULL;
file->f_pos = 0;
return 0;
}
static int lpc_misc_cpld_dev_release(struct inode *inode, struct file *file)
{
file->private_data = NULL;
file->f_pos = 0;
return 0;
}
static const struct file_operations lpc_misc_cpld_dev_fops = {
.owner = THIS_MODULE,
.llseek = lpc_misc_cpld_dev_llseek,
.read = lpc_misc_cpld_dev_read,
.write = lpc_misc_cpld_dev_write,
.unlocked_ioctl = lpc_misc_cpld_dev_ioctl,
.open = lpc_misc_cpld_dev_open,
.release = lpc_misc_cpld_dev_release,
};
static ssize_t lpc_misc_fpga_dev_read (struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
int ret;
u8 value8[MAX_FPGA_REG_SIZE];
int i;
if ((count > MAX_FPGA_REG_SIZE) || ((file->f_pos + count) > MAX_FPGA_REG_SIZE)) {
return -EFAULT;
}
for (i = 0; i < count; i++) {
ret = lpc_fpga_read((int)(file->f_pos + i), &value8[i]);
if (ret) {
LPC_DBG_ERROR("lpc_fpga_read i %d addr 0x%x failed ret %d.\n",
i, ((unsigned int)file->f_pos + i), ret);
return i;
}
}
if (copy_to_user(buf, value8, count)) {
return -EFAULT;
}
return count;
}
static ssize_t lpc_misc_fpga_dev_write (struct file *file, const char __user *buf, size_t count,
loff_t *offset)
{
int ret;
u8 value8[MAX_FPGA_REG_SIZE];
int i;
if ((count > MAX_FPGA_REG_SIZE) || ((file->f_pos + count) > MAX_FPGA_REG_SIZE)) {
return -EFAULT;
}
if (copy_from_user(value8, buf, count)) {
return -EFAULT;
}
for (i = 0; i < count; i++) {
ret = lpc_fpga_write((int)(file->f_pos + i), value8[i]);
if (ret) {
LPC_DBG_ERROR("lpc_fpga_write i %d addr 0x%x value 0x%x failed ret %d.\n",
i, (int)(file->f_pos + i), value8[i], ret);
return i;
}
}
return count;
}
static loff_t lpc_misc_fpga_dev_llseek(struct file *file, loff_t offset, int origin)
{
loff_t ret;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36)
mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
#else
/* do noting add tjm */
inode_lock(file_inode(file));
#endif
switch (origin) {
case 0:
file->f_pos = offset;
ret = file->f_pos;
break;
case 1:
file->f_pos += offset;
ret = file->f_pos;
break;
default:
ret = -EINVAL;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36)
mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
#else
/* do noting add tjm */
inode_unlock(file_inode(file));
#endif
return ret;
}
static long lpc_misc_fpga_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return -1;
}
static int lpc_misc_fpga_dev_open(struct inode *inode, struct file *file)
{
file->private_data = NULL;
file->f_pos = 0;
return 0;
}
static int lpc_misc_fpga_dev_release(struct inode *inode, struct file *file)
{
file->private_data = NULL;
file->f_pos = 0;
return 0;
}
static const struct file_operations lpc_misc_fpga_dev_fops = {
.owner = THIS_MODULE,
.llseek = lpc_misc_fpga_dev_llseek,
.read = lpc_misc_fpga_dev_read,
.write = lpc_misc_fpga_dev_write,
.unlocked_ioctl = lpc_misc_fpga_dev_ioctl,
.open = lpc_misc_fpga_dev_open,
.release = lpc_misc_fpga_dev_release,
};
static struct miscdevice lpc_misc_cpld_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "lpc_cpld",
.fops = &lpc_misc_cpld_dev_fops,
};
static struct miscdevice lpc_misc_fpga_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "lpc_fpga",
.fops = &lpc_misc_fpga_dev_fops,
};
static int lpc_misc_drv_init(void)
{
if (misc_register(&lpc_misc_cpld_dev) != 0) {
LPC_DBG_ERROR("Register %s failed.\r\n", lpc_misc_cpld_dev.name);
return -ENXIO;
}
if (misc_register(&lpc_misc_fpga_dev) != 0) {
LPC_DBG_ERROR("Register %s failed.\r\n", lpc_misc_fpga_dev.name);
return -ENXIO;
}
return 0;
}
static void lpc_misc_drv_exit(void)
{
misc_deregister(&lpc_misc_cpld_dev);
misc_deregister(&lpc_misc_fpga_dev);
}
#define LPC_MAKE_PCI_IO_RANGE(__base) ((0xfc0001) | ((__base) & (0xFFFC)))
static int lpc_pci_cfg_init(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int i;
int size;
size = ARRAY_SIZE(g_rg_lpc_dev_default);
for (i = 0; i < size; i++) {
pci_write_config_dword(pdev, g_rg_lpc_dev[i].lpc_pci_addr, LPC_MAKE_PCI_IO_RANGE(g_rg_lpc_dev[i].base));
LPC_DBG_VERBOSE("set lpc pci cfg[addr: 0x%x, value:0x%x].\n", LPC_PCI_CFG_BASE(i), LPC_MAKE_PCI_IO_RANGE(g_rg_lpc_dev[i].base));
if (!request_region(g_rg_lpc_dev[i].base, g_rg_lpc_dev[i].size, "rg_lpc")) {
LPC_DBG_ERROR("request_region [0x%x][0x%x] failed!\n", g_rg_lpc_dev[i].base, g_rg_lpc_dev[i].size);
return -EBUSY;
}
}
return 0;
}
static void lpc_pci_cfg_exit(void)
{
int i;
int size;
size = ARRAY_SIZE(g_rg_lpc_dev_default);
for (i = 0; i < size; i++) {
release_region(g_rg_lpc_dev[i].base, g_rg_lpc_dev[i].size);
}
return;
}
static int rg_lpc_cpld_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
LPC_DBG_VERBOSE("Enter.\n");
ret = lpc_pci_cfg_init(pdev, id);
if (ret) {
LPC_DBG_ERROR("lpc_pci_cfg_init failed ret %d.\n", ret);
return ret;
}
ret = lpc_misc_drv_init();
if (ret) {
LPC_DBG_ERROR("lpc_misc_drv_init failed ret %d.\n", ret);
return ret;
}
LPC_DBG_VERBOSE("Leave success\n");
return 0;
}
static void rg_lpc_cpld_remove(struct pci_dev *pdev)
{
LPC_DBG_VERBOSE("Enter.\n");
lpc_misc_drv_exit();
lpc_pci_cfg_exit();
LPC_DBG_VERBOSE("Leave.\n");
}
#define PCI_VENDOR_ID_D1527_LPC (0x8c54)
#define PCI_VENDOR_ID_C3000_LPC (0x19dc)
#if 0
static const struct pci_device_id rg_lpc_cpld_pcidev_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_C3000_LPC) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_D1527_LPC) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, rg_lpc_cpld_pcidev_id);
static struct pci_driver rg_lpc_driver = {
.name = "rg_lpc",
.id_table = rg_lpc_cpld_pcidev_id,
.probe = rg_lpc_cpld_probe,
.remove = rg_lpc_cpld_remove,
};
module_pci_driver(rg_lpc_driver);
#else
static int __init lpc_dbg_init(void)
{
struct pci_dev *pdev = NULL;
int ret;
LPC_DBG_VERBOSE("Enter.\n");
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_D1527_LPC, pdev);
if (!pdev) {
LPC_DBG_ERROR("pci_get_device(0x8086, 0x8c54) failed!\n");
return 0;
}
ret = rg_lpc_cpld_probe(pdev, NULL);
LPC_DBG_VERBOSE("Leave ret %d.\n", ret);
return ret;
}
static void __exit lpc_dbg_exit(void)
{
LPC_DBG_VERBOSE("Enter.\n");
rg_lpc_cpld_remove(NULL);
LPC_DBG_VERBOSE("Leave.\n");
}
module_init(lpc_dbg_init);
module_exit(lpc_dbg_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("support <support@ragile.com>");