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.
411 lines
11 KiB
411 lines
11 KiB
/* |
|
* Copyright (c) 2015 MediaTek Inc. |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License version 2 as |
|
* published by the Free Software Foundation. |
|
* |
|
* 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. |
|
*/ |
|
|
|
#ifndef __MTK_CMDQ_H__ |
|
#define __MTK_CMDQ_H__ |
|
|
|
#include <linux/mailbox_client.h> |
|
#include <linux/mailbox/mtk-cmdq-mailbox.h> |
|
|
|
#define CMDQ_SPR_FOR_TEMP (0) |
|
#define CMDQ_THR_SPR_IDX0 0 |
|
#define CMDQ_THR_SPR_IDX1 1 |
|
#define CMDQ_THR_SPR_IDX2 2 |
|
#define CMDQ_THR_SPR_IDX3 3 |
|
#define CMDQ_THR_SPR_MAX (4) |
|
|
|
#define CMDQ_TPR_ID (56) |
|
#define CMDQ_GPR_CNT_ID (32) |
|
#define CMDQ_CPR_STRAT_ID (0x8000) |
|
#define CMDQ_EVENT_MAX 0x3FF |
|
#define SUBSYS_NO_SUPPORT 99 |
|
|
|
/* GCE provide 26M timer, thus each tick 1/26M second, |
|
* which is, 1 microsecond = 26 ticks |
|
*/ |
|
#define CMDQ_US_TO_TICK(_t) (_t * 26) |
|
#define CMDQ_TICK_TO_US(_t) (do_div(_t, 26)) |
|
|
|
#if IS_ENABLED(CONFIG_MACH_MT6771) || IS_ENABLED(CONFIG_MACH_MT8168) || \ |
|
IS_ENABLED(CONFIG_MACH_MT6768) || IS_ENABLED(CONFIG_MACH_MT6739) || \ |
|
IS_ENABLED(CONFIG_MACH_MT8167) || IS_ENABLED(CONFIG_MACH_MT6765) |
|
#define CMDQ_REG_SHIFT_ADDR(addr) (addr) |
|
#define CMDQ_REG_REVERT_ADDR(addr) (addr) |
|
#elif IS_ENABLED(CONFIG_MACH_MT6779) || IS_ENABLED(CONFIG_MACH_MT6785) || \ |
|
IS_ENABLED(CONFIG_MACH_MT6789) || IS_ENABLED(CONFIG_MACH_MT6885) |
|
#define CMDQ_REG_SHIFT_ADDR(addr) ((addr) >> 3) |
|
#define CMDQ_REG_REVERT_ADDR(addr) ((addr) << 3) |
|
#endif |
|
|
|
/* GCE provide 32/64 bit General Purpose Register (GPR) |
|
* use as data cache or address register |
|
* 32bit: R0-R15 |
|
* 64bit: P0-P7 |
|
* Note: |
|
* R0-R15 and P0-P7 actullay share same memory |
|
* R0 use as mask in instruction, thus be care of use R1/P0. |
|
*/ |
|
enum cmdq_gpr { |
|
/* 32bit R0 to R15 */ |
|
CMDQ_GPR_R00 = 0x00, |
|
CMDQ_GPR_R01 = 0x01, |
|
CMDQ_GPR_R02 = 0x02, |
|
CMDQ_GPR_R03 = 0x03, |
|
CMDQ_GPR_R04 = 0x04, |
|
CMDQ_GPR_R05 = 0x05, |
|
CMDQ_GPR_R06 = 0x06, |
|
CMDQ_GPR_R07 = 0x07, |
|
CMDQ_GPR_R08 = 0x08, |
|
CMDQ_GPR_R09 = 0x09, |
|
CMDQ_GPR_R10 = 0x0A, |
|
CMDQ_GPR_R11 = 0x0B, |
|
CMDQ_GPR_R12 = 0x0C, |
|
CMDQ_GPR_R13 = 0x0D, |
|
CMDQ_GPR_R14 = 0x0E, |
|
CMDQ_GPR_R15 = 0x0F, |
|
|
|
/* 64bit P0 to P7 */ |
|
CMDQ_GPR_P0 = 0x10, |
|
CMDQ_GPR_P1 = 0x11, |
|
CMDQ_GPR_P2 = 0x12, |
|
CMDQ_GPR_P3 = 0x13, |
|
CMDQ_GPR_P4 = 0x14, |
|
CMDQ_GPR_P5 = 0x15, |
|
CMDQ_GPR_P6 = 0x16, |
|
CMDQ_GPR_P7 = 0x17, |
|
}; |
|
|
|
/* Define GCE tokens which not change by platform */ |
|
enum gce_event { |
|
/* GPR timer token, 994 to 994+23 */ |
|
GCE_TOKEN_GPR_TIMER = 994, |
|
}; |
|
|
|
struct cmdq_pkt; |
|
|
|
struct cmdq_subsys { |
|
u32 base; |
|
u8 id; |
|
}; |
|
|
|
struct cmdq_base { |
|
struct cmdq_subsys subsys[32]; |
|
u8 count; |
|
u16 cpr_base; |
|
u8 cpr_cnt; |
|
}; |
|
|
|
struct cmdq_client { |
|
struct mbox_client client; |
|
struct mbox_chan *chan; |
|
void *cl_priv; |
|
struct mutex chan_mutex; |
|
}; |
|
|
|
struct cmdq_buf_pool { |
|
struct dma_pool *pool; |
|
atomic_t cnt; |
|
u32 limit; |
|
}; |
|
|
|
struct cmdq_operand { |
|
/* register type */ |
|
bool reg; |
|
union { |
|
/* index */ |
|
u16 idx; |
|
/* value */ |
|
u16 value; |
|
}; |
|
}; |
|
|
|
enum CMDQ_LOGIC_ENUM { |
|
CMDQ_LOGIC_ASSIGN = 0, |
|
CMDQ_LOGIC_ADD = 1, |
|
CMDQ_LOGIC_SUBTRACT = 2, |
|
CMDQ_LOGIC_MULTIPLY = 3, |
|
CMDQ_LOGIC_XOR = 8, |
|
CMDQ_LOGIC_NOT = 9, |
|
CMDQ_LOGIC_OR = 10, |
|
CMDQ_LOGIC_AND = 11, |
|
CMDQ_LOGIC_LEFT_SHIFT = 12, |
|
CMDQ_LOGIC_RIGHT_SHIFT = 13 |
|
}; |
|
|
|
enum CMDQ_CONDITION_ENUM { |
|
CMDQ_CONDITION_ERROR = -1, |
|
|
|
/* these are actual HW op code */ |
|
CMDQ_EQUAL = 0, |
|
CMDQ_NOT_EQUAL = 1, |
|
CMDQ_GREATER_THAN_AND_EQUAL = 2, |
|
CMDQ_LESS_THAN_AND_EQUAL = 3, |
|
CMDQ_GREATER_THAN = 4, |
|
CMDQ_LESS_THAN = 5, |
|
|
|
CMDQ_CONDITION_MAX, |
|
}; |
|
|
|
struct cmdq_flush_completion { |
|
struct cmdq_pkt *pkt; |
|
struct completion cmplt; |
|
s32 err; |
|
}; |
|
|
|
u32 cmdq_subsys_id_to_base(struct cmdq_base *cmdq_base, int id); |
|
|
|
/** |
|
* cmdq_pkt_realloc_cmd_buffer() - reallocate command buffer for CMDQ packet |
|
* @pkt: the CMDQ packet |
|
* @size: the request size |
|
* Return: 0 for success; else the error code is returned |
|
*/ |
|
int cmdq_pkt_realloc_cmd_buffer(struct cmdq_pkt *pkt, size_t size); |
|
|
|
/** |
|
* cmdq_register_device() - register device which needs CMDQ |
|
* @dev: device for CMDQ to access its registers |
|
* |
|
* Return: cmdq_base pointer or NULL for failed |
|
*/ |
|
struct cmdq_base *cmdq_register_device(struct device *dev); |
|
|
|
/** |
|
* cmdq_mbox_create() - create CMDQ mailbox client and channel |
|
* @dev: device of CMDQ mailbox client |
|
* @index: index of CMDQ mailbox channel |
|
* |
|
* Return: CMDQ mailbox client pointer |
|
*/ |
|
struct cmdq_client *cmdq_mbox_create(struct device *dev, int index); |
|
void cmdq_mbox_stop(struct cmdq_client *cl); |
|
|
|
void cmdq_mbox_pool_set_limit(struct cmdq_client *cl, u32 limit); |
|
void cmdq_mbox_pool_create(struct cmdq_client *cl); |
|
void cmdq_mbox_pool_clear(struct cmdq_client *cl); |
|
|
|
void *cmdq_mbox_buf_alloc(struct device *dev, dma_addr_t *pa_out); |
|
void cmdq_mbox_buf_free(struct device *dev, void *va, dma_addr_t pa); |
|
|
|
s32 cmdq_dev_get_event(struct device *dev, const char *name); |
|
|
|
struct cmdq_pkt_buffer *cmdq_pkt_alloc_buf(struct cmdq_pkt *pkt); |
|
|
|
void cmdq_pkt_free_buf(struct cmdq_pkt *pkt); |
|
|
|
s32 cmdq_pkt_add_cmd_buffer(struct cmdq_pkt *pkt); |
|
|
|
/** |
|
* cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel |
|
* @client: the CMDQ mailbox client |
|
*/ |
|
void cmdq_mbox_destroy(struct cmdq_client *client); |
|
|
|
/** |
|
* cmdq_pkt_create() - create a CMDQ packet |
|
* @pkt_ptr: CMDQ packet pointer to retrieve cmdq_pkt |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
*/ |
|
int cmdq_pkt_create(struct cmdq_pkt **pkt_ptr); |
|
|
|
void cmdq_pkt_set_client(struct cmdq_pkt *pkt, struct cmdq_client *cl); |
|
|
|
s32 cmdq_pkt_cl_create(struct cmdq_pkt **pkt_ptr, struct cmdq_client *cl); |
|
|
|
/** |
|
* cmdq_pkt_destroy() - destroy the CMDQ packet |
|
* @pkt: the CMDQ packet |
|
*/ |
|
void cmdq_pkt_destroy(struct cmdq_pkt *pkt); |
|
|
|
u64 *cmdq_pkt_get_va_by_offset(struct cmdq_pkt *pkt, size_t offset); |
|
|
|
dma_addr_t cmdq_pkt_get_pa_by_offset(struct cmdq_pkt *pkt, u32 offset); |
|
|
|
s32 cmdq_pkt_append_command(struct cmdq_pkt *pkt, u16 arg_c, u16 arg_b, |
|
u16 arg_a, u8 s_op, u8 arg_c_type, u8 arg_b_type, u8 arg_a_type, |
|
enum cmdq_code code); |
|
|
|
s32 cmdq_pkt_read(struct cmdq_pkt *pkt, struct cmdq_base *clt_base, |
|
dma_addr_t src_addr, u16 dst_reg_idx); |
|
|
|
s32 cmdq_pkt_read_reg(struct cmdq_pkt *pkt, u8 subsys, u16 offset, |
|
u16 dst_reg_idx); |
|
|
|
s32 cmdq_pkt_read_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u16 dst_reg_idx); |
|
|
|
s32 cmdq_pkt_write_reg(struct cmdq_pkt *pkt, u8 subsys, |
|
u16 offset, u16 src_reg_idx, u32 mask); |
|
|
|
s32 cmdq_pkt_write_value(struct cmdq_pkt *pkt, u8 subsys, |
|
u16 offset, u32 value, u32 mask); |
|
|
|
s32 cmdq_pkt_write_reg_addr(struct cmdq_pkt *pkt, dma_addr_t addr, |
|
u16 src_reg_idx, u32 mask); |
|
|
|
s32 cmdq_pkt_write_value_addr(struct cmdq_pkt *pkt, dma_addr_t addr, |
|
u32 value, u32 mask); |
|
|
|
s32 cmdq_pkt_store_value(struct cmdq_pkt *pkt, u16 indirect_dst_reg_idx, |
|
u16 dst_addr_low, u32 value, u32 mask); |
|
|
|
s32 cmdq_pkt_store_value_reg(struct cmdq_pkt *pkt, u16 indirect_dst_reg_idx, |
|
u16 dst_addr_low, u16 indirect_src_reg_idx, u32 mask); |
|
|
|
s32 cmdq_pkt_write_indriect(struct cmdq_pkt *pkt, struct cmdq_base *clt_base, |
|
dma_addr_t addr, u16 src_reg_idx, u32 mask); |
|
|
|
/** |
|
* cmdq_pkt_write() - append write command to the CMDQ packet |
|
* @pkt: the CMDQ packet |
|
* @value: the specified target register value |
|
* @clt_base: the CMDQ base |
|
* @addr: target register address |
|
* @mask: the specified target register mask |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
*/ |
|
s32 cmdq_pkt_write(struct cmdq_pkt *pkt, struct cmdq_base *clt_base, |
|
dma_addr_t addr, u32 value, u32 mask); |
|
|
|
s32 cmdq_pkt_mem_move(struct cmdq_pkt *pkt, struct cmdq_base *clt_base, |
|
dma_addr_t src_addr, dma_addr_t dst_addr, u16 swap_reg_idx); |
|
|
|
s32 cmdq_pkt_assign_command(struct cmdq_pkt *pkt, u16 reg_idx, u32 value); |
|
|
|
s32 cmdq_pkt_logic_command(struct cmdq_pkt *pkt, enum CMDQ_LOGIC_ENUM s_op, |
|
u16 result_reg_idx, |
|
struct cmdq_operand *left_operand, |
|
struct cmdq_operand *right_operand); |
|
|
|
s32 cmdq_pkt_jump(struct cmdq_pkt *pkt, s32 offset); |
|
|
|
s32 cmdq_pkt_jump_addr(struct cmdq_pkt *pkt, u32 addr); |
|
|
|
s32 cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, u32 value, u32 addr, u32 mask, |
|
u8 reg_gpr); |
|
|
|
s32 cmdq_pkt_poll_reg(struct cmdq_pkt *pkt, u32 value, u8 subsys, |
|
u16 offset, u32 mask); |
|
|
|
/** |
|
* cmdq_pkt_poll() - append polling command with mask to the CMDQ packet |
|
* @pkt: the CMDQ packet |
|
* @value: the specified target register value |
|
* @subsys: the CMDQ subsys id |
|
* @offset: register offset from module base |
|
* @mask: the specified target register mask |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
*/ |
|
s32 cmdq_pkt_poll(struct cmdq_pkt *pkt, struct cmdq_base *clt_base, |
|
u32 value, u32 addr, u32 mask, u8 reg_gpr); |
|
|
|
/* cmdq_pkt_sleep() - append commands to wait a short time in microsecond |
|
* @pkt: the CMDQ packet |
|
* @tick: sleep time in tick, use CMDQ_MS_TO_TICK to translate into ms |
|
* @reg_gpr: GPR use to counting |
|
* |
|
* Return 0 for success; else the error code is returned |
|
*/ |
|
s32 cmdq_pkt_sleep(struct cmdq_pkt *pkt, u16 tick, u16 reg_gpr); |
|
|
|
s32 cmdq_pkt_poll_timeout(struct cmdq_pkt *pkt, u32 value, u8 subsys, |
|
phys_addr_t addr, u32 mask, u16 count, u16 reg_gpr); |
|
|
|
void cmdq_pkt_perf_end(struct cmdq_pkt *pkt); |
|
void cmdq_pkt_perf_begin(struct cmdq_pkt *pkt); |
|
u32 *cmdq_pkt_get_perf_ret(struct cmdq_pkt *pkt); |
|
|
|
/** |
|
* cmdq_pkt_wfe() - append wait for event command to the CMDQ packet |
|
* @pkt: the CMDQ packet |
|
* @event: the desired event type to "wait and CLEAR" |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
*/ |
|
int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event); |
|
|
|
int cmdq_pkt_wait_no_clear(struct cmdq_pkt *pkt, u16 event); |
|
|
|
/** |
|
* cmdq_pkt_clear_event() - append clear event command to the CMDQ packet |
|
* @pkt: the CMDQ packet |
|
* @event: the desired event to be cleared |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
*/ |
|
s32 cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event); |
|
|
|
s32 cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event); |
|
|
|
s32 cmdq_pkt_finalize(struct cmdq_pkt *pkt); |
|
|
|
s32 cmdq_pkt_finalize_loop(struct cmdq_pkt *pkt); |
|
|
|
/** |
|
* cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ |
|
* packet and call back at the end of done packet |
|
* @client: the CMDQ mailbox client |
|
* @pkt: the CMDQ packet |
|
* @cb: called at the end of done packet |
|
* @data: this data will pass back to cb |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
* |
|
* Trigger CMDQ to asynchronously execute the CMDQ packet and call back |
|
* at the end of done packet. Note that this is an ASYNC function. When the |
|
* function returned, it may or may not be finished. |
|
*/ |
|
s32 cmdq_pkt_flush_async(struct cmdq_client *client, struct cmdq_pkt *pkt, |
|
cmdq_async_flush_cb cb, void *data); |
|
|
|
s32 cmdq_pkt_flush_threaded(struct cmdq_client *client, struct cmdq_pkt *pkt, |
|
cmdq_async_flush_cb cb, void *data); |
|
|
|
/** |
|
* cmdq_pkt_flush() - trigger CMDQ to execute the CMDQ packet |
|
* @client: the CMDQ mailbox client |
|
* @pkt: the CMDQ packet |
|
* |
|
* Return: 0 for success; else the error code is returned |
|
* |
|
* Trigger CMDQ to execute the CMDQ packet. Note that this is a |
|
* synchronous flush function. When the function returned, the recorded |
|
* commands have been done. |
|
*/ |
|
s32 cmdq_pkt_flush(struct cmdq_client *client, struct cmdq_pkt *pkt); |
|
|
|
s32 cmdq_pkt_dump_buf(struct cmdq_pkt *pkt, u32 curr_pa); |
|
|
|
int cmdq_dump_pkt(struct cmdq_pkt *pkt); |
|
|
|
|
|
struct cmdq_thread_task_info { |
|
dma_addr_t pa_base; |
|
struct cmdq_pkt *pkt; |
|
struct list_head list_entry; |
|
}; |
|
|
|
struct cmdq_timeout_info { |
|
u32 irq; |
|
u32 irq_en; |
|
dma_addr_t curr_pc; |
|
u32 *curr_pc_va; |
|
dma_addr_t end_addr; |
|
u32 task_num; |
|
struct cmdq_thread_task_info *timeout_task; |
|
struct list_head task_list; |
|
}; |
|
#endif /* __MTK_CMDQ_H__ */
|
|
|