feat(mt8196): add SPM common version support

This patch provides common APIs for communication with other subsystems
as well as common APIs for collecting the clock and power status of
each subsystem.

Signed-off-by: Wenzhen Yu <wenzhen.yu@mediatek.com>
Change-Id: I1b907256f53578a58d74d66beec7140edf41f687
This commit is contained in:
Wenzhen Yu 2024-12-16 19:56:48 +08:00
parent a24b53e0e5
commit 5532feb70c
7 changed files with 369 additions and 2 deletions

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_VER_H
#define MT_SPM_VER_H
#include <stdint.h>
enum mt_plat_dram_to_spm_type {
SPMFW_DEFAULT_TYPE = 0,
SPMFW_LP4_2CH_3200,
SPMFW_LP4X_2CH_3600,
SPMFW_LP3_1CH_1866,
SPMFW_LP4X_2CH_3733,
SPMFW_LP4X_2CH_4266,
SPMFW_LP4X_2CH_3200,
SPMFW_LP5_2CH_6400,
SPMFW_LP5X_4CH_7500,
SPMFW_TYPE_NOT_FOUND,
};
enum pwrctrl_selection {
SPM_INIT_PWRCTRL = 0,
SPM_VCOREDVFS_PWRCTRL,
SPM_IDLE_PWRCTRL,
SPM_SUSPEND_PWRCTRL,
SPM_PWRCTRL_MAX,
};
struct pcm_desc {
const char *version; /* PCM code version */
uint32_t *base; /* Binary array base */
uintptr_t base_dma; /* DMA addr of base */
uint32_t pmem_words;
uint32_t total_words;
uint32_t pmem_start;
uint32_t dmem_start;
};
#define DYNA_LOAD_PCM_PATH_SIZE 128
#define PCM_FIRMWARE_VERSION_SIZE 128
struct dyna_load_pcm_t {
char path[DYNA_LOAD_PCM_PATH_SIZE];
char version[PCM_FIRMWARE_VERSION_SIZE];
char *buf;
struct pcm_desc desc;
int ready;
};
struct load_pcm_fw_t {
unsigned int fw_max_num;
char **pcm_name_str;
struct dyna_load_pcm_t *dyna_load_pcm;
unsigned int (*is_fw_running)(void);
unsigned int (*get_fw_index)(unsigned int fw_type);
int (*fw_init)(struct pcm_desc *desc);
int (*fw_run)(unsigned int first, void *pwrctrl);
};
/* SPM firmware restart definition */
#define SPM_FW_FORCE_RESET BIT(0)
#define SPM_FW_FORCE_RESUME BIT(1)
int spm_firmware_restart(unsigned int force, void *pwrctrl);
int spm_firmware_type_get(void);
void spm_firmware_type_probe(unsigned int type);
void spm_firmware_init(uint64_t addr, uint64_t size);
uint64_t spm_load_firmware_status(void);
void register_load_fw(struct load_pcm_fw_t *info);
#endif /* MT_SPM_VER_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, MediaTek Inc. All rights reserved.
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -10,7 +10,9 @@
enum mt_spm_sspm_notify_id {
MT_SPM_NOTIFY_LP_ENTER = 0,
MT_SPM_NOTIFY_LP_LEAVE,
MT_SPM_NOTIFY_SUSPEND_VCORE_VOLTAGE,
MT_SPM_NOTIFY_SUSPEND_VCORE,
MT_SPM_NOTIFY_IDLE_ENTER,
MT_SPM_NOTIFY_IDLE_LEAVE,
};
#ifdef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_SSPM_INTC_H
#define MT_SPM_SSPM_INTC_H
#define MT_SPM_SSPM_INTC_SEL_0 0x10
#define MT_SPM_SSPM_INTC_SEL_1 0x20
#define MT_SPM_SSPM_INTC_SEL_2 0x40
#define MT_SPM_SSPM_INTC_SEL_3 0x80
#define MT_SPM_SSPM_INTC_TRIGGER(id, sg) \
(((0x10 << (id)) | ((sg) << (id))) & 0xFF)
#define SSPM_CFGREG_ADDR(ofs) (SSPM_CFGREG_BASE + (ofs))
#define AP_SSPM_IRQ SSPM_CFGREG_ADDR(0x018)
#define DO_SPM_SSPM_LP_NOTIFY() mmio_write_32(AP_SSPM_IRQ, 1)
#endif /* MT_SPM_SSPM_INTC_H */

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/libc/errno.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <mtk_mmap_pool.h>
#include <notifier/inc/mt_spm_notifier.h>
#include <notifier/v4/mt_spm_sspm_intc.h>
#define MT_SPM_SSPM_MBOX_OFF(x) (SSPM_MBOX_3_BASE + x)
#define MT_SPM_MBOX(slot) MT_SPM_SSPM_MBOX_OFF((slot<<2UL))
/* LOOKUP SSPM_MBOX_SPM_LP1 */
#define SSPM_MBOX_SPM_LP_LOOKUP1 MT_SPM_MBOX(0)
/* LOOKUP SSPM_MBOX_SPM_LP2 */
#define SSPM_MBOX_SPM_LP_LOOKUP2 MT_SPM_MBOX(1)
#define SSPM_MBOX_SPM_LP1 MT_SPM_MBOX(2)
#define SSPM_MBOX_SPM_LP2 MT_SPM_MBOX(3)
#define SSPM_MBOX_SPM_SIZE 16
/* 4 mbox is in usage */
#define MT_SPM_MBOX_OFFSET(slot) MT_SPM_MBOX((slot + 4))
enum SSPM_SLEEP_CMD {
SLP_TASK_NONE = 0,
SLP_TASK_AP_SUSPEND,
SLP_TASK_AP_RESUME,
SLP_TASK_APSRC_OFF,
SLP_TASK_APSRC_ON,
SLP_TASK_INFRA_OFF,
SLP_TASK_INFRA_ON,
SLP_TASK_VCORE_OFF,
SLP_TASK_VCORE_ON,
SLP_TASK_IDLE_OFF,
SLP_TASK_IDLE_ON,
SLP_TASK_INFRA_noPERI_OFF,
SLP_TASK_INFRA_noPERI_ON,
SLP_TASK_ERR = 32,
};
static unsigned int cur_mbox_index;
static int __mt_spm_is_available_index(int cur_idx)
{
unsigned int val;
val = mmio_read_32(MT_SPM_MBOX_OFFSET(cur_idx));
val = (val >> 30);
if (val == 0 || val == 3)
return 1;
return 0;
}
static int __mt_spm_get_available_index(void)
{
unsigned int idx = cur_mbox_index;
int i = 0;
for (i = 0 ; i < SSPM_MBOX_SPM_SIZE ; i++) {
if (__mt_spm_is_available_index(idx)) {
cur_mbox_index = (idx + 1) % SSPM_MBOX_SPM_SIZE;
return idx;
}
idx = (idx + 1) % SSPM_MBOX_SPM_SIZE;
}
return -EBUSY;
}
static int __mt_spm_sspm_write_cmd_queue(int idx, int value)
{
unsigned int val;
val = mmio_read_32(MT_SPM_MBOX_OFFSET(idx));
val = val ^ BIT(31);
val = (value & 0x3fffffff) | (val & 0xc0000000);
mmio_write_32(MT_SPM_MBOX_OFFSET(idx), val);
return 0;
}
void mt_spm_sspm_cmd_enqueue(int cmd)
{
int idx;
idx = __mt_spm_get_available_index();
/* Block when queue full */
if (idx == -EBUSY) {
while (!__mt_spm_is_available_index(cur_mbox_index))
;
idx = cur_mbox_index;
cur_mbox_index = (cur_mbox_index+1) % SSPM_MBOX_SPM_SIZE;
}
__mt_spm_sspm_write_cmd_queue(idx, cmd);
}
int mt_spm_sspm_notify_u32(int type, unsigned int val)
{
switch (type) {
case MT_SPM_NOTIFY_LP_ENTER:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_AP_SUSPEND);
DO_SPM_SSPM_LP_NOTIFY();
break;
case MT_SPM_NOTIFY_LP_LEAVE:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_AP_RESUME);
DO_SPM_SSPM_LP_NOTIFY();
break;
case MT_SPM_NOTIFY_IDLE_ENTER:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_IDLE_OFF);
DO_SPM_SSPM_LP_NOTIFY();
break;
case MT_SPM_NOTIFY_IDLE_LEAVE:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_IDLE_ON);
DO_SPM_SSPM_LP_NOTIFY();
break;
default:
break;
}
return 0;
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_PMIC_WRAP_H
#define MT_SPM_PMIC_WRAP_H
struct pmic_wrap_cmd_setting {
uint32_t spm_pwrap_addr;
uint32_t cmd_addr;
uint32_t cmd_data;
};
struct pmic_wrap_phase_setting {
struct pmic_wrap_cmd_setting *cmd;
unsigned int nr_idx;
};
struct pmic_wrap_setting {
struct pmic_wrap_phase_setting *phase;
const unsigned int phase_nr_idx;
};
int mt_spm_pmic_wrap_set_phase(unsigned int phase);
int mt_spm_pmic_wrap_set_cmd(unsigned int phase,
unsigned int idx, unsigned int cmd_data);
unsigned long mt_spm_pmic_wrap_get_cmd(unsigned int phase, unsigned int idx);
void mt_spm_pmic_wrap_set_table(struct pmic_wrap_setting *pw);
#endif /* MT_SPM_PMIC_WRAP_H */

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/libc/errno.h>
#include <lib/mmio.h>
#include <pmic_wrap/inc/mt_spm_pmic_wrap.h>
#define SPM_DATA_SHIFT 16
static struct pmic_wrap_setting *pmic_wrap;
int mt_spm_pmic_wrap_set_phase(unsigned int phase)
{
int idx;
uint32_t cmd_addr, cmd_data;
struct pmic_wrap_phase_setting *current_phase;
if (!pmic_wrap)
return -ENODEV;
if (phase >= pmic_wrap->phase_nr_idx)
return -EINVAL;
current_phase = &pmic_wrap->phase[phase];
for (idx = 0; idx < current_phase->nr_idx; idx++) {
cmd_addr = current_phase->cmd[idx].cmd_addr;
cmd_data = current_phase->cmd[idx].cmd_data;
mmio_write_32(current_phase->cmd[idx].spm_pwrap_addr,
(cmd_addr << SPM_DATA_SHIFT) | cmd_data);
}
return 0;
}
int mt_spm_pmic_wrap_set_cmd(unsigned int phase,
unsigned int idx, unsigned int cmd_data)
{
uint32_t cmd_addr;
struct pmic_wrap_phase_setting *current_phase;
if (!pmic_wrap)
return -ENODEV;
if (phase >= pmic_wrap->phase_nr_idx)
return -EINVAL;
if (idx >= pmic_wrap->phase[phase].nr_idx)
return -EINVAL;
current_phase = &pmic_wrap->phase[phase];
current_phase->cmd[idx].cmd_data = cmd_data;
cmd_addr = current_phase->cmd[idx].cmd_addr;
mmio_write_32(current_phase->cmd[idx].spm_pwrap_addr,
(cmd_addr << SPM_DATA_SHIFT) | cmd_data);
return 0;
}
unsigned long mt_spm_pmic_wrap_get_cmd(unsigned int phase, unsigned int idx)
{
if (!pmic_wrap)
return 0;
if (phase >= pmic_wrap->phase_nr_idx)
return 0;
if (idx >= pmic_wrap->phase[phase].nr_idx)
return 0;
return pmic_wrap->phase[phase].cmd[idx].cmd_data;
}
void mt_spm_pmic_wrap_set_table(struct pmic_wrap_setting *pw)
{
pmic_wrap = pw;
}

View file

@ -0,0 +1,23 @@
#
# Copyright (c) 2025, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := spm_version
LOCAL_SRCS-y :=
ifneq (${NOTIFIER_VER},)
LOCAL_SRCS-y += ${LOCAL_DIR}/notifier/${NOTIFIER_VER}/mt_spm_sspm_notifier.c
endif
ifneq (${PMIC_GS_DUMP_VER},)
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_gs/${PMIC_GS_DUMP_VER}/mt_spm_pmic_gs_dump.c
endif
ifneq (${PMIC_WRAP_VER},)
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_wrap/${PMIC_WRAP_VER}/mt_spm_pmic_wrap.c
endif
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_SUPPORT))