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
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");
|
|
|