blob: 720af180d277d012cce63e6959f844efad6d9f1c [file] [log] [blame]
/*
* drivers/soc/zte/plat/plat-zx298501.c
*
* Copyright (C) 2021 ZTE-TSP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/syscore_ops.h>
#include <linux/gpio.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <linux/reset.h>
#include <linux/io.h>
#include <linux/amba/serial.h>
#include <linux/serial_reg.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/sched/clock.h>
#include <linux/suspend.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/reboot.h>
#include <linux/miscdevice.h>
#include <dt-bindings/soc/mbtk_plat_irq.h>
#include <uapi/linux/bsp_api.h>
//#include <linux/soc/sc/common.h>
/*#include <linux/soc/sc/pcu.h>
#include <linux/soc/sc/spinlock.h>
*/
/*
* we use sysfs to test&debug some system funcs
*
*/
struct kobject *zx_root_kobj;
struct kobject *zx_test_kobj;
struct kobject *zx_pm_kobj;
extern int __init zx_clk_test_init(void);
extern int __init zx_dma_test_init(void);
extern int __init zx_icp_test_init(void);
extern int __init zx_timer_test_init(void);
#define DOUBLE_EINT_DBG 0
#define EINT_THREAD_TEST 0
#define CONFIG_USE_DEBUG_LED 1
#define ZX_RESET_TEST 1
#define ZX_CLK_TEST 1
#define ZX_PINCTRL_TEST 1
#define ZX_GPIO_TEST 1
#define ZX_EINT_TEST 1
#define ZX_PM_TEST 1
#if ZX_PM_TEST
#define PM_RUNTIME_AUTO_TEST 1
#endif
#define ZX_SPINLOCK_TEST 0
#define ZX_PM_QOS_TEST 0
#define TRUE 1
#define FALSE 0
/*
*
* some test need device probe
*/
struct zx_drv_test
{
struct device *dev;
#if ZX_RESET_TEST
struct reset_control *rst;
#endif
#if ZX_PINCTRL_TEST
struct pinctrl *pctrl;
struct pinctrl_state *state0;
struct pinctrl_state *state1;
struct pinctrl_state *state2;
#endif
#if ZX_GPIO_TEST
int gpio;
int gpio2;
int gpio3;
struct gpio_desc *gd;
#endif
#if ZX_EINT_TEST
int eint_irq;
int eint_irq2;
#endif
#if ZX_CLK_TEST
struct clk *clk;
#endif
};
struct zx_drv_test drv_test = {0};
#define MAX_GPIO_NUM 4
struct MbtkPlatIrq_dev
{
struct device *dev;
struct pinctrl *pctrl;
int gpio_desc[MAX_GPIO_NUM] ;
int release_func_callback[MAX_GPIO_NUM] ;
//struct wakeup_source *WakeUp_ws;
};
struct MbtkPlatIrq_dev g_MbtkPlatIrq_dev = {0};
#if 0//ZX_RESET_TEST
static void drv_reset_test(struct reset_control *rstc)
{
reset_control_assert(rstc);
udelay(10);
reset_control_deassert(rstc);
}
#endif
#if ZX_EINT_TEST
#if EINT_THREAD_TEST
static irqreturn_t test_eint_pri_isr(int irq, void *p)
{
disable_irq_nosync(irq);
return IRQ_WAKE_THREAD;
}
static irqreturn_t test_eint_isr(int irq, void *p)
{
static int eint_cnt = 0;
if ( pinctrl_select_state(drv_test.pctrl, drv_test.state0) < 0) {
pr_err("setting state0 failed\n");
}
irq_set_irq_type(drv_test.eint_irq, gpio_get_value(drv_test.gpio)?IRQ_TYPE_LEVEL_LOW:IRQ_TYPE_LEVEL_HIGH);
if ( pinctrl_select_state(drv_test.pctrl, drv_test.state1) < 0) {
pr_err("setting state0 failed\n");
}
enable_irq(irq);
pr_info("eint9 get = %d\n", ++eint_cnt);
return IRQ_HANDLED;
}
#else
static irqreturn_t test_eint_isr(int irq, void *p)
{
static int eint_cnt = 0;
irq_set_irq_type(drv_test.eint_irq, gpio_get_value(drv_test.gpio)?IRQ_TYPE_LEVEL_LOW:IRQ_TYPE_LEVEL_HIGH);
//pr_info("eint9 get = %d\n", ++eint_cnt);
return IRQ_HANDLED;
}
#endif
static irqreturn_t test_eint_isr2(int irq, void *p)
{
static int eint_cnt1 = 0;
irq_set_irq_type(drv_test.eint_irq2, gpio_get_value(drv_test.gpio2)?IRQ_TYPE_LEVEL_LOW:IRQ_TYPE_LEVEL_HIGH);
pr_info("eint12 get = %d\n", ++eint_cnt1);
return IRQ_HANDLED;
}
#endif
/*-------------------------------------------------------------------*/
#define MBTK_IRQ_MINOR (170)
#define MBTK_LIBIRQ_MAX (4)
/*
* line : request
* type : driver use
* wake_flag : for wait
*
*/
struct libirq_info {
unsigned int line;
unsigned int hirq;
unsigned int virq;
unsigned int type;
int wake;
unsigned int used;
bool wake_flag;
wait_queue_head_t wait;
char name[16];
};
struct libirq_context {
unsigned int pending;
spinlock_t lock;
struct pinctrl *pctrl;
struct pinctrl_state *state[MBTK_LIBIRQ_MAX];
struct device_node *np;
struct device_node *ext8in1_np;
struct libirq_info info[MBTK_LIBIRQ_MAX];
};
static struct libirq_context irq_ctx = {0};
#define line_used(l) irq_ctx.info[l].used
static int irq_line_convert(int line)
{
#if 0 //forbid by niening
if (line>=4)
return EX24_INT + line - 8;
else
return EX21_INT + line;
#else
int irq;
irq = gpio_to_irq(g_MbtkPlatIrq_dev.gpio_desc[line]);
if (irq < 0)
{
pr_err("%s. gpio %d request irq %d failed\n", __func__,g_MbtkPlatIrq_dev.gpio_desc[line], irq);
}
return irq;
#endif
}
static unsigned int irq_type_convert(unsigned int req_type)
{
//printk("--->%s/L%d req_type = %d\n", __FUNCTION__, __LINE__, req_type);
if (req_type == 0)
return IRQ_TYPE_EDGE_RISING;
else if (req_type == 1)
return IRQ_TYPE_EDGE_FALLING;
else if (req_type == 2)
return IRQ_TYPE_LEVEL_HIGH;
else if (req_type == 3)
return IRQ_TYPE_LEVEL_LOW;
else
return IRQ_TYPE_NONE;
}
static int mbkt_irq_map_ext8in1(int hirq, unsigned int type)
{
struct of_phandle_args args;
args.args_count = 2;
args.args[0] = hirq;
args.args[1] = type;
args.np = irq_ctx.ext8in1_np;
return irq_create_of_mapping(&args);
}
static int mbkt_irq_map(int hirq, unsigned int type, unsigned int line)
{
struct of_phandle_args args;
int ret = 0;
#if 0
char name[16];
//if (hirq>=EX8_INT && hirq<=EX15_INT)
// return mbkt_irq_map_ext8in1(hirq, type);
memset(name, 0, sizeof(name));
sprintf(name, "%s%d", "gpio_irq", line);
ret = gpio_request(g_MbtkPlatIrq_dev.gpio_desc[line], name);
if(ret < 0)
{
pr_err("%s. gpio_request for =%d failed\n", __func__,g_MbtkPlatIrq_dev.gpio_desc[line]);
}
gpio_direction_input(g_MbtkPlatIrq_dev.gpio_desc[line]);
hirq = gpio_to_irq(g_MbtkPlatIrq_dev.gpio_desc[line]);
pr_err("%s. %s=%d, hirq = %d\n", __func__, name, g_MbtkPlatIrq_dev.gpio_desc[line], hirq);
irq_ctx.info[line].hirq = hirq;
#endif
args.args_count = 3;
args.args[0] = 0;
args.args[1] = hirq;
args.args[2] = type;
args.np = irq_ctx.np;
return hirq;
//return irq_create_of_mapping(&args);
}
static void mbtk_irq_wait(unsigned int line)
{
struct libirq_info *info = &(irq_ctx.info[line]);
info->wake_flag = false;
wait_event_freezable(info->wait, info->wake_flag);
}
static void mbtk_irq_wakeup(unsigned int line)
{
struct libirq_info *info = &(irq_ctx.info[line]);
info->wake_flag = true;
wake_up_interruptible(&info->wait);
}
static irqreturn_t mbtk_irq_isr(int irq, void *priv)
{
struct libirq_info *info = (struct libirq_info *)priv;
unsigned int line = info->line;
int gpio_value = 0;
disable_irq_nosync(irq); //add by niening
gpio_value = gpio_get_value_cansleep(g_MbtkPlatIrq_dev.gpio_desc[line]) ;
printk("%s/L%d, gpio_value = %d \n", __FUNCTION__, __LINE__, gpio_value);
if(info->wake)
{
pm_wakeup_event(g_MbtkPlatIrq_dev.dev, 2000);
}
if(line_used(line)) {
irq_ctx.pending |= BIT(line);
mbtk_irq_wakeup(line);
}
pr_info("%s:eint get = %d\n", __func__, line);
enable_irq(irq);//add by niening
return IRQ_HANDLED;
}
static int mbtk_irq_open(struct inode *inode, struct file *filp)
{
int error = 0;
unsigned int line;
struct libirq_info *info;
line = iminor(inode) - MBTK_IRQ_MINOR;
filp->private_data = &(irq_ctx.info[line]);
info = (struct libirq_info *)filp->private_data;
// add by niening for solve upper app restart send install cmd
if (g_MbtkPlatIrq_dev.release_func_callback[info->line] == TRUE)
{
pr_err("%s/L%d\n", __FUNCTION__, __LINE__);
free_irq(info->virq, info);
}
return error;
}
static int mbtk_irq_release(struct inode *inode, struct file *filp)
{
struct libirq_info *info;
info = (struct libirq_info *)filp->private_data;
pr_err("%s/L%d\n", __FUNCTION__, __LINE__);
if(line_used(info->line)) {
#if 0 // forbid by niening for upper app goto sleep will callback this function
//irq_set_irq_type(info->virq, IRQ_TYPE_NONE);
//free_irq(info->virq, info);
#endif
line_used(info->line) = 0;
}
filp->private_data = NULL;
g_MbtkPlatIrq_dev.release_func_callback[info->line] = TRUE;
return 0;
}
static long mbtk_irq_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int error = 0;
struct libirq_info *info;
int virq;
unsigned int type;
unsigned int en;
int ret = 0;
unsigned long flags;
info = (struct libirq_info *)filp->private_data;
switch (cmd) {
case SC_IRQ_INSTALL:
if(line_used(info->line))
return -EEXIST;
type = irq_type_convert((unsigned int)arg);
virq = mbkt_irq_map(info->hirq, type, info->line);
if (virq <= 0) {
pr_err("%s:mbkt_irq_map %d failed %d(%d)\n", __func__, info->line, virq, type);
return -ENOMEM;
}
/* pr_err("%s:mbkt_irq_map %d %d %d\n", __func__, info->line, virq, info->hirq);*/
#if 1// niening_Test
/* if ( pinctrl_select_state(irq_ctx.pctrl, irq_ctx.state[info->line]) < 0) {
pr_err("%s:setting state%d failed\n", __func__, info->line);
return -ENODEV;
}
*/
ret = request_irq(virq, mbtk_irq_isr, 0, info->name, info);
if(ret<0) {
pr_err("%s:request_irq %d failed %d\n", __func__, info->line, type);
return ret;
}
#else
ret = devm_request_threaded_irq(g_MbtkPlatIrq_dev.dev, virq, mbtk_irq_isr,mbtk_irq_isr,0 , info->name, info);
#endif
info->virq = virq;
info->type = type;
line_used(info->line) = 1;
pr_info("%s:install(%d) hirq(%d) virq(%d) type(%d)\n", __func__, info->line, info->hirq, info->virq, info->type);
break;
case SC_IRQ_UNINSTALL:
if(!line_used(info->line))
return -ENODEV;
irq_set_irq_type(info->virq, IRQ_TYPE_NONE);
free_irq(info->virq, info);
line_used(info->line) = 0;
pr_info("%s:uninstall(%d)\n", __func__, info->line);
break;
case SC_IRQ_SET_TYPE:
if(!line_used(info->line))
return -ENODEV;
type = irq_type_convert((unsigned int)arg);
#if 0 //niening_test
ret = irq_set_irq_type(info->virq, type);
#else
ret = irq_set_irq_type(info->virq, (type | IRQF_ONESHOT));
#endif
if (ret)
return ret;
info->type = type;
pr_info("%s:set_type(%d) virq(%d) type(%d)\n", __func__, info->line, info->virq, info->type);
break;
case SC_IRQ_SET_WAKE:
if(!line_used(info->line))
return -ENODEV;
en = (unsigned int)arg;
#if 0 //niening_test
ret = irq_set_irq_wake(info->virq, en);
if (ret)
return ret;
#else
if(en)
enable_irq_wake(info->virq);
else
disable_irq_wake(info->virq);
#endif
info->wake = en;
pr_info("%s:set_wake(%d) virq(%d) wake(%d)\n", __func__, info->line, info->virq, info->wake);
break;
case SC_IRQ_GET_WAKE:
if(!line_used(info->line))
return -ENODEV;
error = put_user(info->wake, (unsigned int __user *)arg);
pr_info("%s:get_wake(%d) virq(%d) wake(%d)\n", __func__, info->line, info->virq, info->wake);
break;
case SC_IRQ_GET_STATUS:
if(!line_used(info->line))
return -ENODEV;
mbtk_irq_wait(info->line);
spin_lock_irqsave(&irq_ctx.lock, flags);
error = put_user(irq_ctx.pending, (unsigned int __user *)arg);
spin_unlock_irqrestore(&irq_ctx.lock, flags);
pr_debug("%s:get_status(%d) virq(%d) wake(%d) pending(0x%x)\n",
__func__, info->line, info->virq, info->wake, irq_ctx.pending);
break;
case SC_IRQ_CLEAR_STATUS:
if(!line_used(info->line))
return -ENODEV;
spin_lock_irqsave(&irq_ctx.lock, flags);
irq_ctx.pending &= ~(1 << info->line);
spin_unlock_irqrestore(&irq_ctx.lock, flags);
pr_info("%s:clear_status(%d)\n", __func__, info->line);
break;
default:
error = -ENOTTY;
break;
}
return error;
}
#ifdef CONFIG_COMPAT
static long
mbtk_irq_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
if (_IOC_TYPE(cmd) != SC_IRQ_IOC_MAGIC)
return -ENOTTY;
if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
cmd &= ~IOCSIZE_MASK;
cmd |= sizeof(char *) << IOCSIZE_SHIFT;
}
return mbtk_irq_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#endif /* CONFIG_COMPAT */
static const struct file_operations mbtk_plat_irq_fops = {
.open = mbtk_irq_open,
.release = mbtk_irq_release,
.llseek = no_llseek,
.unlocked_ioctl = mbtk_irq_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = mbtk_irq_compat_ioctl,
#endif
};
static struct miscdevice mbtk_irq_device[MBTK_LIBIRQ_MAX] = {0};
static int mbtk_plat_irq_device_init(struct platform_device *pdev)
{
int i;
int ret = 0;
char name[16];
struct miscdevice *misc_dev = NULL;
struct device_node *np;
g_MbtkPlatIrq_dev.dev = &pdev->dev;
np = of_find_compatible_node(NULL, NULL, "mbtk,plat-irq");
if (NULL == np) {
pr_err("Can't find interrupt-controller \n");
return -ENODEV;
}
irq_ctx.np = np;
for(i= 0; i < MAX_GPIO_NUM; i++)
{
memset(name, 0, sizeof(name));
sprintf(name, "%s%d", "gpio_irq", i);
pr_err("%s. parse %s \n", __func__, name);
g_MbtkPlatIrq_dev.gpio_desc[i] = of_get_named_gpio(np, name, 0);
g_MbtkPlatIrq_dev.release_func_callback[i] = FALSE;
if (unlikely(g_MbtkPlatIrq_dev.gpio_desc[i] < 0))
{
pr_err("%s. parse %s failed\n", __func__, name);
}
else
{
pr_err("%s. %s=%d g_MbtkPlatIrq_dev.release_func_callback[i] =%d\n", __func__, name, g_MbtkPlatIrq_dev.gpio_desc[i], g_MbtkPlatIrq_dev.release_func_callback[i]);
}
ret = gpio_request(g_MbtkPlatIrq_dev.gpio_desc[i], name);
if(ret < 0)
{
pr_err("%s. gpio_request for =%d failed\n", __func__,g_MbtkPlatIrq_dev.gpio_desc[i]);
return ret;
}
gpio_direction_input(g_MbtkPlatIrq_dev.gpio_desc[i]);
}
/*
irq_ctx.pctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(irq_ctx.pctrl)) {
dev_warn(&pdev->dev, "Failed to get sc_irq pins");
printk("--->%s/L%d\n", __FUNCTION__, __LINE__);
irq_ctx.pctrl = NULL;
return -ENODEV;
}
*/
for (i=0; i<MBTK_LIBIRQ_MAX; i++) {
misc_dev = &mbtk_irq_device[i];
misc_dev->mode = 0666,
misc_dev->minor = MBTK_IRQ_MINOR + i,
memset(name, 0, sizeof(name));
sprintf(name, "%s%d", "sc_irq", i);
misc_dev->name = name;
misc_dev->fops = &mbtk_plat_irq_fops;
strcpy(irq_ctx.info[i].name, name);
irq_ctx.info[i].line = i;
irq_ctx.info[i].hirq = irq_line_convert(i);
init_waitqueue_head(&irq_ctx.info[i].wait);
while ((ret = misc_register(misc_dev)) < 0) {
if (ret != -EINTR)
break;
}
if (ret < 0) {
printk(KERN_ERR "misc_register failed with error %d\n", ret);
}
/* ret = misc_register(misc_dev);
if (ret) {
pr_err("%s:register dev(%d) failed:%d \n", __func__, i, ret);
return ret;
}*/
#if 0 //niening_Test
irq_ctx.state[i] = pinctrl_lookup_state(irq_ctx.pctrl, name);
if (IS_ERR(irq_ctx.state[i])) {
dev_err(&pdev->dev, "TEST: missing state(%s)\n", name);
return -ENODEV;
}
#endif
}
spin_lock_init(&irq_ctx.lock);
return ret;
};
static int mbtk_plat_irq_probe(struct platform_device *pdev)
{
int ret = 0;
//ret = mbtk_plat_irq_device_init();
//if (ret)
// return ret;
ret = mbtk_plat_irq_device_init(pdev);
device_init_wakeup(&pdev->dev, true);
return ret;
}
static int mbtk_plat_irq_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id mbtk_plat_irq_match[] = {
{ .compatible = "mbtk,plat-irq", },
{ }
};
static struct platform_driver zx_bsp_driver = {
.probe = mbtk_plat_irq_probe,
.remove = mbtk_plat_irq_remove,
.driver = {
.name = "mbtk_PlatIrq",
.of_match_table = mbtk_plat_irq_match,
},
};
builtin_platform_driver(zx_bsp_driver)
/*---------------------------------------------------------------*/
#if 0
static struct reset_control *reboot_rst;
static int zx_restart(struct notifier_block *this,
unsigned long mode, void *cmd)
{
if (reboot_rst) {
reset_control_assert(reboot_rst);
}
return NOTIFY_DONE;
}
static struct notifier_block zx_restart_handler = {
.notifier_call = zx_restart,
.priority = 129,
};
static int zx_reboot_probe(struct platform_device *pdev)
{
int ret;
struct device_node *np = pdev->dev.of_node;
reboot_rst = of_reset_control_get_by_index(np, 0);
if (!reboot_rst) {
dev_err(&pdev->dev, "No reset handler found!");
return -EINVAL;
}
ret = register_restart_handler(&zx_restart_handler);
if (ret)
pr_warn("cannot register restart handler, %d\n", ret);
return 0;
}
static const struct of_device_id zx_reboot_match[] = {
{ .compatible = "zte,reboot", },
{ }
};
static struct platform_driver zx_reboot_driver = {
.probe = zx_reboot_probe,
.driver = {
.name = "zx_reboot",
.of_match_table = zx_reboot_match,
},
};
builtin_platform_driver(zx_reboot_driver)
/*----------------------------------------------------------------*/
#define CONFIG_RPMSG_LOG 1
#ifdef CONFIG_RPMSG_LOG
#define RPMSG_LOG_SIZE (20*1024)
static char rpmsg_printk_buf[RPMSG_LOG_SIZE];
static u32 rpmsg_log_point = 0;
static u32 rpmsg_log_turn = 0;
static u32 rpmsg_sram_inited = 0;
//static char rpmsg_log_temp_buf[512] = {0};
static spinlock_t rpmsg_log_lock;
static void rpmsg_sram_cpy(char *s, unsigned len)
{
unsigned long flags;
spin_lock_irqsave(&rpmsg_log_lock, flags);
if(rpmsg_log_point + len + 2 >= RPMSG_LOG_SIZE) {
rpmsg_log_point = 0;
if (!rpmsg_log_turn)
rpmsg_log_turn = 1;
}
memcpy(rpmsg_printk_buf+rpmsg_log_point, s, len);
rpmsg_log_point += len;
rpmsg_printk_buf[rpmsg_log_point]=0;
spin_unlock_irqrestore(&rpmsg_log_lock, flags);
}
#endif
static ssize_t rpmsg_log_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
#ifdef CONFIG_RPMSG_LOG
unsigned long flags;
if (rpmsg_sram_inited) {
spin_lock_irqsave(&rpmsg_log_lock, flags);
if (!rpmsg_log_turn) {
s += sprintf(s, "%s", rpmsg_printk_buf);
}
else {
s += sprintf(s, "%s", rpmsg_printk_buf+rpmsg_log_point+2);
s += sprintf(s, "%s", rpmsg_printk_buf);
}
spin_unlock_irqrestore(&rpmsg_log_lock, flags);
}
#endif
return (s - buf);
}
/**
* usage: like printk(...)
*/
void rpmsg_printk(const char *fmt, ...)
{
#ifdef CONFIG_RPMSG_LOG
va_list args;
unsigned long long t;
unsigned long nanosec_rem;
int tlen, len;
char rpmsg_log_temp_buf[512] = {0};
if(!rpmsg_sram_inited)
return;
va_start(args, fmt);
/* add time stamp */
t = cpu_clock(smp_processor_id());
nanosec_rem = do_div(t, 1000000000);
tlen = sprintf(rpmsg_log_temp_buf, ">%5lu.%06lu< ",
(unsigned long) t, nanosec_rem / 1000);
len = vsprintf(rpmsg_log_temp_buf+tlen, fmt, args);
len += tlen;
rpmsg_sram_cpy(rpmsg_log_temp_buf, len);
va_end(args);
#endif
}
void rpmsg_sram_init(void)
{
#ifdef CONFIG_RPMSG_LOG
pr_info("[RPMSG] LOG_INIT \n");
memset(rpmsg_printk_buf, 0, RPMSG_LOG_SIZE);
rpmsg_log_point = 0;
spin_lock_init(&rpmsg_log_lock);
rpmsg_sram_inited = 1;
#endif
}
#endif