blob: c1423952a3946356a1ecbc3f2449ee7f3ed413a6 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright 2020 Google LLC
*
*/
#ifndef __FRAMEWORK_H_
#define __FRAMEWORK_H_
#ifdef CONFIG_GS_ACPM_MODULE
#include "common.h"
#endif
/**
* struct acpm_framework - General information for ACPM framework.
*
* @plugins: Pointer to soc-specific plugins array.
* @pid_framework: Plugin ID for ACPM framework.
* @pid_max: # of plugins.
* @ipc_max: # of IPC channels.
* @irq_max: # of interrupt sources.
* @ktime_index: ktime information from the kernel.
* @log_buf_rear: Rear pointer of the log buffer.
* @log_buf_front: Front pointer of the log buffer.
* @log_data: Base address of the log buffer.
* @log_entry_size: Entry size of the log buffer.
* @log_entry_len: Length of the log buffer.
* @ipc_base: Base address of the IPC buffer.
* @ipc_buf_tx_size: Size of the IPC TX buffer.
* @total_size: Size of the framework and all plugins attached.
* @fw_size: Size of the ACPM framework.
* @intr_to_skip: Disabled interrupts.
* @preemption_irq: preemptive interrupts.
* @intr_flag_offset: Field offset for Mailbox interrupt pending register.
*/
struct acpm_framework {
#ifndef CONFIG_GS_ACPM_MODULE
struct plugin *plugins;
#else
u32 plugins;
#endif
u32 num_plugins;
#ifndef CONFIG_GS_ACPM_MODULE
struct ipc_channel *ipc_channels;
#else
u32 ipc_channels;
#endif
u32 num_ipc_channels;
u32 pid_framework;
u32 pid_max;
u32 ipc_ap_max;
u32 ipc_cp_max;
u32 ipc_gnss_max;
u32 ipc_wlbt_max;
u32 ipc_max;
u32 irq_max;
u32 ktime_index;
u32 log_buf_rear;
u32 log_buf_front;
u32 log_data;
u32 log_entry_size;
u32 log_entry_len;
u32 ipc_base;
u32 ipc_buf_tx_size;
u32 fw_size;
u32 intr_to_skip;
u32 intr_flag_offset;
struct build_info info;
u32 preempt_irq_max;
u32 nvic_max;
u32 intr_stat;
u32 intr_stat1;
u32 preemption_irq;
u32 preempt_plugin;
u32 preempt_log_buf_rear;
u32 preempt_log_buf_front;
u32 preempt_log_data;
u32 preempt_log_entry_len;
u32 fvmap;
u32 reserved[62];
u32 err_log_async_channel;
};
/**
* struct channel_info - IPC information of a channel
*
* @rx_rear: Rear ptr for RX cmd queue. (for dequeue)
* @rx_front: Front ptr for RX cmd queue. (just for empty check)
* @rx_base: Predefined base addr for RX cmd queue.
* @rx_indr_buf: Predefined base addr for RX indirect buffer.
* @tx_rear: Rear ptr for TX queue.
* @tx_front: Front ptr for TX queue.
* @tx_base: Predefined base addr for TX queue.
* @q_len: Length of both TX/RX queue.
* @q_elem_size: Element size of both TX/RX queue.
* @credit: For preventing starvation of certain plugin.
*/
struct channel_info {
u32 rx_rear;
u32 rx_front;
u32 rx_base;
u32 rx_indr_buf;
u32 rx_indr_buf_base;
u32 rx_indr_buf_size;
u32 tx_rear;
u32 tx_front;
u32 tx_base;
u32 q_len;
u32 q_elem_size;
u32 credit;
u32 mbox_addr;
};
/**
* struct ipc_channel - descriptor for ipc channel.
*
* @id: The ipc channel's id.
* @field: The ipc channel's field in mailbox status register.
* @late_init_source: Use of this channel broadcast late_init_ipc
* @owner: This interrupt's Belonged plugin.
* @type: The ipc channel's memory type; QUEUE or Register.
* @ch: IPC information for this plugin's channel.
* @ap_poll: The flag indicating whether AP polls on this channel or not. (interrupt)
*/
struct ipc_channel {
u32 id;
u32 field:30; // Only 16 are manage by HW
u32 late_init_source:1;
u32 use_sacpm:1;
s32 owner;
u32 type;
struct channel_info ch;
u32 ap_poll;
};
/**
* struct acpm_interrupt - descriptor for individual interrupt source.
*
* @field: The interrupt's field in NVIC pending register.
* @handler: Handler for this interrupt.
* @owner: This interrupt's Belonged plugin.
* @is_disabled: Flag to skip this interrupt or not.
*/
struct acpm_interrupt {
u32 field;
s32 (*handler)(u32 intr);
s32 owner;
bool is_disabled;
bool log_skip;
bool idle_ip_skip;
bool is_preemption;
};
/**
* struct apm_peri - The abstraction for APM peripherals.
*
* @mpu_init: Initializes Core's MPU. (Regions, ...)
* @enable_systick: Enables System Tick.
* @disable_systick: Disables System Tick.
* @get_systick_cvr: Get the current value register of System Tick.
* @get_systick_icvr: Get (MAX_VAL - CUR_VAL) of System Tick.
* @get_systick_icvra: Get (MAX_VAL - CUR_VAL) & MAX_VAL of System Tick.
* @get_systick_csr: Get the current status register of System Tick.
* @enable_wdt: Enables Watchdog Timer.
* @disable_wdt: Disables Watchdog Timer.
* @enable_intr: Enables specific interrupts on NVIC.
* @get_enabled_intr: Get enabled interrupts on NVIC.
* @clr_pend_intr: Clears pended interrupts on NVIC.
* @get_pend_intr: Get Pended interrupts on NVIC.
* @get_mbox_pend_intr: Get Pended interrupts on Mailbox.
* @clr_mbox_pend_intr: Clears pended interrupts on Mailbox.
* @gen_mbox_intr_ap: Generates Mailbox interrupt to AP.
*/
struct apm_peri {
void (*power_mode_init)(void);
void (*peri_timer_init)(void);
void (*set_peri_timer_event)(u32 msec);
void (*del_peri_timer_event)(void);
u32 (*get_peri_timer_cvr)(void);
u32 (*get_peri_timer_icvr)(void);
u32 (*get_peri_timer_icvra)(void);
void (*mpu_init)(void);
void (*enable_systick)(void);
void (*disable_systick)(void);
u32 (*get_systick_cvr)(void);
u32 (*get_systick_icvr)(void);
u32 (*get_systick_icvra)(void);
u32 (*get_systick_csr)(void);
void (*enable_wdt)(void);
void (*disable_wdt)(void);
void (*enable_intr)(u32 idx, u32 intr);
void (*disable_intr)(u32 idx, u32 intr);
u32 (*get_enabled_intr)(u32 idx);
void (*clr_pend_intr)(u32 idx, u32 intr);
u32 (*get_active_intr)(u32 idx);
u32 (*get_pend_intr)(u32 idx);
u32 (*get_mbox_pend_intr)(u32 mbox_addr);
void (*clr_mbox_pend_intr)(u32 mbox_addr, u32 intr);
void (*gen_mbox_intr)(struct ipc_channel *ipc_ch);
u32 (*set_idle_ip)(u32 is_idle, u32 intr_filed);
s32 (*udelay_systick)(u32 udelay_us);
void (*set_wdtrst_req)(void);
void (*uart_write_str)(const char *str);
void (*bl2_release)(void);
};
extern struct apm_peri apm_peri;
/**
* struct plat_ops - Getters for platform specific data to ACPM framework.
*
* @plugin_base_init: initializes base address of plugins.
* @get_acpm_platform_data: inits the remaining data.
* @get_target_plugin: returns next plugin to be executed.
*/
struct plat_ops {
void (*plugin_base_init)(struct acpm_framework *acpm);
void (*get_acpm_platform_data)(struct acpm_framework *acpm);
u32 (*get_target_plugin)(u32 intr, void *acpm_data, u32 int_status, u32 *ch_num);
void (*ipc_channel_init)(struct acpm_framework *acpm);
void *(*get_plugins_extern_fn)(void);
u32 (*get_mbox_addr)(u32 intr);
u32 (*filter_buff_int_status)(u32 intr, u32 int_status);
u32 (*filter_queue_int_status)(u32 intr, u32 int_status);
void (*wait_for_intr)(void);
u32 (*system_reset)(void);
void (*preemption_enable)(void);
void (*preemption_disable)(void);
void (*restore_intr)(void);
void (*preemption_disable_irq_save)(u32 *flag);
void (*preemption_enable_irq_restore)(u32 *flag);
};
extern struct plat_ops plat_ops;
s32 shard_queue_ipc_dispatcher(u32 intr);
s32 shard_buffer_ipc_dispatcher(u32 intr);
s32 dummy_irq_handler(u32 intr);
void acpm_insert_dbg_log(u32 plugin_id, struct dbg_log_info *log);
char *acpm_strcpy(char *dest, const char *src);
extern void acpm_print(u32 id, const char *s, u32 int_data, u32 level);
extern void *get_intr_vector(u32 *irq_max);
extern void *get_preempt_intr_vector(u32 *irq_max);
extern u32 get_nvic_max(void);
extern struct acpm_framework acpm;
enum shard_buffer_type {
TYPE_QUEUE = 1,
TYPE_BUFFER,
};
#define LOG_ID_SHIFT (28)
#define LOG_TIME_INDEX (20)
#define LOG_LEVEL (19)
#define AVAILABLE_TIME (26000)
#define ACPM_DEBUG_PRINT
#ifdef ACPM_DEBUG_PRINT
#define ACPM_PRINT_ERR(id, s, int_data) acpm_print(id, s, int_data, 0xF)
#define ACPM_PRINT(id, s, int_data) acpm_print(id, s, int_data, 0x1)
#else
#define ACPM_PRINT_ERR(id, s, int_data) do {} while (0)
#define ACPM_PRINT(a, b, c) do {} while (0)
#endif
#define true (1)
#define false (0)
/* IPC Protocol bit field definitions */
#define IPC_PRTC_OWN (31)
#define IPC_PRTC_RSP (30)
#define IPC_PRTC_INDR (29)
#define IPC_PRTC_ID (26)
#define IPC_PRTC_IDX (0x7 << IPC_PRTC_ID)
#define IPC_PRTC_DP_ATTACH (25)
#define IPC_PRTC_DP_DETACH (24)
#define IPC_PRTC_DP_CMD ((1 << IPC_PRTC_DP_ATTACH) | (1 << IPC_PRTC_DP_DETACH))
#define IPC_PRTC_TEST (23)
#define IPC_PRTC_STOP (22)
#define ERR_NOPLUGIN (10)
#define ERR_REJECTED (11)
#define ERR_NOTYET (12)
/* speedy definition */
struct speedyops {
int (*init)(void);
#ifdef CONFIG_MULTI_PMIC
int (*tx)(u8 channel, unsigned int reg, unsigned int val);
int (*rx)(u8 channel, unsigned int reg);
#else
int (*tx)(unsigned int reg, unsigned int val);
int (*rx)(unsigned int reg);
#endif
};
extern struct speedyops speedyops;
#ifdef CONFIG_GS_ACPM_MODULE
/**
* acpm_get_buffer - Get an ACPM named buffer. This handle old ACPM cases.
*
* @sram: Pointer to ACPM sram.
* @acpm: Pointer to ACPM struct.
* @name: Name of the buffer we are looking for.
* @addr: On success, the address of the buffer we are looking for.
* @size: On success, the size of the buffer we are looking for.
*
* @return: 0 success (buffer found)
* -1 failed (buffer not found)
*/
static inline int acpm_get_buffer(char *sram, const struct acpm_framework *acpm,
const char *name, char **addr, u32 *size)
{
struct plugin *plugins = (struct plugin *)(sram + acpm->plugins);
u32 i;
for (i = 0; i < acpm->num_plugins; i++) {
const u32 *next;
struct plugin_ops *plugin_ops;
if (!plugins[i].plugin_ops)
continue; /* No plugin attached */
plugin_ops =
(struct plugin_ops *)(sram + plugins[i].plugin_ops);
if (plugin_ops->info.build_version
[sizeof(plugin_ops->info.build_version) - 1] != 0) {
/*
* Old acpm has info.build_version[25],build_time[25]
* instead of info.build_version[48] and info.major,
* info.minor.
* 1) info.build_time[22] ==
* new info.build_version[47] != 0
* It's an old version and the string is too big
* to fit in 23 char.
* 2) info.build_time[22] ==
* new info.build_version[47] == 0
* If it's an old version and the string fit in
* 23 char
* In that case info.build_time[23] == 0, so
* info.major == 0.
* 3) info.build_time[22] ==
* new info.build_version[47] == 0
* If it's a new version, info.major > 0
*/
continue; /* Old ACPM not supporting version */
}
if (plugin_ops->info.major < BUILD_INFO_MAJOR_BUFFERS)
continue; /* No buffers in this struct */
next = &plugin_ops->buffers;
while (*next) {
u32 i = 0;
struct plugin_buffer *buffer =
(struct plugin_buffer *)(sram + *next);
while ((i < sizeof(buffer->name)) &&
(buffer->name[i] == name[i]) &&
(buffer->name[i] != 0)) {
i++;
}
if (i < sizeof(buffer->name) &&
buffer->name[i] != name[i]) {
next = &buffer->next;
continue;
}
*addr = sram + buffer->address;
*size = buffer->size;
return 0;
}
}
return -1;
}
#endif
#define speedy_init() speedyops.init()
#ifdef CONFIG_MULTI_PMIC
#define speedy_tx(channel, reg, val) speedyops.tx(channel, reg, val)
#define speedy_rx(channel, reg) speedyops.rx(channel, reg)
#else
#define speedy_tx(reg, val) speedyops.tx(reg, val)
#define speedy_rx(reg) speedyops.rx(reg)
#endif
#define MAGIC 0x0BAD0BAD
#endif