405 lines
11 KiB
C
405 lines
11 KiB
C
/*******************************************************************************
|
|
*
|
|
* This file is licensed under the terms of the GNU General Public License
|
|
* version 2. This program is licensed "as is" without any warranty of any
|
|
* kind, whether express or implied.
|
|
*
|
|
* Copyright (c) 2017 Cadence Design Systems, Inc.
|
|
* Copyright 2018 NXP
|
|
*
|
|
************************************************************/
|
|
/************************************************************
|
|
* fsl_dsp_proxy.h
|
|
*
|
|
* Proxy commmand/response messages
|
|
************************************************************/
|
|
|
|
#ifndef __FSL_DSP_PROXY_H
|
|
#define __FSL_DSP_PROXY_H
|
|
|
|
#include <linux/wait.h>
|
|
#include <linux/device.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/platform_data/dma-imx.h>
|
|
#include <linux/mx8_mu.h>
|
|
#include <linux/interrupt.h>
|
|
|
|
#define XF_CFG_MESSAGE_POOL_SIZE 256
|
|
|
|
/*******************************************************************************
|
|
* Local proxy data
|
|
******************************************************************************/
|
|
|
|
/* ...execution message */
|
|
struct xf_message {
|
|
/* ...pointer to next message in a list */
|
|
struct xf_message *next;
|
|
|
|
/* ...session-id */
|
|
u32 id;
|
|
|
|
/* ...operation code */
|
|
u32 opcode;
|
|
|
|
/* ...length of data buffer */
|
|
u32 length;
|
|
|
|
/* ...translated data pointer */
|
|
void *buffer;
|
|
|
|
/* ...return message status */
|
|
u32 ret;
|
|
};
|
|
|
|
/* ...message queue */
|
|
struct xf_msg_queue {
|
|
/* ...pointer to list head */
|
|
struct xf_message *head;
|
|
|
|
/* ...pointer to list tail */
|
|
struct xf_message *tail;
|
|
};
|
|
|
|
struct xf_proxy_message {
|
|
/* ...session ID */
|
|
u32 session_id;
|
|
|
|
/* ...proxy API command/response code */
|
|
u32 opcode;
|
|
|
|
/* ...length of attached buffer */
|
|
u32 length;
|
|
|
|
/* ...physical address of message buffer */
|
|
u32 address;
|
|
|
|
/* ...return message status */
|
|
u32 ret;
|
|
};
|
|
/**********************************************************************/
|
|
|
|
enum icm_action_t {
|
|
ICM_CORE_READY = 1,
|
|
ICM_CORE_INIT,
|
|
ICM_CORE_EXIT,
|
|
};
|
|
|
|
/* ...adjust IPC client of message going from user-space */
|
|
#define XF_MSG_AP_FROM_USER(id, client) (((id) & ~(0xF << 2)) | (client << 2))
|
|
|
|
/* ...message id contains source and destination ports specification */
|
|
#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16))
|
|
|
|
/* ...wipe out IPC client from message going to user-space */
|
|
#define XF_MSG_AP_TO_USER(id) ((id) & ~(0xF << 18))
|
|
#define __XF_AP_PROXY(core) ((core) | 0x8000)
|
|
#define __XF_DSP_PROXY(core) ((core) | 0x8000)
|
|
|
|
/* ...message id contains source and destination ports specification */
|
|
#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16))
|
|
#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F)
|
|
#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F)
|
|
|
|
/* ...special treatment of AP-proxy destination field */
|
|
#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF)
|
|
#define __XF_AP_PROXY(core) ((core) | 0x8000)
|
|
#define __XF_DSP_PROXY(core) ((core) | 0x8000)
|
|
|
|
/* ...opcode composition with command/response data tags */
|
|
#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F))
|
|
|
|
/* ...shared buffer allocation */
|
|
#define XF_ALLOC __XF_OPCODE(0, 0, 4)
|
|
|
|
/* ...shared buffer freeing */
|
|
#define XF_FREE __XF_OPCODE(0, 0, 5)
|
|
|
|
/* ...resume component operation */
|
|
#define XF_RESUME __XF_OPCODE(0, 0, 14)
|
|
|
|
/* ...resume component operation */
|
|
#define XF_SUSPEND __XF_OPCODE(0, 0, 15)
|
|
|
|
|
|
/*******************************************************************************
|
|
* Ring buffer support
|
|
******************************************************************************/
|
|
/* ...cache-line size on DSP */
|
|
#define XF_PROXY_ALIGNMENT 64
|
|
|
|
/* ...total length of shared memory queue (for commands and responses) */
|
|
#define XF_PROXY_MESSAGE_QUEUE_LENGTH (1 << 6)
|
|
|
|
/* ...index mask */
|
|
#define XF_PROXY_MESSAGE_QUEUE_MASK 0x3F
|
|
|
|
/* ...ring-buffer index */
|
|
#define __XF_QUEUE_IDX(idx, counter) \
|
|
(((idx) & XF_PROXY_MESSAGE_QUEUE_MASK) | ((counter) << 16))
|
|
|
|
/* ...retrieve ring-buffer index */
|
|
#define XF_QUEUE_IDX(idx) \
|
|
((idx) & XF_PROXY_MESSAGE_QUEUE_MASK)
|
|
|
|
/* ...increment ring-buffer index */
|
|
#define XF_QUEUE_ADVANCE_IDX(idx) \
|
|
(((idx) + 0x10001) & (0xFFFF0000 | XF_PROXY_MESSAGE_QUEUE_MASK))
|
|
|
|
/* ...test if ring buffer is empty */
|
|
#define XF_QUEUE_EMPTY(read, write) \
|
|
((read) == (write))
|
|
|
|
/* ...test if ring buffer is full */
|
|
#define XF_QUEUE_FULL(read, write) \
|
|
((write) == (read) + (XF_PROXY_MESSAGE_QUEUE_LENGTH << 16))
|
|
|
|
/* ...basic cache operations */
|
|
#define XF_PROXY_INVALIDATE(addr, len) { }
|
|
|
|
#define XF_PROXY_FLUSH(addr, len) { }
|
|
|
|
/* ...data managed by host CPU (remote) - in case of shunt it is a IPC layer */
|
|
struct xf_proxy_host_data {
|
|
/* ...command queue */
|
|
struct xf_proxy_message command[XF_PROXY_MESSAGE_QUEUE_LENGTH];
|
|
|
|
/* ...writing index into command queue */
|
|
u32 cmd_write_idx;
|
|
|
|
/* ...reading index for response queue */
|
|
u32 rsp_read_idx;
|
|
|
|
/* ...indicate command queue is valid or not */
|
|
u32 cmd_invalid;
|
|
};
|
|
|
|
/* ...data managed by DSP (local) */
|
|
struct xf_proxy_dsp_data {
|
|
/* ...response queue */
|
|
struct xf_proxy_message response[XF_PROXY_MESSAGE_QUEUE_LENGTH];
|
|
|
|
/* ...writing index into response queue */
|
|
u32 rsp_write_idx;
|
|
|
|
/* ...reading index for command queue */
|
|
u32 cmd_read_idx;
|
|
|
|
/* ...indicate response queue is valid or not */
|
|
u32 rsp_invalid;
|
|
};
|
|
|
|
/* ...shared memory data */
|
|
struct xf_shmem_data {
|
|
/* ...ingoing data (maintained by DSP (local side)) */
|
|
struct xf_proxy_host_data local;
|
|
|
|
/* ...outgoing data (maintained by host CPU (remote side)) */
|
|
struct xf_proxy_dsp_data remote;
|
|
|
|
};
|
|
|
|
/* ...shared memory data accessor */
|
|
#define XF_SHMEM_DATA(proxy) \
|
|
((proxy)->ipc.shmem)
|
|
|
|
/* ...atomic reading */
|
|
#define __XF_PROXY_READ_ATOMIC(var) \
|
|
({ XF_PROXY_INVALIDATE(&(var), sizeof(var)); \
|
|
*(u32 *)&(var); })
|
|
|
|
/* ...atomic writing */
|
|
#define __XF_PROXY_WRITE_ATOMIC(var, value) \
|
|
({*(u32 *)&(var) = (value); \
|
|
XF_PROXY_FLUSH(&(var), sizeof(var)); \
|
|
(value); })
|
|
|
|
/* ...accessors */
|
|
#define XF_PROXY_READ(proxy, field) \
|
|
__XF_PROXY_READ_##field(XF_SHMEM_DATA(proxy))
|
|
|
|
#define XF_PROXY_WRITE(proxy, field, v) \
|
|
__XF_PROXY_WRITE_##field(XF_SHMEM_DATA(proxy), (v))
|
|
|
|
/* ...individual fields reading */
|
|
#define __XF_PROXY_READ_cmd_write_idx(shmem) \
|
|
__XF_PROXY_READ_ATOMIC(shmem->local.cmd_write_idx)
|
|
|
|
#define __XF_PROXY_READ_cmd_read_idx(shmem) \
|
|
shmem->remote.cmd_read_idx
|
|
|
|
#define __XF_PROXY_READ_cmd_invalid(shmem) \
|
|
__XF_PROXY_READ_ATOMIC(shmem->local.cmd_invalid)
|
|
|
|
#define __XF_PROXY_READ_rsp_write_idx(shmem) \
|
|
__XF_PROXY_READ_ATOMIC(shmem->remote.rsp_write_idx)
|
|
|
|
#define __XF_PROXY_READ_rsp_read_idx(shmem) \
|
|
shmem->local.rsp_read_idx
|
|
|
|
#define __XF_PROXY_READ_rsp_invalid(shmem) \
|
|
__XF_PROXY_READ_ATOMIC(shmem->remote.rsp_invalid)
|
|
|
|
/* ...individual fields writings */
|
|
#define __XF_PROXY_WRITE_cmd_write_idx(shmem, v) \
|
|
__XF_PROXY_WRITE_ATOMIC(shmem->local.cmd_write_idx, v)
|
|
|
|
#define __XF_PROXY_WRITE_cmd_read_idx(shmem, v) \
|
|
__XF_PROXY_WRITE_ATOMIC(shmem->remote.cmd_read_idx, v)
|
|
|
|
#define __XF_PROXY_WRITE_cmd_invalid(shmem, v) \
|
|
__XF_PROXY_WRITE_ATOMIC(shmem->local.cmd_invalid, v)
|
|
|
|
#define __XF_PROXY_WRITE_rsp_read_idx(shmem, v) \
|
|
__XF_PROXY_WRITE_ATOMIC(shmem->local.rsp_read_idx, v)
|
|
|
|
#define __XF_PROXY_WRITE_rsp_write_idx(shmem, v) \
|
|
__XF_PROXY_WRITE_ATOMIC(shmem->remote.rsp_write_idx, v)
|
|
|
|
#define __XF_PROXY_WRITE_rsp_invalid(shmem, v) \
|
|
__XF_PROXY_WRITE_ATOMIC(shmem->remote.rsp_invalid, v)
|
|
|
|
/* ...command buffer accessor */
|
|
#define XF_PROXY_COMMAND(proxy, idx) \
|
|
(&XF_SHMEM_DATA(proxy)->local.command[(idx)])
|
|
|
|
/* ...response buffer accessor */
|
|
#define XF_PROXY_RESPONSE(proxy, idx) \
|
|
(&XF_SHMEM_DATA(proxy)->remote.response[(idx)])
|
|
|
|
/*******************************************************************************
|
|
* Local proxy data
|
|
******************************************************************************/
|
|
|
|
struct xf_proxy_ipc_data {
|
|
/* ...shared memory data pointer */
|
|
struct xf_shmem_data __iomem *shmem;
|
|
|
|
/* ...core identifier */
|
|
u32 core;
|
|
|
|
/* ...IPC registers memory */
|
|
void __iomem *regs;
|
|
};
|
|
|
|
/* ...proxy data */
|
|
struct xf_proxy {
|
|
/* ...IPC layer data */
|
|
struct xf_proxy_ipc_data ipc;
|
|
|
|
/* ...shared memory status change processing item */
|
|
struct work_struct work;
|
|
|
|
struct completion cmd_complete;
|
|
int is_ready;
|
|
|
|
/* ...internal lock */
|
|
spinlock_t lock;
|
|
|
|
/* ...busy queue (for clients waiting ON NOTIFIcation) */
|
|
wait_queue_head_t busy;
|
|
|
|
/* ...waiting queue for synchronous proxy operations */
|
|
wait_queue_head_t wait;
|
|
|
|
/* ...submitted commands queue */
|
|
struct xf_msg_queue command;
|
|
|
|
/* ...pending responses queue */
|
|
struct xf_msg_queue response;
|
|
|
|
/* ...global message pool */
|
|
struct xf_message pool[XF_CFG_MESSAGE_POOL_SIZE];
|
|
|
|
/* ...pointer to first free message in the pool */
|
|
struct xf_message *free;
|
|
};
|
|
|
|
union icm_header_t {
|
|
struct {
|
|
u32 msg:6;
|
|
u32 sub_msg:6; // sub_msg will have ICM_MSG
|
|
u32 rsvd:3; /* reserved */
|
|
u32 intr:1; /* intr = 1 when sending msg. */
|
|
u32 size:15; /* =size in bytes (excluding header) */
|
|
u32 ack:1; /* response message when ack=1 */
|
|
};
|
|
u32 allbits;
|
|
};
|
|
|
|
struct dsp_ext_msg {
|
|
u32 phys;
|
|
u32 size;
|
|
};
|
|
|
|
struct dsp_mem_msg {
|
|
u32 ext_msg_phys;
|
|
u32 ext_msg_size;
|
|
u32 scratch_phys;
|
|
u32 scratch_size;
|
|
u32 dsp_config_phys;
|
|
u32 dsp_config_size;
|
|
};
|
|
|
|
static inline void xf_lock_init(spinlock_t *lock)
|
|
{
|
|
spin_lock_init(lock);
|
|
}
|
|
|
|
static inline void xf_lock(spinlock_t *lock)
|
|
{
|
|
spin_lock(lock);
|
|
}
|
|
|
|
static inline void xf_unlock(spinlock_t *lock)
|
|
{
|
|
spin_unlock(lock);
|
|
}
|
|
|
|
/* ...init proxy */
|
|
int xf_proxy_init(struct xf_proxy *proxy);
|
|
|
|
/* ...send message to proxy */
|
|
int xf_cmd_send(struct xf_proxy *proxy,
|
|
u32 id,
|
|
u32 opcode,
|
|
void *buffer,
|
|
u32 length);
|
|
|
|
/* ...get message from proxy */
|
|
struct xf_message *xf_cmd_recv(struct xf_proxy *proxy,
|
|
wait_queue_head_t *wq,
|
|
struct xf_msg_queue *queue,
|
|
int wait);
|
|
|
|
/* ...mu interrupt handle */
|
|
irqreturn_t fsl_dsp_mu_isr(int irq, void *dev_id);
|
|
|
|
/* ...initialize client pending message queue */
|
|
void xf_msg_queue_init(struct xf_msg_queue *queue);
|
|
|
|
/* ...return current queue state */
|
|
struct xf_message *xf_msg_queue_head(struct xf_msg_queue *queue);
|
|
|
|
/* ...return the message back to a pool */
|
|
void xf_msg_free(struct xf_proxy *proxy, struct xf_message *m);
|
|
|
|
/* ...release all pending messages */
|
|
void xf_msg_free_all(struct xf_proxy *proxy, struct xf_msg_queue *queue);
|
|
|
|
/* ...wait mu interrupt */
|
|
long icm_ack_wait(struct xf_proxy *proxy, u32 msg);
|
|
|
|
/* ...shared memory translation - kernel virtual address to shared address */
|
|
u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b);
|
|
|
|
/* ...shared memory translation - shared address to kernel virtual address */
|
|
void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address);
|
|
|
|
int xf_cmd_send_suspend(struct xf_proxy *proxy);
|
|
int xf_cmd_send_resume(struct xf_proxy *proxy);
|
|
|
|
#endif
|