soc/mediatek/mt8196: Move srclken_rc related code to common

To promote code reuse and maintainability, move srclken_rc related code
to common folder.

BUG=b:379008996
BRANCH=none
TEST=build passed.

Signed-off-by: LiLiang Chen <liliang.chen@mediatek.corp-partner.google.com>
Signed-off-by: Vince Liu <vince-wl.liu@mediatek.corp-partner.google.com>
Change-Id: Ic8401f910bf37c3f413147e293d1d9274c62d8ee
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88378
Reviewed-by: Yidi Lin <yidilin@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
LiLiang Chen 2025-06-29 21:26:48 +08:00 committed by Yu-Ping Wu
commit e7cefe4f41
5 changed files with 260 additions and 240 deletions

View file

@ -0,0 +1,185 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
#ifndef SOC_MEDIATEK_COMMON_SRCLKEN_RC_H
#define SOC_MEDIATEK_COMMON_SRCLKEN_RC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define ACK_DELAY_US 10
#define ACK_DELAY_TIMES 200
/* RC_CENTRAL_CFG1 setting */
#define RC_CENTRAL_ENABLE_VAL 1
#define RC_CENTRAL_DISABLE_VAL 0
/* register direct write */
#define IS_SPI2PMIC_SET_CLR_VAL 0
#define KEEP_RC_SPI_ACTIVE_VAL 1
#define SRCLKEN_RC_EN_SEL_VAL 0
/* RC_CENTRAL_CFG1 settle time setting */
#define VCORE_SETTLE_TIME_VAL 0x7 /* ~= 200us */
#define ULPOSC_SETTLE_TIME_VAL 0x4 /* ~= ? 150us */
#define NON_DCXO_SETTLE_TIME_VAL 0x1 /* 2^(step+5)*0x33*30.77ns~=400us */
#define DCXO_SETTLE_TIME_VAL 0x41 /* 2^(step+5)*0x87*30.77ns~= 1063us */
/* RC_CENTRAL_CFG2[8] */
#define SRCLKENAO_MODE 0
#define VREQ_MODE 1
/* RC_CENTRAL_CFG2[25] */
#define RC_32K 0
#define RC_ULPOSC1 1
/* Signal Control Mode */
#define MERGE_OR_MODE 0x0
#define BYPASS_MODE 0x1
#define MERGE_AND_MODE BIT(1)
#define BYPASS_RC_MODE (0x2 << 1)
#define BYPASS_OR_MODE 0x3
#define BYPASS_OTHER_MODE (0x3 << 1)
#define ASYNC_MODE BIT(3)
#define NO_REQ 0
#define SW_SRCLKEN_BBLPM_MSK 0x1
#define FPM_REQ BIT(4)
#define BBLPM_REQ BIT(5)
#define SW_SRCLKEN_FPM_MSK 0x1
/* use srlckenao to set vcore */
#define SPI_TRIG_MODE SRCLKENAO_MODE
/* release vcore when spi request done */
#define IS_SPI_DONE_RELEASE 0
/* pmic spec under 200us */
#define SPI_CLK_SRC RC_32K
/* RC_CENTRAL_CFG2 control mode */
/* merge with vreq */
#define VREQ_CTRL_M BYPASS_MODE
/* merge with ulposc */
#define ULPOSC_CTRL_M_VAL BYPASS_MODE
/* merge with pwrap_scp */
#define PWRAP_CTRL_M MERGE_OR_MODE
/* RC_DCXO_FPM_CFG*/
#define MD0_SRCLKENO_0_MASK_B 0
#define FULL_SET_HW_MODE 0
/* RC_DCXO_FPM_CFG control mode*/
/* merge with spm */
#define DCXO_FPM_CTRL_MODE (MERGE_OR_MODE | ASYNC_MODE)
/* RC_CENTRAL_CFG5 */
#define RC_SPMI_BYTE_LEN 0x1
#define PMIC_GROUP_ID 0xB
/* MXX_SRCLKEN_CFG settle time setting */
#define CENTROL_CNT_STEP 0x3 /* Fix in 3 */
#define DCXO_STABLE_TIME 0x70 /* ~= 700us */
#define XO_DEFAULT_STABLE_TIME 0x29 /* ~= 400us */
#define XO_MD0_STABLE_TIME 0x15 /* ~= 200us */
#define XO_MD1_STABLE_TIME 0x15 /* ~= 200us */
#define XO_MDRF_STABLE_TIME 0x3D /* ~= 600us */
enum {
SW_BBLPM_LOW,
SW_BBLPM_HIGH,
};
enum {
SW_FPM_LOW,
SW_FPM_HIGH,
};
enum {
DXCO_SETTLE_BLK_DIS,
DXCO_SETTLE_BLK_EN,
};
enum {
REQ_ACK_IMD_DIS,
REQ_ACK_IMD_EN,
};
struct rc_config {
bool disabled;
bool lpm;
bool hw_mode;
};
enum rc_ctrl_m {
HW_MODE = 0,
SW_MODE = 1,
INIT_MODE = 0xff,
};
enum {
SRLCKEN_RC_BRINGUP = 0,
SRCLKEN_RC_DISABLE,
SRCLKEN_RC_ENABLE,
SRCLKEN_RC_SKIP,
};
struct subsys_rc_con {
u32 dcxo_prd;
u32 xo_prd;
u32 cnt_step;
u32 track_en;
u32 req_ack_imd_en;
u32 xo_soc_link_en;
u32 sw_bblpm;
u32 sw_fpm;
u32 sw_rc;
u32 bypass_cmd;
u32 dcxo_settle_blk_en;
};
#define SUB_CTRL_CON(_id, _dcxo_prd, _xo_prd, \
_sw_bblpm, _sw_fpm, _sw_rc, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en) \
[_id] = { \
.dcxo_prd = _dcxo_prd, \
.xo_prd = _xo_prd, \
.cnt_step = CENTROL_CNT_STEP, \
.track_en = 0x0, \
.req_ack_imd_en = _req_ack_imd_en, \
.xo_soc_link_en = 0x0, \
.sw_bblpm = _sw_bblpm, \
.sw_fpm = _sw_fpm, \
.sw_rc = _sw_rc, \
.bypass_cmd = _bypass_cmd, \
.dcxo_settle_blk_en = _dcxo_settle_blk_en, \
}
/* Init as SW FPM mode */
#define SUB_CTRL_CON_INIT(_id, _dcxo_prd, _xo_prd, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en) \
SUB_CTRL_CON(_id, _dcxo_prd, _xo_prd, \
SW_BBLPM_LOW, SW_FPM_HIGH, SW_MODE, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en)
/* Init as SW LPM mode */
#define SUB_CTRL_CON_NO_INIT(_id, _dcxo_prd, _xo_prd, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en) \
SUB_CTRL_CON(_id, _dcxo_prd, _xo_prd, \
SW_BBLPM_LOW, SW_FPM_LOW, SW_MODE, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en)
/* Normal init, SW FPM mode */
#define SUB_CTRL_CON_EN(_id, _xo_prd, _req_ack_imd_en) \
SUB_CTRL_CON_INIT(_id, \
DCXO_STABLE_TIME, _xo_prd, \
_req_ack_imd_en, 0, DXCO_SETTLE_BLK_EN)
extern const struct rc_config rc_config[];
extern const size_t rc_config_num;
void rc_init_subsys_hw_mode(void);
void rc_init_subsys_lpm(void);
int srclken_rc_init(void);
#endif /* SOC_MEDIATEK_COMMON_SRCLKEN_RC_H */

View file

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
#include <assert.h>
#include <console/console.h>
#include <delay.h>
#include <device/mmio.h>
#include <soc/addressmap.h>
#include <soc/clkbuf_ctl.h>
#include <soc/pmif.h>
#include <soc/pmif_common.h>
#include <soc/spmi.h>
#include <soc/srclken_rc.h>
#include <soc/srclken_rc_common.h>
#include <timer.h>
/* RC initial flow and relative setting */
static void rc_ctrl_mode_switch(enum chn_id id, enum rc_ctrl_m mode)
{
assert(id < ARRAY_SIZE(rc_regs->rc_mxx_srclken_cfg));
int cfg = (mode == SW_MODE);
SET32_BITFIELDS(&rc_regs->rc_mxx_srclken_cfg[id], SW_SRCLKEN_RC, cfg);
printk(BIOS_INFO, "M0%d: 0x%x\n", id, read32(&rc_regs->rc_mxx_srclken_cfg[id]));
}
/* RC subsys FPM control */
static void rc_ctrl_fpm_switch(enum chn_id id, u32 mode)
{
assert(id < ARRAY_SIZE(rc_regs->rc_mxx_srclken_cfg));
assert(mode == SW_FPM_HIGH || mode == SW_FPM_LOW);
int fpm = (mode == SW_FPM_HIGH) ? 1 : 0;
SET32_BITFIELDS(&rc_regs->rc_mxx_srclken_cfg[id], SW_SRCLKEN_FPM, fpm);
printk(BIOS_INFO, "M0%d FPM SWITCH: %#x\n", id,
read32(&rc_regs->rc_mxx_srclken_cfg[id]));
}
void rc_init_subsys_hw_mode(void)
{
int chn_n;
for (chn_n = 0; chn_n < MAX_CHN_NUM; chn_n++) {
if (rc_config[chn_n].hw_mode)
rc_ctrl_mode_switch(chn_n, HW_MODE);
}
}
void rc_init_subsys_lpm(void)
{
int chn_n;
for (chn_n = 0; chn_n < MAX_CHN_NUM; chn_n++) {
if (rc_config[chn_n].lpm)
rc_ctrl_fpm_switch(chn_n, SW_FPM_LOW);
}
}

View file

@ -49,7 +49,7 @@ romstage-y += ../common/pmif_clk.c pmif_clk.c
romstage-y += ../common/pmif.c pmif_init.c
romstage-y += ../common/rtc.c ../common/rtc_osc_init.c
romstage-y += ../common/pmif_spmi_v2.c pmif_spmi.c
romstage-y += srclken_rc.c
romstage-y += ../common/srclken_rc.c srclken_rc.c
romstage-y += thermal.c
romstage-y += thermal_sram.c

View file

@ -3,6 +3,9 @@
#ifndef __SOC_MEDIATEK_MT8196_INCLUDE_SOC_SRCLKEN_RC_H__
#define __SOC_MEDIATEK_MT8196_INCLUDE_SOC_SRCLKEN_RC_H__
#include <soc/addressmap.h>
#include <soc/srclken_rc_common.h>
/* Channel id: Update this enum for porting */
enum chn_id {
CHN_SUSPEND = 0,
@ -187,58 +190,6 @@ DEFINE_BIT(BBLPM_ACK, 3)
DEFINE_BITFIELD(BYPASS_DCXO_VOTE_H, 31, 16)
DEFINE_BITFIELD(BYPASS_DCXO_VOTE_L, 15, 0)
enum {
SW_SRCLKEN_FPM_MSK = 0x1,
SW_SRCLKEN_BBLPM_MSK = 0x1,
};
/* RC_CENTRAL_CFG2[8] */
#define SRCLKENAO_MODE 0
#define VREQ_MODE 1
/* RC_CENTRAL_CFG2[25] */
#define RC_32K 0
#define RC_ULPOSC1 1
/* Signal Control Mode */
#define MERGE_OR_MODE 0x0
#define BYPASS_MODE 0x1
#define MERGE_AND_MODE BIT(1)
#define BYPASS_RC_MODE (0x2 << 1)
#define BYPASS_OR_MODE 0x3
#define BYPASS_OTHER_MODE (0x3 << 1)
#define ASYNC_MODE BIT(3)
#define NO_REQ 0
#define FPM_REQ BIT(4)
#define BBLPM_REQ BIT(5)
enum rc_ctrl_m {
HW_MODE = 0,
SW_MODE = 1,
};
enum {
SRLCKEN_RC_BRINGUP = 0,
SRCLKEN_RC_DISABLE,
SRCLKEN_RC_ENABLE,
SRCLKEN_RC_SKIP,
};
struct subsys_rc_con {
u32 dcxo_prd;
u32 xo_prd;
u32 cnt_step;
u32 track_en;
u32 req_ack_imd_en;
u32 xo_soc_link_en;
u32 sw_bblpm;
u32 sw_fpm;
u32 sw_rc;
u32 bypass_cmd;
u32 dcxo_settle_blk_en;
};
int srclken_rc_init(void);
static struct mtk_rc_regs *const rc_regs = (void *)RC_BASE;
#endif

View file

@ -12,53 +12,8 @@
#include <soc/srclken_rc.h>
#include <timer.h>
static struct mtk_rc_regs *rc_regs = (struct mtk_rc_regs *)RC_BASE;
#define ACK_DELAY_US 10
#define ACK_DELAY_TIMES 200
/* RC_CENTRAL_CFG1 setting */
#define RC_CENTRAL_ENABLE_VAL 1
#define RC_CENTRAL_DISABLE_VAL 0
/* register direct write */
#define IS_SPI2PMIC_SET_CLR_VAL 0
#define KEEP_RC_SPI_ACTIVE_VAL 1
#define SRCLKEN_RC_EN_SEL_VAL 0
/* RC_CENTRAL_CFG1 settle time setting */
#define VCORE_SETTLE_TIME_VAL 0x7 /* ~= 200us */
#define ULPOSC_SETTLE_TIME_VAL 0x4 /* ~= ? 150us */
#define NON_DCXO_SETTLE_TIME_VAL 0x1 /* 2^(step+5)*0x33*30.77ns ~= 400us */
#define DCXO_SETTLE_TIME_VAL 0x41 /* 2^(step+5)*0x87*30.77ns ~= 1063us */
/* RC_CENTRAL_CFG2 setting */
/* use srlckenao to set vcore */
#define SPI_TRIG_MODE SRCLKENAO_MODE
/* release vcore when spi request done */
#define IS_SPI_DONE_RELEASE 0
/* pmic spec under 200us */
#define SPI_CLK_SRC RC_32K
/* RC_CENTRAL_CFG2 control mode */
/* merge with spm */
#define SRCLKENO_0_CTRL_M BYPASS_MODE
/* merge with vreq */
#define VREQ_CTRL_M BYPASS_MODE
/* merge with ulposc */
#define ULPOSC_CTRL_M_VAL BYPASS_MODE
/* merge with pwrap_scp */
#define PWRAP_CTRL_M MERGE_OR_MODE
/* RC_DCXO_FPM_CFG*/
#define MD0_SRCLKENO_0_MASK_B 0 /* md0 control by pmrc */
#define FULL_SET_HW_MODE 0 /* dcxo mode use pmrc_en */
/* RC_DCXO_FPM_CFG control mode*/
/* merge with spm */
#define DCXO_FPM_CTRL_MODE (MERGE_OR_MODE | ASYNC_MODE)
/* RC_CENTRAL_CFG5 */
#define RC_SPMI_BYTE_LEN 0x1 /* 0: 2bytes, 1: 2 * 2bytes */
#define PMIC_GROUP_ID 0xB
/* pmrc_en address */
/* default use this reg direct write */
@ -66,68 +21,6 @@ static struct mtk_rc_regs *rc_regs = (struct mtk_rc_regs *)RC_BASE;
#define PMRC_CON0_SET 0x198
#define PMRC_CON0_CLR 0x19A
enum {
SW_BBLPM_LOW,
SW_BBLPM_HIGH,
};
enum {
SW_FPM_LOW,
SW_FPM_HIGH,
};
enum {
DXCO_SETTLE_BLK_DIS,
DXCO_SETTLE_BLK_EN,
};
enum {
REQ_ACK_IMD_DIS,
REQ_ACK_IMD_EN,
};
#define SUB_CTRL_CON(_id, _dcxo_prd, _xo_prd, \
_sw_bblpm, _sw_fpm, _sw_rc, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en) \
[_id] = { \
.dcxo_prd = _dcxo_prd, \
.xo_prd = _xo_prd, \
.cnt_step = CENTROL_CNT_STEP, \
.track_en = 0, \
.req_ack_imd_en = _req_ack_imd_en, \
.xo_soc_link_en = 0, \
.sw_bblpm = _sw_bblpm, \
.sw_fpm = _sw_fpm, \
.sw_rc = _sw_rc, \
.bypass_cmd = _bypass_cmd, \
.dcxo_settle_blk_en = _dcxo_settle_blk_en, \
}
/* Init as SW FPM mode */
#define SUB_CTRL_CON_INIT(_id, _dcxo_prd, _xo_prd, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en) \
SUB_CTRL_CON(_id, _dcxo_prd, _xo_prd, \
SW_BBLPM_LOW, SW_FPM_HIGH, SW_MODE, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en)
/* Init as SW LPM mode */
#define SUB_CTRL_CON_NO_INIT(_id, _dcxo_prd, _xo_prd, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en) \
SUB_CTRL_CON(_id, _dcxo_prd, _xo_prd, \
SW_BBLPM_LOW, SW_FPM_LOW, SW_MODE, \
_req_ack_imd_en, _bypass_cmd, \
_dcxo_settle_blk_en)
/* Normal init, SW FPM mode */
#define SUB_CTRL_CON_EN(_id, _xo_prd, _req_ack_imd_en) \
SUB_CTRL_CON_INIT(_id, \
DCXO_STABLE_TIME, _xo_prd, \
_req_ack_imd_en, 0, DXCO_SETTLE_BLK_EN)
/* XO/DCXO settle time=0, bypass cmd */
#define SUB_CTRL_CON_DIS(_id) \
SUB_CTRL_CON_INIT(_id, \
@ -141,14 +34,7 @@ enum {
REQ_ACK_IMD_EN, 0, DXCO_SETTLE_BLK_EN)
/* Porting starting from here */
/* MXX_SRCLKEN_CFG settle time setting */
#define CENTROL_CNT_STEP 0x3 /* Fix in 3 */
#define DCXO_STABLE_TIME 0x70 /* ~= 700us */
#define XO_DEFAULT_STABLE_TIME 0x29 /* ~= 400us */
#define XO_MD0_STABLE_TIME 0x15 /* ~= 200us */
#define XO_MD1_STABLE_TIME 0x15 /* ~= 200us */
#define XO_MD2_STABLE_TIME 0x33 /* ~= 500us */
#define XO_MDRF_STABLE_TIME 0x3D /* ~= 600us */
#define VCORE_STABLE_TIME 0x15 /* ~= 200us */
/* SUBSYS_INTF_CFG_FPM */
@ -167,25 +53,21 @@ enum {
#define SUBSYS_EN_H 0x0000
/* First try to switch fpm. After polling ack done, switch to HW mode */
static const struct {
bool disabled;
bool lpm;
bool hw_mode;
} rc_config[MAX_CHN_NUM] = {
[CHN_SUSPEND] = { .lpm = false, .hw_mode = true },
[CHN_MD1] = { .lpm = false, .hw_mode = true },
[CHN_MD2] = { .lpm = false, .hw_mode = true },
[CHN_MD3] = { .lpm = false, .hw_mode = true },
[CHN_MDRF] = { .lpm = false, .hw_mode = true },
[CHN_MMWAVE] = { .lpm = false, .hw_mode = true },
const struct rc_config rc_config[MAX_CHN_NUM] = {
[CHN_SUSPEND] = { .hw_mode = true },
[CHN_MD1] = { .hw_mode = true },
[CHN_MD2] = { .hw_mode = true },
[CHN_MD3] = { .hw_mode = true },
[CHN_MDRF] = { .hw_mode = true },
[CHN_MMWAVE] = { .hw_mode = true },
[CHN_GPS] = { .lpm = true, .hw_mode = true },
[CHN_PCIE_CONN1] = { .lpm = false, .hw_mode = true },
[CHN_VCORE] = { .lpm = true, .hw_mode = false },
[CHN_PCIE_CONN1] = { .hw_mode = true },
[CHN_VCORE] = { .lpm = true },
[CHN_CONN_MCU] = { .lpm = true, .hw_mode = true },
[CHN_COANT] = { .lpm = true, .hw_mode = true },
[CHN_NFC_CONN2] = { .lpm = true, .hw_mode = true },
[CHN_SUSPEND2] = { .lpm = false, .hw_mode = true },
[CHN_UFS_VREQ] = { .lpm = false, .hw_mode = true },
[CHN_SUSPEND2] = { .hw_mode = true },
[CHN_UFS_VREQ] = { .hw_mode = true },
[CHN_DCXO_L] = { .disabled = true },
[CHN_DCXO_H] = { .disabled = true },
[CHN_UFS_2] = {},
@ -206,7 +88,7 @@ static const struct {
[CHN_RSV9] = {},
};
static const struct subsys_rc_con rc_ctrl[MAX_CHN_NUM] = {
const struct subsys_rc_con rc_ctrl[MAX_CHN_NUM] = {
SUB_CTRL_CON_EN(CHN_SUSPEND, XO_DEFAULT_STABLE_TIME, REQ_ACK_IMD_EN),
/* CFG[2] = 0x1 for bypass waiting DCXO settle time */
/* Usually also need to set CFG6_2 not involve FPM vote */
@ -296,38 +178,6 @@ static void rc_dump_reg_info(void)
printk(BIOS_INFO, "RC_PI_PO_STA:%#x\n", read32(&rc_regs->rc_pi_po_sta));
}
/* RC initial flow and relative setting */
static void rc_ctrl_mode_switch(enum chn_id id, enum rc_ctrl_m mode)
{
assert(id < MAX_CHN_NUM);
switch (mode) {
case SW_MODE:
SET32_BITFIELDS(&rc_regs->rc_mxx_srclken_cfg[id], SW_SRCLKEN_RC, 1);
break;
case HW_MODE:
SET32_BITFIELDS(&rc_regs->rc_mxx_srclken_cfg[id], SW_SRCLKEN_RC, 0);
break;
default:
return;
}
printk(BIOS_INFO, "M0%d: %#x\n", id, read32(&rc_regs->rc_mxx_srclken_cfg[id]));
}
/* RC subsys FPM control*/
static void rc_ctrl_fpm_switch(enum chn_id id, u32 mode)
{
assert(id < MAX_CHN_NUM);
assert(mode == SW_FPM_HIGH || mode == SW_FPM_LOW);
int fpm = (mode == SW_FPM_HIGH) ? 1 : 0;
SET32_BITFIELDS(&rc_regs->rc_mxx_srclken_cfg[id], SW_SRCLKEN_FPM, fpm);
printk(BIOS_INFO, "M0%d FPM SWITCH: %#x\n", id,
read32(&rc_regs->rc_mxx_srclken_cfg[id]));
}
static void rc_ctrl_mode_init(void)
{
u32 ch;
@ -352,30 +202,6 @@ static void rc_ctrl_mode_init(void)
}
}
static void rc_init_subsys_lpm(void)
{
u32 ch;
for (ch = 0; ch < MAX_CHN_NUM; ch++) {
if (rc_config[ch].disabled)
continue;
if (rc_config[ch].lpm)
rc_ctrl_fpm_switch(ch, SW_FPM_LOW);
}
}
static void rc_init_subsys_hw_mode(void)
{
u32 ch;
for (ch = 0; ch < MAX_CHN_NUM; ch++) {
if (rc_config[ch].disabled)
continue;
if (rc_config[ch].hw_mode)
rc_ctrl_mode_switch(ch, HW_MODE);
}
}
static int polling_rc_chn_ack(enum chn_id id, u32 mask, u32 value)
{
if (!retry(ACK_DELAY_TIMES,