blob: bc9ccf37bc8f6fa3b0280a243096a5a68435cb39 [file] [log] [blame]
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* DSP proxy header - commands/responses from DSP driver to DSP ramework
*
* Copyright 2018 NXP
* Copyright (c) 2017 Cadence Design Systems, Inc.
*/
#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>
#include "fsl_dsp_pool.h"
#define XF_CFG_MESSAGE_POOL_SIZE 256
struct xf_client;
/*******************************************************************************
* Local proxy data
******************************************************************************/
struct xf_message;
struct xf_handle;
typedef void (*xf_response_cb)(struct xf_handle *h, struct xf_message *msg);
/* ...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))
#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8))
#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8))
/* ...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(id) (((id) >> 0) & 0xFFFF)
#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3)
#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_CLIENT(id) (((id) >> 22) & 0x1FF)
#define __XF_AP_PROXY(core) ((core) | 0x8000)
#define __XF_DSP_PROXY(core) ((core) | 0x8000)
#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 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;
int is_active;
/* ...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;
/* ...auxiliary buffer pool for clients */
struct xf_pool *aux;
};
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;
u32 dsp_board_type;
};
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);
struct xf_message*
xf_cmd_recv_timeout(struct xf_proxy *proxy, wait_queue_head_t *wq,
struct xf_msg_queue *queue, int wait);
struct xf_message*
xf_cmd_send_recv(struct xf_proxy *proxy, u32 id, u32 opcode,
void *buffer, u32 length);
struct xf_message*
xf_cmd_send_recv_wq(struct xf_proxy *proxy, u32 id, u32 opcode, void *buffer,
u32 length, wait_queue_head_t *wq,
struct xf_msg_queue *queue);
struct xf_message*
xf_cmd_send_recv_complete(struct xf_client *client, struct xf_proxy *proxy,
u32 id, u32 opcode, void *buffer, u32 length,
struct work_struct *work,
struct completion *completion);
/* ...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);
int xf_cmd_alloc(struct xf_proxy *proxy, void **buffer, u32 length);
int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length);
int xf_open(struct xf_client *client, struct xf_proxy *proxy,
struct xf_handle *handle, const char *id, u32 core,
xf_response_cb response);
int xf_close(struct xf_client *client, struct xf_handle *handle);
/*******************************************************************************
* Opcode composition
******************************************************************************/
/* ...opcode composition with command/response data tags */
#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F))
/* ...accessors */
#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31))
#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30))
#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F))
/*******************************************************************************
* Opcode types
******************************************************************************/
/* ...unregister client */
#define XF_UNREGISTER __XF_OPCODE(0, 0, 0)
/* ...register client at proxy */
#define XF_REGISTER __XF_OPCODE(1, 0, 1)
/* ...port routing command */
#define XF_ROUTE __XF_OPCODE(1, 0, 2)
/* ...port unrouting command */
#define XF_UNROUTE __XF_OPCODE(1, 0, 3)
/* ...shared buffer allocation */
#define XF_ALLOC __XF_OPCODE(0, 0, 4)
/* ...shared buffer freeing */
#define XF_FREE __XF_OPCODE(0, 0, 5)
/* ...set component parameters */
#define XF_SET_PARAM __XF_OPCODE(1, 0, 6)
/* ...get component parameters */
#define XF_GET_PARAM __XF_OPCODE(1, 1, 7)
/* ...input buffer reception */
#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8)
/* ...output buffer reception */
#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9)
/* ...flush specific port */
#define XF_FLUSH __XF_OPCODE(0, 0, 10)
/* ...start component operation */
#define XF_START __XF_OPCODE(0, 0, 11)
/* ...stop component operation */
#define XF_STOP __XF_OPCODE(0, 0, 12)
/* ...pause component operation */
#define XF_PAUSE __XF_OPCODE(0, 0, 13)
/* ...resume component operation */
#define XF_RESUME __XF_OPCODE(0, 0, 14)
/* ...resume component operation */
#define XF_SUSPEND __XF_OPCODE(0, 0, 15)
/* ...load lib for component operation */
#define XF_LOAD_LIB __XF_OPCODE(0, 0, 16)
/* ...unload lib for component operation */
#define XF_UNLOAD_LIB __XF_OPCODE(0, 0, 17)
/* ...component output eos operation */
#define XF_OUTPUT_EOS __XF_OPCODE(0, 0, 18)
/* ...total amount of supported decoder commands */
#define __XF_OP_NUM 19
#endif