542 lines
14 KiB
C
542 lines
14 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2016 MediaTek Inc.
|
|
*/
|
|
#include <linux/cdev.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/bitops.h>
|
|
#include "mt-plat/mtk_ccci_common.h"
|
|
#include "ccci_config.h"
|
|
#include "ccci_common_config.h"
|
|
#include "ccci_core.h"
|
|
#include "ccci_bm.h"
|
|
#include "port_ipc.h"
|
|
#include "port_ipc_internal.h"
|
|
#include "ccci_ipc_msg_id.h"
|
|
#include "ccci_modem.h"
|
|
#include "ccci_fsm.h"
|
|
#include "port_t.h"
|
|
static struct ipc_task_id_map ipc_msgsvc_maptbl[] = {
|
|
|
|
#define __IPC_ID_TABLE
|
|
#include "ccci_ipc_task_ID.h"
|
|
#undef __IPC_ID_TABLE
|
|
};
|
|
|
|
#ifdef CONFIG_MTK_CONN_MD
|
|
/* this file also include ccci_ipc_task_ID.h,
|
|
* must include it after ipc_msgsvc_maptbl
|
|
*/
|
|
#include "conn_md_exp.h"
|
|
#endif
|
|
|
|
#define MAX_QUEUE_LENGTH 32
|
|
|
|
#define local_AP_id_2_unify_id(id) local_xx_id_2_unify_id(id, 1)/* not using */
|
|
#define local_MD_id_2_unify_id(id) local_xx_id_2_unify_id(id, 0)
|
|
#define unify_AP_id_2_local_id(id) unify_xx_id_2_local_id(id, 1)
|
|
#define unify_MD_id_2_local_id(id) unify_xx_id_2_local_id(id, 0)/* not using */
|
|
|
|
static struct ipc_task_id_map *local_xx_id_2_unify_id(u32 local_id, int AP)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipc_msgsvc_maptbl); i++) {
|
|
if (ipc_msgsvc_maptbl[i].task_id == local_id &&
|
|
(AP ? (ipc_msgsvc_maptbl[i].extq_id & AP_UNIFY_ID_FLAG) :
|
|
!(ipc_msgsvc_maptbl[i].extq_id & AP_UNIFY_ID_FLAG)))
|
|
return ipc_msgsvc_maptbl + i;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct ipc_task_id_map *unify_xx_id_2_local_id(u32 unify_id, int AP)
|
|
{
|
|
int i;
|
|
|
|
if (!(AP ? (unify_id & AP_UNIFY_ID_FLAG) :
|
|
!(unify_id & AP_UNIFY_ID_FLAG)))
|
|
return NULL;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipc_msgsvc_maptbl); i++) {
|
|
if (ipc_msgsvc_maptbl[i].extq_id == unify_id)
|
|
return ipc_msgsvc_maptbl + i;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int port_ipc_recv_match(struct port_t *port, struct sk_buff *skb)
|
|
{
|
|
struct ccci_header *ccci_h = (struct ccci_header *)skb->data;
|
|
struct ccci_ipc_ctrl *ipc_ctrl =
|
|
(struct ccci_ipc_ctrl *)port->private_data;
|
|
struct ipc_task_id_map *id_map = NULL;
|
|
|
|
if (port->rx_ch != CCCI_IPC_RX)
|
|
return 1;
|
|
|
|
CCCI_DEBUG_LOG(port->md_id, IPC,
|
|
"task_id matching: (%x/%x)\n",
|
|
ipc_ctrl->task_id, ccci_h->reserved);
|
|
id_map = unify_AP_id_2_local_id(ccci_h->reserved);
|
|
if (id_map == NULL)
|
|
return 0;
|
|
if (id_map->task_id == ipc_ctrl->task_id)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
#if MD_GENERATION <= (6295)
|
|
static int send_new_time_to_md(int md_id, int tz);
|
|
#endif
|
|
int current_time_zone;
|
|
|
|
long port_ipc_ioctl(struct file *file, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
long ret = 0;
|
|
struct port_t *port = file->private_data;
|
|
struct sk_buff *skb = NULL;
|
|
unsigned long flags;
|
|
struct ccci_ipc_ctrl *ipc_ctrl =
|
|
(struct ccci_ipc_ctrl *)port->private_data;
|
|
|
|
switch (cmd) {
|
|
case CCCI_IPC_RESET_RECV:
|
|
/* purge the Rx list */
|
|
spin_lock_irqsave(&port->rx_skb_list.lock, flags);
|
|
while ((skb = __skb_dequeue(&port->rx_skb_list)) != NULL)
|
|
ccci_free_skb(skb);
|
|
spin_unlock_irqrestore(&port->rx_skb_list.lock, flags);
|
|
break;
|
|
|
|
case CCCI_IPC_RESET_SEND:
|
|
clear_bit(CCCI_TASK_PENDING, &ipc_ctrl->flag);
|
|
wake_up(&ipc_ctrl->tx_wq);
|
|
break;
|
|
|
|
case CCCI_IPC_WAIT_MD_READY:
|
|
if (ipc_ctrl->md_is_ready == 0) {
|
|
ret = wait_event_interruptible(ipc_ctrl->md_rdy_wq,
|
|
ipc_ctrl->md_is_ready == 1);
|
|
if (ret == -ERESTARTSYS)
|
|
ret = -EINTR;
|
|
}
|
|
break;
|
|
|
|
case CCCI_IPC_UPDATE_TIME:
|
|
CCCI_REPEAT_LOG(port->md_id, IPC,
|
|
"CCCI_IPC_UPDATE_TIME 0x%x\n", (unsigned int)arg);
|
|
current_time_zone = (int)arg;
|
|
#if MD_GENERATION <= (6295)
|
|
ret = send_new_time_to_md(port->md_id, (int)arg);
|
|
#else
|
|
ret = send_new_time_to_new_md(port->md_id, (int)arg);
|
|
#endif
|
|
break;
|
|
|
|
case CCCI_IPC_WAIT_TIME_UPDATE:
|
|
CCCI_DEBUG_LOG(port->md_id, IPC,
|
|
"CCCI_IPC_WAIT_TIME_UPDATE\n");
|
|
ret = wait_time_update_notify();
|
|
CCCI_DEBUG_LOG(port->md_id, IPC,
|
|
"CCCI_IPC_WAIT_TIME_UPDATE wakeup\n");
|
|
break;
|
|
|
|
|
|
case CCCI_IPC_UPDATE_TIMEZONE:
|
|
CCCI_REPEAT_LOG(port->md_id, IPC,
|
|
"CCCI_IPC_UPDATE_TIMEZONE keep 0x%x\n",
|
|
(unsigned int)arg);
|
|
current_time_zone = (int)arg;
|
|
break;
|
|
default:
|
|
ret = -1;
|
|
break;
|
|
};
|
|
|
|
if (ret == -1)
|
|
ret = port_dev_ioctl(file, cmd, arg);
|
|
return ret;
|
|
}
|
|
|
|
void port_ipc_md_state_notify(struct port_t *port, unsigned int state)
|
|
{
|
|
struct ccci_ipc_ctrl *ipc_ctrl =
|
|
(struct ccci_ipc_ctrl *)port->private_data;
|
|
|
|
switch (state) {
|
|
case READY:
|
|
ipc_ctrl->md_is_ready = 1;
|
|
wake_up_all(&ipc_ctrl->md_rdy_wq);
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
}
|
|
|
|
int port_ipc_write_check_id(struct port_t *port, struct sk_buff *skb)
|
|
{
|
|
struct ccci_ipc_ilm *ilm =
|
|
(struct ccci_ipc_ilm *)((char *)skb->data +
|
|
sizeof(struct ccci_header));
|
|
struct ipc_task_id_map *id_map;
|
|
|
|
id_map = local_MD_id_2_unify_id(ilm->dest_mod_id);
|
|
if (id_map == NULL) {
|
|
CCCI_ERROR_LOG(port->md_id, IPC,
|
|
"Invalid Dest MD ID (%d)\n", ilm->dest_mod_id);
|
|
return -CCCI_ERR_IPC_ID_ERROR;
|
|
}
|
|
return id_map->extq_id;
|
|
}
|
|
|
|
unsigned int port_ipc_poll(struct file *fp, struct poll_table_struct *poll)
|
|
{
|
|
struct port_t *port = fp->private_data;
|
|
struct ccci_ipc_ctrl *ipc_ctrl =
|
|
(struct ccci_ipc_ctrl *)port->private_data;
|
|
unsigned int mask = 0;
|
|
|
|
poll_wait(fp, &ipc_ctrl->tx_wq, poll);
|
|
poll_wait(fp, &port->rx_wq, poll);
|
|
if (!skb_queue_empty(&port->rx_skb_list))
|
|
mask |= POLLIN | POLLRDNORM;
|
|
if (!test_bit(CCCI_TASK_PENDING, &ipc_ctrl->flag))
|
|
mask |= POLLOUT | POLLWRNORM;
|
|
|
|
return mask;
|
|
}
|
|
|
|
static struct port_t *find_ipc_port_by_task_id(int md_id, int task_id)
|
|
{
|
|
return port_get_by_minor(md_id, task_id + CCCI_IPC_MINOR_BASE);
|
|
}
|
|
|
|
|
|
static const struct file_operations ipc_dev_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = &port_dev_open, /*use default API*/
|
|
.read = &port_dev_read, /*use default API*/
|
|
.write = &port_dev_write, /*use default API*/
|
|
.release = &port_dev_close,/*use default API*/
|
|
.unlocked_ioctl = &port_ipc_ioctl,
|
|
#ifdef CONFIG_COMPAT
|
|
.compat_ioctl = &port_dev_compat_ioctl,
|
|
#endif
|
|
.poll = &port_ipc_poll,
|
|
};
|
|
|
|
static int port_ipc_kernel_write(int md_id, struct ipc_ilm *in_ilm)
|
|
{
|
|
u32 task_id;
|
|
int count, actual_count, ret;
|
|
struct port_t *port;
|
|
struct ccci_header *ccci_h = NULL;
|
|
struct ccci_ipc_ilm *ilm = NULL;
|
|
struct sk_buff *skb = NULL;
|
|
|
|
/* src module id check */
|
|
task_id = in_ilm->src_mod_id & (~AP_UNIFY_ID_FLAG);
|
|
port = find_ipc_port_by_task_id(md_id, task_id);
|
|
if (!port) {
|
|
CCCI_ERROR_LOG(-1, IPC, "invalid task ID %x\n",
|
|
in_ilm->src_mod_id);
|
|
return -EINVAL;
|
|
}
|
|
if (in_ilm->local_para_ptr == NULL) {
|
|
CCCI_ERROR_LOG(-1, IPC,
|
|
"invalid ILM local parameter pointer %p for task %d\n",
|
|
in_ilm, task_id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
count = sizeof(struct ccci_ipc_ilm) +
|
|
in_ilm->local_para_ptr->msg_len;
|
|
if (count > CCCI_MTU) {
|
|
CCCI_ERROR_LOG(port->md_id, IPC,
|
|
"reject packet(size=%d ), lager than MTU on %s\n",
|
|
count, port->name);
|
|
return -ENOMEM;
|
|
}
|
|
CCCI_DEBUG_LOG(port->md_id, IPC, "write on %s for %d\n",
|
|
port->name, in_ilm->local_para_ptr->msg_len);
|
|
|
|
actual_count = count + sizeof(struct ccci_header);
|
|
skb = ccci_alloc_skb(actual_count, 1, 1);
|
|
if (skb) {
|
|
/* ccci header */
|
|
ccci_h = (struct ccci_header *)skb_put(skb,
|
|
sizeof(struct ccci_header));
|
|
ccci_h->data[0] = 0;
|
|
ccci_h->data[1] = actual_count;
|
|
ccci_h->channel = port->tx_ch;
|
|
ccci_h->reserved = 0;
|
|
/* copy ilm */
|
|
ilm = (struct ccci_ipc_ilm *)skb_put(skb,
|
|
sizeof(struct ccci_ipc_ilm));
|
|
ilm->src_mod_id = in_ilm->src_mod_id;
|
|
ilm->dest_mod_id = in_ilm->dest_mod_id;
|
|
ilm->sap_id = in_ilm->sap_id;
|
|
ilm->msg_id = in_ilm->msg_id;
|
|
/* to let MD treat it as != NULL */
|
|
ilm->local_para_ptr = 1;
|
|
ilm->peer_buff_ptr = 0;
|
|
/* copy data */
|
|
count = in_ilm->local_para_ptr->msg_len;
|
|
memcpy(skb_put(skb, count), in_ilm->local_para_ptr, count);
|
|
/* send packet */
|
|
ret = port_ipc_write_check_id(port, skb);
|
|
if (ret < 0)
|
|
goto err_out;
|
|
else
|
|
ccci_h->reserved = ret; /* Unity ID */
|
|
ret = port_send_skb_to_md(port, skb, 1);
|
|
if (ret)
|
|
goto err_out;
|
|
else
|
|
return actual_count - sizeof(struct ccci_header);
|
|
|
|
err_out:
|
|
ccci_free_skb(skb);
|
|
return ret;
|
|
} else {
|
|
return -EBUSY;
|
|
}
|
|
}
|
|
|
|
int ccci_ipc_send_ilm(int md_id, struct ipc_ilm *in_ilm)
|
|
{
|
|
if (md_id < 0 || md_id >= MAX_MD_NUM)
|
|
return -EINVAL;
|
|
return port_ipc_kernel_write(md_id, in_ilm);
|
|
}
|
|
|
|
#ifdef CONFIG_MTK_CONN_MD
|
|
static int ccci_ipc_send_ilm_to_md1(struct ipc_ilm *in_ilm)
|
|
{
|
|
return port_ipc_kernel_write(0, in_ilm);
|
|
}
|
|
#endif
|
|
static int port_ipc_kernel_thread(void *arg)
|
|
{
|
|
struct port_t *port = arg;
|
|
struct sk_buff *skb = NULL;
|
|
struct ccci_header *ccci_h = NULL;
|
|
unsigned long flags;
|
|
int ret = 0;
|
|
struct ccci_ipc_ilm *ilm = NULL;
|
|
struct ipc_ilm out_ilm;
|
|
struct ipc_task_id_map *id_map = NULL;
|
|
|
|
CCCI_DEBUG_LOG(port->md_id, IPC,
|
|
"port %s's thread running\n", port->name);
|
|
|
|
while (1) {
|
|
retry:
|
|
if (skb_queue_empty(&port->rx_skb_list)) {
|
|
ret = wait_event_interruptible(port->rx_wq,
|
|
!skb_queue_empty(&port->rx_skb_list));
|
|
if (ret == -ERESTARTSYS)
|
|
continue; /* FIXME */
|
|
}
|
|
if (kthread_should_stop())
|
|
break;
|
|
CCCI_DEBUG_LOG(port->md_id, IPC,
|
|
"read on %s\n", port->name);
|
|
/* 1. dequeue */
|
|
spin_lock_irqsave(&port->rx_skb_list.lock, flags);
|
|
skb = __skb_dequeue(&port->rx_skb_list);
|
|
if (port->rx_skb_list.qlen == 0)
|
|
port_ask_more_req_to_md(port);
|
|
spin_unlock_irqrestore(&port->rx_skb_list.lock, flags);
|
|
if (skb == NULL)
|
|
goto retry;
|
|
/* 2. process the request */
|
|
/* ccci header */
|
|
ccci_h = (struct ccci_header *)skb->data;
|
|
skb_pull(skb, sizeof(struct ccci_header));
|
|
ilm = (struct ccci_ipc_ilm *)(skb->data);
|
|
/* copy ilm */
|
|
out_ilm.src_mod_id = ilm->src_mod_id;
|
|
out_ilm.dest_mod_id = ccci_h->reserved;
|
|
out_ilm.sap_id = ilm->sap_id;
|
|
out_ilm.msg_id = ilm->msg_id;
|
|
/* data pointer */
|
|
skb_pull(skb, sizeof(struct ccci_ipc_ilm));
|
|
out_ilm.local_para_ptr = (struct local_para *)(skb->data);
|
|
out_ilm.peer_buff_ptr = 0;
|
|
id_map = unify_AP_id_2_local_id(ccci_h->reserved);
|
|
if (id_map != NULL) {
|
|
switch (id_map->task_id) {
|
|
case AP_IPC_WMT:
|
|
#ifdef CONFIG_MTK_CONN_MD
|
|
#ifndef CCCI_PLATFORM_MT6877
|
|
mtk_conn_md_bridge_send_msg(&out_ilm);
|
|
#endif
|
|
#endif
|
|
break;
|
|
case AP_IPC_PKTTRC:
|
|
#if defined(CONFIG_MTK_MD_DIRECT_TETHERING_SUPPORT)
|
|
pkt_track_md_msg_hdlr(&out_ilm);
|
|
#endif
|
|
break;
|
|
case AP_IPC_USB:
|
|
#if defined(CONFIG_MTK_MD_DIRECT_TETHERING_SUPPORT) \
|
|
|| defined(CONFIG_MTK_MD_DIRECT_LOGGING_SUPPORT)
|
|
rndis_md_msg_hdlr(&out_ilm);
|
|
#endif
|
|
break;
|
|
default:
|
|
CCCI_ERROR_LOG(port->md_id, IPC,
|
|
"recv unknown task ID %d\n",
|
|
id_map->task_id);
|
|
break;
|
|
}
|
|
} else {
|
|
CCCI_ERROR_LOG(port->md_id, IPC,
|
|
"recv unknown module ID %d\n",
|
|
ccci_h->reserved);
|
|
}
|
|
CCCI_DEBUG_LOG(port->md_id, IPC,
|
|
"read done on %s l=%d\n", port->name,
|
|
out_ilm.local_para_ptr->msg_len);
|
|
ccci_free_skb(skb);
|
|
}
|
|
return 0;
|
|
}
|
|
int port_ipc_init(struct port_t *port)
|
|
{
|
|
struct cdev *dev = NULL;
|
|
int ret = 0;
|
|
struct ccci_ipc_ctrl *ipc_ctrl =
|
|
kmalloc(sizeof(struct ccci_ipc_ctrl), GFP_KERNEL);
|
|
|
|
if (unlikely(!ipc_ctrl)) {
|
|
CCCI_ERROR_LOG(port->md_id, IPC, "alloc ipc_ctrl fail!!\n");
|
|
return -1;
|
|
}
|
|
|
|
port->rx_length_th = MAX_QUEUE_LENGTH;
|
|
port->private_data = ipc_ctrl;
|
|
/*
|
|
* tricky part, we use pre-defined minor number as task ID,
|
|
* then we modify it into the right number.
|
|
*/
|
|
ipc_ctrl->task_id = port->minor;
|
|
port->minor += CCCI_IPC_MINOR_BASE;
|
|
init_waitqueue_head(&ipc_ctrl->tx_wq);
|
|
init_waitqueue_head(&ipc_ctrl->md_rdy_wq);
|
|
ipc_ctrl->md_is_ready = 0;
|
|
ipc_ctrl->port = port;
|
|
port->skb_from_pool = 1;
|
|
if (port->flags & PORT_F_WITH_CHAR_NODE) {
|
|
dev = kmalloc(sizeof(struct cdev), GFP_KERNEL);
|
|
if (unlikely(!dev)) {
|
|
CCCI_ERROR_LOG(port->md_id, IPC,
|
|
"alloc ipc char dev fail!!\n");
|
|
kfree(ipc_ctrl);
|
|
return -1;
|
|
}
|
|
cdev_init(dev, &ipc_dev_fops);
|
|
dev->owner = THIS_MODULE;
|
|
ret = cdev_add(dev, MKDEV(port->major,
|
|
port->minor_base + port->minor), 1);
|
|
ret = ccci_register_dev_node(port->name, port->major,
|
|
port->minor_base + port->minor);
|
|
port->interception = 0;
|
|
port->flags |= PORT_F_ADJUST_HEADER;
|
|
} else {
|
|
kthread_run(port_ipc_kernel_thread, port, "%s", port->name);
|
|
if (ipc_ctrl->task_id == AP_IPC_WMT) {
|
|
#ifdef CONFIG_MTK_CONN_MD
|
|
struct conn_md_bridge_ops ccci_ipc_conn_ops = {
|
|
.rx_cb = ccci_ipc_send_ilm_to_md1};
|
|
|
|
mtk_conn_md_bridge_reg(MD_MOD_EL1, &ccci_ipc_conn_ops);
|
|
mtk_conn_md_bridge_reg(MD_MOD_GMMGR,
|
|
&ccci_ipc_conn_ops);
|
|
#endif
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct port_ops ipc_port_ops = {
|
|
.init = &port_ipc_init,
|
|
.recv_skb = &port_recv_skb,
|
|
.recv_match = &port_ipc_recv_match,
|
|
.md_state_notify = &port_ipc_md_state_notify,
|
|
};
|
|
|
|
#if MD_GENERATION <= (6295)
|
|
int send_new_time_to_md(int md_id, int tz)
|
|
{
|
|
struct ipc_ilm in_ilm;
|
|
char local_param[sizeof(struct local_para) + 16];
|
|
unsigned int timeinfo[4];
|
|
struct timeval tv = { 0 };
|
|
|
|
do_gettimeofday(&tv);
|
|
|
|
timeinfo[0] = tv.tv_sec;
|
|
timeinfo[1] = sizeof(tv.tv_sec) > 4 ? tv.tv_sec >> 32 : 0;
|
|
timeinfo[2] = tz;
|
|
timeinfo[3] = sys_tz.tz_dsttime;
|
|
|
|
in_ilm.src_mod_id = AP_MOD_CCCIIPC;
|
|
in_ilm.dest_mod_id = MD_MOD_CCCIIPC;
|
|
in_ilm.sap_id = 0;
|
|
in_ilm.msg_id = IPC_MSG_ID_CCCIIPC_CLIB_TIME_REQ;
|
|
in_ilm.local_para_ptr = (struct local_para *)&local_param[0];
|
|
/* msg_len not only contain local_para_ptr->data,
|
|
* but also contain 4 Bytes header itself
|
|
*/
|
|
in_ilm.local_para_ptr->msg_len = 20;
|
|
memcpy(in_ilm.local_para_ptr->data, timeinfo, 16);
|
|
|
|
CCCI_DEBUG_LOG(md_id, IPC,
|
|
"Update time(R): [sec=0x%lx][timezone=0x%08x][des=0x%08x]\n",
|
|
tv.tv_sec, sys_tz.tz_minuteswest, sys_tz.tz_dsttime);
|
|
CCCI_DEBUG_LOG(md_id, IPC,
|
|
"Update time(A): [L:0x%08x][H:0x%08x][0x%08x][0x%08x]\n",
|
|
timeinfo[0], timeinfo[1], timeinfo[2], timeinfo[3]);
|
|
if (port_ipc_kernel_write(md_id, &in_ilm) < 0) {
|
|
CCCI_NORMAL_LOG(md_id, IPC, "Update fail\n");
|
|
return -1;
|
|
}
|
|
CCCI_REPEAT_LOG(md_id, IPC, "Update success\n");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int ccci_get_emi_info(int md_id, struct ccci_emi_info *emi_info)
|
|
{
|
|
struct ccci_mem_layout *mem_layout = NULL;
|
|
|
|
if (md_id < 0 || md_id > MAX_MD_NUM || !emi_info)
|
|
return -EINVAL;
|
|
mem_layout = ccci_md_get_mem(md_id);
|
|
if (!mem_layout) {
|
|
CCCI_ERROR_LOG(md_id, IPC, "%s:ccci_md_get_mem fail\n",
|
|
__func__);
|
|
return -1;
|
|
}
|
|
|
|
emi_info->ap_domain_id = 0;
|
|
emi_info->md_domain_id = 1;
|
|
emi_info->ap_view_bank0_base = mem_layout->md_bank0.base_ap_view_phy;
|
|
emi_info->bank0_size = mem_layout->md_bank0.size;
|
|
emi_info->ap_view_bank4_base =
|
|
mem_layout->md_bank4_noncacheable_total.base_md_view_phy;
|
|
emi_info->bank4_size = mem_layout->md_bank4_noncacheable_total.size;
|
|
return 0;
|
|
}
|
|
|