You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
8.1 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd. 2010-2021. All rights reserved.
* Description: common driver moudle define
* Author: Hisilicon
* Create: 2010-1-25
*/
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/arm-smccc.h>
#include "osal_ext.h"
#include "drv_base_ext.h"
#include "drv_dev_ext.h"
#include "drv_media_ext.h"
#include "osal_comm.h"
#include "drv_module.h"
#include "soc_module.h"
#include "drv_ioctl_module.h"
#include "osal_private.h"
typedef struct {
unsigned int *interrupt_cpu_array;
unsigned int affinity_cells;
unsigned int affinity_groups;
} affinity_info;
static struct platform_device *g_osal_virt_dev = NULL;
static affinity_info g_osal_affinity_info = {0};
/* irq: hard irq number in dts
* paffinity: affinity to fill in
* used by osal only
* 0 on success, -x on errors
*/
int osal_irq_find_affinity(unsigned int irq, unsigned int *paffinity)
{
unsigned int affinity_cells, affinity_groups, i;
if (unlikely(paffinity == NULL)) {
osal_printk("paffinity is null!\n");
return -EINVAL;
}
if (g_osal_affinity_info.interrupt_cpu_array == NULL) { /* not exist or error */
osal_printk(KERN_DEBUG"interrupt_cpu_info was null cannot find affnity!\n");
*paffinity = OSAL_CPU_ALL;
return -ENOENT;
}
affinity_cells = g_osal_affinity_info.affinity_cells;
affinity_groups = g_osal_affinity_info.affinity_groups;
for (i = 0; i < affinity_groups; i++) { /* traverse every group */
if (irq == g_osal_affinity_info.interrupt_cpu_array[i * affinity_cells]) {
break;
}
}
if (i == affinity_groups) { /* no irq in table */
osal_printk("irq:%#x was out of plan, please set affinity manually!\n", irq);
*paffinity = OSAL_CPU_ALL;
return -ENOENT;
}
*paffinity = g_osal_affinity_info.interrupt_cpu_array[i * affinity_cells + 1];
return 0;
}
int osal_get_irq_by_name(const char *name)
{
struct resource *res = NULL;
if (g_osal_virt_dev == NULL) {
osal_printk("%s -osal_virt_dev is not registered\n", __FUNCTION__);
return -1;
}
if (name == NULL) {
osal_printk("input module name is NULL.\n");
return -1;
}
res = platform_get_resource_byname(g_osal_virt_dev, IORESOURCE_IRQ, name);
if (res == NULL) {
osal_printk("module %s platform_get_resource_byname fail!\n", name);
return -1;
}
return (int)res->start;
}
EXPORT_SYMBOL(osal_get_irq_by_name);
void osal_smccc_smc(const osal_smccc_info *info, osal_smccc_res *res)
{
struct arm_smccc_res res_tmp = { 0 };
if (info == NULL || res == NULL) {
osal_printk("osal_smccc_smc info or res null ptr\n");
return;
}
arm_smccc_smc(info->a0, info->a1, info->a2, info->a3,
info->a4, info->a5, info->a6, info->a7, &res_tmp);
res->a0 = res_tmp.a0;
res->a1 = res_tmp.a1;
res->a2 = res_tmp.a2;
res->a3 = res_tmp.a3;
}
EXPORT_SYMBOL(osal_smccc_smc);
static int drv_osal_virt_probe(struct platform_device *dev)
{
int ret;
unsigned int affinity_cells;
unsigned int affinity_groups;
osal_printk("name:%s\n", dev->dev.of_node->name);
if (strcmp(dev->dev.of_node->name, "virtdev") == 0) {
g_osal_virt_dev = dev;
osal_printk("virtual device initialization.1 success\n");
} else if (strcmp(dev->dev.of_node->name, "cpu_affinity") == 0) {
ret = of_property_read_u32(dev->dev.of_node, "affinity-cells", &affinity_cells);
if (ret != 0) {
osal_printk("get affinity-cells failed\n");
return -1;
}
ret = of_property_read_u32(dev->dev.of_node, "affinity-size-cells", &affinity_groups);
if (ret != 0) {
osal_printk("get affinity-size-cells failed\n");
return -1;
}
g_osal_affinity_info.interrupt_cpu_array =
(unsigned int *)kzalloc((affinity_cells * affinity_groups * sizeof(unsigned int)), GFP_KERNEL);
if (g_osal_affinity_info.interrupt_cpu_array == NULL) {
osal_printk("kzalloc interrupt cpu info failed\n");
return -1;
}
ret = of_property_read_u32_array(dev->dev.of_node, "interrupt_cpu",
g_osal_affinity_info.interrupt_cpu_array, (affinity_cells * affinity_groups));
if (ret != 0) {
osal_printk("get interrupt_cpu info failed\n");
kfree(g_osal_affinity_info.interrupt_cpu_array);
g_osal_affinity_info.interrupt_cpu_array = NULL;
return -1;
}
g_osal_affinity_info.affinity_cells = affinity_cells;
g_osal_affinity_info.affinity_groups = affinity_groups;
osal_printk("virtual device initialization.2 success\n");
}
return 0;
}
static int drv_osal_virt_remove(struct platform_device *dev)
{
if ((strcmp(dev->dev.of_node->name, "cpu_affinity") == 0) &&
(g_osal_affinity_info.interrupt_cpu_array != NULL)) {
kfree(g_osal_affinity_info.interrupt_cpu_array);
g_osal_affinity_info.interrupt_cpu_array = NULL;
}
return 0;
}
static const struct of_device_id g_osal_virt_dev_match[] __maybe_unused = {
{ .compatible = "virt-device", },
{ .compatible = "cpu_affinity", },
{},
};
MODULE_DEVICE_TABLE(of, g_osal_virt_dev_match);
struct platform_driver g_osal_virt_platform_drv = {
.probe = drv_osal_virt_probe,
.remove = drv_osal_virt_remove,
.driver = {
.name = "virt-device",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(g_osal_virt_dev_match),
},
};
static int ext_drv_osal_init(void)
{
int ret;
ret = platform_driver_register(&g_osal_virt_platform_drv);
if (ret != 0) {
osal_printk("register driver failed\n");
return -1;
}
ret = drv_pm_mod_init();
if (ret != TD_SUCCESS) {
osal_printk("drv_pm_mod_init failed:%#x!\n", ret);
goto exit_platform;
}
return TD_SUCCESS;
exit_platform:
platform_driver_unregister(&g_osal_virt_platform_drv);
return ret;
}
static void ext_drv_osal_exit(void)
{
platform_driver_unregister(&g_osal_virt_platform_drv);
drv_pm_mod_exit();
return;
}
static int osal_drv_open(void *private_data)
{
osal_printk("osal open\n");
return 0;
}
static int osal_drv_close(void *private_data)
{
osal_printk("osal close\n");
return 0;
}
static osal_fileops g_osal_module_fops = {
.open = osal_drv_open,
.release = osal_drv_close,
.cmd_list = NULL,
.cmd_cnt = 0,
};
static osal_dev g_osal_dev = {
.name = SOC_DEV_OSAL_NAME,
.minor = SOC_DEV_OSAL_MINOR,
.fops = &g_osal_module_fops,
};
static int drv_osal_dev_register(void)
{
int ret;
ret = osal_dev_register(&g_osal_dev);
if (ret != 0) {
osal_printk("register device failed\n");
return -1;
}
return 0;
}
static void drv_osal_dev_unregister(void)
{
osal_dev_unregister(&g_osal_dev);
}
int drv_osal_module_init(void)
{
int ret;
drv_module_init();
ret = ext_drv_osal_init();
if (ret != 0) {
osal_printk("common init failed\n");
goto err_module_exit;
}
ret = drv_osal_dev_register();
if (ret != 0) {
osal_printk("dev register failed\n");
goto err_osal_exit;
}
#ifndef SOCT_FPGA_SUPPORT
ret = ext_drv_bus_clock_init();
if (ret != 0) {
osal_printk("init bus clock failed\n");
goto err_osal_unregister;
}
#endif
#ifdef MODULE
osal_printk("Load osal_ext.ko success.\n");
#endif
return 0;
#ifndef SOCT_FPGA_SUPPORT
err_osal_unregister:
drv_osal_dev_unregister();
#endif
err_osal_exit:
ext_drv_osal_exit();
err_module_exit:
drv_module_exit();
return -1;
}
void drv_osal_module_exit(void)
{
drv_osal_dev_unregister();
drv_module_exit();
ext_drv_osal_exit();
#ifndef SOCT_FPGA_SUPPORT
ext_drv_bus_clock_deinit();
#endif
osal_printk("remove osal_ext.ko success.\n");
return;
}
#ifdef MODULE
module_init(drv_osal_module_init);
module_exit(drv_osal_module_exit);
#else
soc_initcall(drv_osal_module_init);
#endif
MODULE_AUTHOR("HUANGLONG");
MODULE_LICENSE("GPL");