Hello hsin-hsiung wang,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/45398
to review the following change.
Change subject: soc/mediatek/mt8192: add pmif driver ......................................................................
soc/mediatek/mt8192: add pmif driver
MT8192 uses power management interface(PMIF) to access pmics by spmi and spi, so we add pmif driver to control pmics.
TEST=Boots correctly on MT8192EVB.
Signed-off-by: Hsin-Hsiung Wang hsin-hsiung.wang@mediatek.com Change-Id: I32fc28f72d9522133baa06f9d67c383f814d862c --- M src/soc/mediatek/mt8192/Makefile.inc M src/soc/mediatek/mt8192/bootblock.c M src/soc/mediatek/mt8192/include/soc/addressmap.h M src/soc/mediatek/mt8192/include/soc/pll.h A src/soc/mediatek/mt8192/include/soc/pmif.h A src/soc/mediatek/mt8192/include/soc/pmif_spi.h A src/soc/mediatek/mt8192/include/soc/pmif_spmi.h A src/soc/mediatek/mt8192/include/soc/pmif_sw.h A src/soc/mediatek/mt8192/include/soc/spmi.h A src/soc/mediatek/mt8192/pmif.c A src/soc/mediatek/mt8192/pmif_clk.c A src/soc/mediatek/mt8192/pmif_spi.c A src/soc/mediatek/mt8192/pmif_spmi.c 13 files changed, 1,550 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/98/45398/1
diff --git a/src/soc/mediatek/mt8192/Makefile.inc b/src/soc/mediatek/mt8192/Makefile.inc index 533eae2..0fc47c4 100755 --- a/src/soc/mediatek/mt8192/Makefile.inc +++ b/src/soc/mediatek/mt8192/Makefile.inc @@ -9,6 +9,7 @@ bootblock-y += ../common/timer.c bootblock-y += ../common/uart.c bootblock-y += ../common/wdt.c +bootblock-y += pmif.c pmif_clk.c pmif_spi.c pmif_spmi.c
verstage-y += flash_controller.c verstage-y += ../common/gpio.c gpio.c diff --git a/src/soc/mediatek/mt8192/bootblock.c b/src/soc/mediatek/mt8192/bootblock.c index 8dffe56..0852f0e 100644 --- a/src/soc/mediatek/mt8192/bootblock.c +++ b/src/soc/mediatek/mt8192/bootblock.c @@ -3,6 +3,7 @@ #include <bootblock_common.h> #include <soc/mmu_operations.h> #include <soc/pll.h> +#include <soc/pmif.h> #include <soc/wdt.h>
void bootblock_soc_init(void) @@ -10,4 +11,5 @@ mtk_mmu_init(); mtk_wdt_init(); mt_pll_init(); + mtk_pmif_init(); } diff --git a/src/soc/mediatek/mt8192/include/soc/addressmap.h b/src/soc/mediatek/mt8192/include/soc/addressmap.h index e0cd536..e9cb788 100644 --- a/src/soc/mediatek/mt8192/include/soc/addressmap.h +++ b/src/soc/mediatek/mt8192/include/soc/addressmap.h @@ -21,7 +21,11 @@ GPT_BASE = IO_PHYS + 0x00008000, EINT_BASE = IO_PHYS + 0x0000B000, APMIXED_BASE = IO_PHYS + 0x0000C000, - PWRAP_BASE = IO_PHYS + 0x0000D000, + MODEM_TEMP_SHARE_BASE = IO_PHYS + 0x00018000, + PMIF_SPI_BASE = IO_PHYS + 0x00026000, + PMIF_SPMI_BASE = IO_PHYS + 0x00027000, + PMICSPI_MST_BASE = IO_PHYS + 0x00028000, + SPMI_MST_BASE = IO_PHYS + 0x00029000, UART0_BASE = IO_PHYS + 0x01002000, SPI0_BASE = IO_PHYS + 0x0100A000, SPI1_BASE = IO_PHYS + 0x01010000, diff --git a/src/soc/mediatek/mt8192/include/soc/pll.h b/src/soc/mediatek/mt8192/include/soc/pll.h index 442aa30..c83436e 100644 --- a/src/soc/mediatek/mt8192/include/soc/pll.h +++ b/src/soc/mediatek/mt8192/include/soc/pll.h @@ -178,7 +178,11 @@ u32 mfgpll_con2; u32 mfgpll_con3; u32 ap_pllgp1_con2; - u32 reserved2[33]; + u32 reserved2[13]; + u32 ulposc1_con0; + u32 ulposc1_con1; + u32 ulposc1_con2; + u32 reserved3[17]; u32 ap_pllgp2_con0; /* 0x0300 */ u32 ap_pllgp2_con1; u32 univpll_con0; diff --git a/src/soc/mediatek/mt8192/include/soc/pmif.h b/src/soc/mediatek/mt8192/include/soc/pmif.h new file mode 100644 index 0000000..6106a3d --- /dev/null +++ b/src/soc/mediatek/mt8192/include/soc/pmif.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __MT8192_SOC_PMIF_H__ +#define __MT8192_SOC_PMIF_H__ + +#include <types.h> + +enum { + PMIF_CMD_REG_0, + PMIF_CMD_REG, + PMIF_CMD_EXT_REG, + PMIF_CMD_EXT_REG_LONG, +}; + +struct mtk_pmif_regs { + u32 init_done; + u32 reserved1[5]; + u32 inf_busy_sta; + u32 other_busy_sta_0; + u32 other_busy_sta_1; + u32 inf_en; + u32 other_inf_en; + u32 inf_cmd_per_0; + u32 inf_cmd_per_1; + u32 inf_cmd_per_2; + u32 inf_cmd_per_3; + u32 inf_max_bytecnt_per_0; + u32 inf_max_bytecnt_per_1; + u32 inf_max_bytecnt_per_2; + u32 inf_max_bytecnt_per_3; + u32 staupd_ctrl; + u32 reserved2[48]; + u32 int_gps_auxadc_cmd_addr; + u32 int_gps_auxadc_cmd; + u32 int_gps_auxadc_rdata_addr; + u32 reserved3[13]; + u32 arb_en; + u32 reserved4[34]; + u32 lat_cnter_en; + u32 lat_limit_loading; + u32 lat_limit_0; + u32 lat_limit_1; + u32 lat_limit_2; + u32 lat_limit_3; + u32 lat_limit_4; + u32 lat_limit_5; + u32 lat_limit_6; + u32 lat_limit_7; + u32 lat_limit_8; + u32 lat_limit_9; + u32 reserved5[99]; + u32 crc_ctrl; + u32 crc_sta; + u32 sig_mode; + u32 pmic_sig_addr; + u32 pmic_sig_val; + u32 reserved6[2]; + u32 cmdissue_en; + u32 reserved7[10]; + u32 timer_ctrl; + u32 timer_sta; + u32 sleep_protection_ctrl; + u32 reserved8[5]; + u32 spi_mode_ctrl; + u32 reserved9[2]; + u32 pmic_eint_sta_addr; + u32 reserved10[2]; + u32 irq_event_en_0; + u32 irq_flag_raw_0; + u32 irq_flag_0; + u32 irq_clr_0; + u32 reserved11[502]; + u32 swinf_0_acc; + u32 swinf_0_wdata_31_0; + u32 swinf_0_wdata_63_32; + u32 reserved12[2]; + u32 swinf_0_rdata_31_0; + u32 swinf_0_rdata_63_32; + u32 reserved13[2]; + u32 swinf_0_vld_clr; + u32 swinf_0_sta; + u32 reserved14[5]; + u32 swinf_1_acc; + u32 swinf_1_wdata_31_0; + u32 swinf_1_wdata_63_32; + u32 reserved15[2]; + u32 swinf_1_rdata_31_0; + u32 swinf_1_rdata_63_32; + u32 reserved16[2]; + u32 swinf_1_vld_clr; + u32 swinf_1_sta; + u32 reserved17[5]; + u32 swinf_2_acc; + u32 swinf_2_wdata_31_0; + u32 swinf_2_wdata_63_32; + u32 reserved18[2]; + u32 swinf_2_rdata_31_0; + u32 swinf_2_rdata_63_32; + u32 reserved19[2]; + u32 swinf_2_vld_clr; + u32 swinf_2_sta; + u32 reserved20[5]; + u32 swinf_3_acc; + u32 swinf_3_wdata_31_0; + u32 swinf_3_wdata_63_32; + u32 reserved21[2]; + u32 swinf_3_rdata_31_0; + u32 swinf_3_rdata_63_32; + u32 reserved22[2]; + u32 swinf_3_vld_clr; + u32 swinf_3_sta; + u32 reserved23[133]; +}; + +check_member(mtk_pmif_regs, inf_busy_sta, 0x18); +check_member(mtk_pmif_regs, int_gps_auxadc_cmd_addr, 0x110); +check_member(mtk_pmif_regs, arb_en, 0x0150); +check_member(mtk_pmif_regs, lat_cnter_en, 0x1DC); +check_member(mtk_pmif_regs, crc_ctrl, 0x398); +check_member(mtk_pmif_regs, cmdissue_en, 0x3B4); +check_member(mtk_pmif_regs, timer_ctrl, 0x3E0); +check_member(mtk_pmif_regs, spi_mode_ctrl, 0x400); +check_member(mtk_pmif_regs, pmic_eint_sta_addr, 0x40C); +check_member(mtk_pmif_regs, irq_event_en_0, 0x418); +check_member(mtk_pmif_regs, swinf_0_acc, 0xC00); + +struct pmif { + struct mtk_pmif_regs *mtk_pmif; + int swinf_ch_start; + int swinf_no; + int mstid; + int pmifid; + int (*read_cmd)(struct pmif *arb, unsigned int slvid, + unsigned int addr, unsigned int *rdata); + int (*write_cmd)(struct pmif *arb, unsigned int slvid, + unsigned int addr, unsigned int wdata); + int (*is_pmif_init_done)(struct pmif *arb); +}; + +enum { + PMIF_SPI, + PMIF_SPMI, +}; + +enum { + E_IO = 1, /* I/O error */ + E_BUSY, /* Device or resource busy */ + E_NODEV, /* No such device */ + E_INVAL, /* Invalid argument */ + E_OPNOTSUPP, /* Operation not supported on transport endpoint */ + E_TIMEOUT, /* Wait for idle time out */ + E_READ_TEST_FAIL, /* SPI read fail */ + E_SPI_INIT_RESET_SPI, /* reset SPI fail */ + E_SPI_INIT_SIDLY, /* SPI edge calibration fail */ +}; + +/* start external API */ +extern struct pmif *get_pmif_controller(int inf, int mstid); +extern int mtk_pmif_init(void); +#endif /*__MT8192_SOC_PMIF_H__*/ diff --git a/src/soc/mediatek/mt8192/include/soc/pmif_spi.h b/src/soc/mediatek/mt8192/include/soc/pmif_spi.h new file mode 100644 index 0000000..606dbbd --- /dev/null +++ b/src/soc/mediatek/mt8192/include/soc/pmif_spi.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8192_PMIC_WRAP_H__ +#define __SOC_MEDIATEK_MT8192_PMIC_WRAP_H__ + +#include <soc/addressmap.h> +#include <types.h> + +struct mt8192_pmicspi_mst_regs { + u32 reserved1[4]; + u32 other_busy_sta_0; + u32 wrap_en; + u32 reserved2[2]; + u32 man_en; + u32 man_acc; + u32 reserved3[3]; + u32 mux_sel; + u32 reserved4[3]; + u32 dio_en; + u32 rddmy; + u32 cslext_write; + u32 cslext_read; + u32 cshext_write; + u32 cshext_read; + u32 ext_ck_write; + u32 ext_ck_read; + u32 si_sampling_ctrl; +}; + +check_member(mt8192_pmicspi_mst_regs, other_busy_sta_0, 0x10); +check_member(mt8192_pmicspi_mst_regs, man_en, 0x20); +check_member(mt8192_pmicspi_mst_regs, mux_sel, 0x34); +check_member(mt8192_pmicspi_mst_regs, dio_en, 0x44); + +static struct mt8192_pmicspi_mst_regs * const mtk_pmicspi_mst = (void *)PMICSPI_MST_BASE; + +struct mtk_iocfg_tl_regs { + u32 drv_cfg0; + u32 drv_cfg0_set; + u32 drv_cfg0_clr; +}; +check_member(mtk_iocfg_tl_regs, drv_cfg0_set, 0x4); +check_member(mtk_iocfg_tl_regs, drv_cfg0_clr, 0x8); + +#define mtk_iocfg_tl ((struct mtk_iocfg_tl_regs *)IOCFG_TL_BASE) + +struct mtk_modem_temp_share_regs { + u32 ctrl; +}; + +#define mtk_modem_temp_share ((struct mtk_modem_temp_share_regs *)SPM_BASE) + +/* PMIC registers */ +enum { + PMIC_BASE = 0x0000, + PMIC_SMT_CON1 = PMIC_BASE + 0x0032, + PMIC_DRV_CON1 = PMIC_BASE + 0x003a, + PMIC_FILTER_CON0 = PMIC_BASE + 0x0042, + PMIC_GPIO_PULLEN0_CLR = PMIC_BASE + 0x0098, + PMIC_RG_SPI_CON0 = PMIC_BASE + 0x0408, + PMIC_DEW_DIO_EN = PMIC_BASE + 0x040c, + PMIC_DEW_READ_TEST = PMIC_BASE + 0x040e, + PMIC_DEW_WRITE_TEST = PMIC_BASE + 0x0410, + PMIC_DEW_CRC_EN = PMIC_BASE + 0x0414, + PMIC_DEW_CRC_VAL = PMIC_BASE + 0x0416, + PMIC_DEW_RDDMY_NO = PMIC_BASE + 0x0424, + PMIC_RG_SPI_CON2 = PMIC_BASE + 0x0426, + PMIC_SPISLV_KEY = PMIC_BASE + 0x044a, + PMIC_INT_STA = PMIC_BASE + 0x0452, + PMIC_AUXADC_ADC7 = PMIC_BASE + 0x1096, + PMIC_AUXADC_ADC10 = PMIC_BASE + 0x109c, + PMIC_AUXADC_RQST0 = PMIC_BASE + 0x1108, +}; + +#define PMIF_SPI_MD_SWINF_NO 0 +#define PMIF_SPI_AP_SECURE_SWINF_NO 1 +#define PMIF_SPI_AP_SWINF_NO 2 +#define PMIF_SPI_SWINF_0_CHAN_NO 8 +#define PMIF_SPI_MD_SWINF_CHAN_NO BIT(PMIF_SPI_SWINF_0_CHAN_NO + PMIF_SPI_MD_SWINF_NO) +#define PMIF_SPI_AP_SECURE_SWINF_CHAN_NO BIT(PMIF_SPI_SWINF_0_CHAN_NO + PMIF_SPI_AP_SECURE_SWINF_NO) +#define PMIF_SPI_AP_SWINF_CHAN_NO BIT(PMIF_SPI_SWINF_0_CHAN_NO + PMIF_SPI_AP_SWINF_NO) + +#define DEFAULT_SLVID 0 + +#define GET_PMICSPI_BUSY(x) ((x>>9) & 0x00000001) +#define GET_CMDISSUE_BUSY(x) ((x>>2) & 0x00000001) + +enum { + SPI_CLK = 0x1, + SPI_CSN = 0x1 << 1, + SPI_MOSI = 0x1 << 2, + SPI_MISO = 0x1 << 3, + SPI_FILTER = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO) << 4, + SPI_SMT = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO), + SPI_PULL_DISABLE = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO) << 4, +}; + +enum { + IO_4_MA = 0x8, +}; + +enum { + SPI_CLK_SHIFT = 0, + SPI_CSN_SHIFT = 4, + SPI_MOSI_SHIFT = 8, + SPI_MISO_SHIFT = 12, + SPI_DRIVING = (IO_4_MA << SPI_CLK_SHIFT | IO_4_MA << SPI_CSN_SHIFT | + IO_4_MA << SPI_MOSI_SHIFT | IO_4_MA << SPI_MISO_SHIFT), +}; + +enum { + OP_WR = 0x1, + OP_CSH = 0x0, + OP_CSL = 0x1, + OP_OUTS = 0x8, +}; + +enum { + DEFAULT_VALUE_READ_TEST = 0x5aa5, + WRITE_TEST_VALUE = 0xa55a +}; + +enum { + DUMMY_READ_CYCLES = 0X8, +}; + +enum { + E_CLK_EDGE = 1, + E_CLK_LAST_SETTING +}; +extern int pmif_spi_init(struct pmif *arb); +#endif /* __SOC_MEDIATEK_MT8192_PMIC_WRAP_H__ */ diff --git a/src/soc/mediatek/mt8192/include/soc/pmif_spmi.h b/src/soc/mediatek/mt8192/include/soc/pmif_spmi.h new file mode 100644 index 0000000..5f89ddc --- /dev/null +++ b/src/soc/mediatek/mt8192/include/soc/pmif_spmi.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __PMIF_SPMI_H__ +#define __PMIF_SPMI_H__ + +#include <soc/addressmap.h> + +#define DEFAULT_VALUE_READ_TEST (0x5a) +#define DEFAULT_VALUE_WRITE_TEST (0xa5) + +#define GET_REC_CMD(x) (x & 0x00000003) +#define GET_REC_W(x) ((x>>2) & 0x00000001) +#define GET_REC_OP_ST_NACK(x) ((x>>3) & 0x00000001) +#define GET_REC_PMIF_NACK(x) ((x>>4) & 0x00000001) +#define GET_REC_PMIF_PARITY_ERR(x) ((x>>5) & 0x00000001) +#define GET_REC_PMIF_BYTE_ERR(x) ((x>>6) & 0x00000001) +#define GET_REC_PMIF_GRP_RD_ERR(x) ((x>>7) & 0x00000001) +#define GET_REC_SLVID(x) ((x>>8) & 0x0000000f) +#define GET_REC_BYTECNT(x) ((x>>12) & 0x0000000f) +#define GET_REC_ADDR(x) ((x>>16) & 0x0000ffff) + +/* + * GPIO number for IO driving config, + * These can be look up by platform/<mtxxxx>/src/drivers/inc/gpio_cfg.h + * must check by platform + */ +#define SPMI_SCL_GPIO 89 +#define SPMI_SDA_GPIO 90 +#define SPMI_SCL_DRV_SHIFT (3) +#define SPMI_SDA_DRV_SHIFT (6) + +#define SPMIMST_RST_SHIFT 4 +#define WDT_UNLOCK_SHIFT 24 + +#define WDT_UNLOCK_KEY 0x85 + +struct mtk_rgu_regs { + u32 reserved[36]; + u32 wdt_swsysrst2; +}; +check_member(mtk_rgu_regs, wdt_swsysrst2, 0x0090); + +struct mtk_iocfg_bm_regs { + u32 reserved[9]; + u32 drv_cfg2_set; + u32 drv_cfg2_clr; +}; +check_member(mtk_iocfg_bm_regs, drv_cfg2_set, 0x0024); +check_member(mtk_iocfg_bm_regs, drv_cfg2_clr, 0x0028); + +struct mtk_spm_regs { + u32 poweron_config_en; + u32 reserved[263]; + u32 ulposc_con; +}; +check_member(mtk_spm_regs, ulposc_con, 0x0420); + +struct mtk_spmi_mst_reg { + u32 op_st_ctrl; + u32 grp_id_en; + u32 op_st_sta; + u32 mst_sampl; + u32 mst_req_en; + u32 reserved1[11]; + u32 rec_ctrl; + u32 rec0; + u32 rec1; + u32 rec2; + u32 rec3; + u32 rec4; + u32 reserved2[41]; + u32 mst_dbg; +}; + +check_member(mtk_spmi_mst_reg, rec_ctrl, 0x40); +check_member(mtk_spmi_mst_reg, mst_dbg, 0xfc); + +#define mtk_rug ((struct mtk_rgu_regs *)RGU_BASE) +#define mtk_iocfg_bm ((struct mtk_iocfg_bm_regs *)IOCFG_BM_BASE) +#define mtk_spm ((struct mtk_spm_regs *)SPM_BASE) +#define mtk_spmi_mst ((struct mtk_spmi_mst_reg *)SPMI_MST_BASE) + +struct cali { + unsigned int dly; + unsigned int pol; +}; + +enum +{ + SPMI_CK_NO_DLY = 0, + SPMI_CK_DLY_1T +}; + +enum +{ + SPMI_CK_POL_NEG = 0, + SPMI_CK_POL_POS +}; + +enum +{ + SPMI_OP_ST_BUSY = 1, + SPMI_OP_ST_ACK = 0, + SPMI_OP_ST_NACK = 1 +}; + +enum +{ + SPMI_RCS_SR_BIT, + SPMI_RCS_A_BIT +}; + +enum +{ + SPMI_RCS_MST_W = 1, + SPMI_RCS_SLV_W = 3 +}; + +enum +{ + SPMI_RESET = 0, + SPMI_SLEEP, + SPMI_SHUTDOWN, + SPMI_WAKEUP +}; + +enum spmi_regs { + SPMI_OP_ST_CTRL, + SPMI_GRP_ID_EN, + SPMI_OP_ST_STA, + SPMI_MST_SAMPL, + SPMI_MST_REQ_EN, + SPMI_REC_CTRL, + SPMI_REC0, + SPMI_REC1, + SPMI_REC2, + SPMI_REC3, + SPMI_REC4, + SPMI_MST_DBG +}; + +extern int pmif_spmi_init(struct pmif *arb); +#endif /*__PMIF_SPMI_H__*/ diff --git a/src/soc/mediatek/mt8192/include/soc/pmif_sw.h b/src/soc/mediatek/mt8192/include/soc/pmif_sw.h new file mode 100644 index 0000000..1d250bf --- /dev/null +++ b/src/soc/mediatek/mt8192/include/soc/pmif_sw.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __PMIF_SW_H__ +#define __PMIF_SW_H__ + +/* Read/write byte limitation, by project */ +/* hw bytecnt indicate when we set 0, it can send 1 byte; + * set 1, it can send 2 byte. + */ +#define PMIF_BYTECNT_MAX 1 + +/* macro for SWINF_FSM */ +#define SWINF_FSM_IDLE (0x00) +#define SWINF_FSM_REQ (0x02) +#define SWINF_FSM_WFDLE (0x04) +#define SWINF_FSM_WFVLDCLR (0x06) +#define SWINF_INIT_DONE (0x01) + +/* indicate which number SW channel start, by project */ +#define PMIF_SWINF_0_CHAN_NO 4 + +/* MD: 0, security domain: 1, AP: 2 */ +#define PMIF_AP_SWINF_NO 2 + +#define GET_SWINF_0_FSM(x) ((x >> 1) & 0x7) + +struct pmif_mpu { + unsigned int rgn_slvid; + unsigned short rgn_s_addr; + unsigned short rgn_e_addr; + unsigned int rgn_domain_per; +}; + +enum { + PMIF_READ_US = 1000, + PMIF_WAIT_IDLE_US = 1000, +}; +extern int pmif_clk_init(void); +#endif /*__PMIF_SW_H__*/ diff --git a/src/soc/mediatek/mt8192/include/soc/spmi.h b/src/soc/mediatek/mt8192/include/soc/spmi.h new file mode 100644 index 0000000..61e49b5 --- /dev/null +++ b/src/soc/mediatek/mt8192/include/soc/spmi.h @@ -0,0 +1,78 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2020 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 __SPMI_H__ +#define __SPMI_H__ + +/* enum marco for cmd/channel */ +enum spmi_master +{ + SPMI_MASTER_0, + SPMI_MASTER_1, + SPMI_MASTER_2, + SPMI_MASTER_3 +}; + +enum spmi_slave +{ + SPMI_SLAVE_0, + SPMI_SLAVE_1, + SPMI_SLAVE_2, + SPMI_SLAVE_3, + SPMI_SLAVE_4, + SPMI_SLAVE_5, + SPMI_SLAVE_6, + SPMI_SLAVE_7, + SPMI_SLAVE_8, + SPMI_SLAVE_9, + SPMI_SLAVE_10, + SPMI_SLAVE_11, + SPMI_SLAVE_12, + SPMI_SLAVE_13, + SPMI_SLAVE_14, + SPMI_SLAVE_15 +}; + +enum slv_type +{ + BUCK_CPU, + BUCK_GPU, + BUCK_MD, + BUCK_RF, + MAIN_PMIC, + BUCK_VPU, + SUB_PMIC, + SLV_TYPE_MAX +}; + +enum slv_type_id +{ + BUCK_RF_ID = 1, + BUCK_MD_ID = 3, + MAIN_PMIC_ID = 5, + BUCK_CPU_ID = 6, + BUCK_GPU_ID = 7, + BUCK_VPU_ID, + SUB_PMIC_ID = 10, + SLV_TYPE_ID_MAX +}; + +struct spmi_device { + int slvid; + int grpiden; + enum slv_type type; + enum slv_type_id type_id; +}; +#endif /*__SPMI_H__*/ diff --git a/src/soc/mediatek/mt8192/pmif.c b/src/soc/mediatek/mt8192/pmif.c new file mode 100644 index 0000000..ca42d37 --- /dev/null +++ b/src/soc/mediatek/mt8192/pmif.c @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <console/console.h> +#include <device/mmio.h> +#include <soc/addressmap.h> +#include <soc/pmif.h> +#include <soc/pmif_spi.h> +#include <soc/pmif_spmi.h> +#include <soc/pmif_sw.h> +#include <soc/spmi.h> +#include <string.h> +#include <timer.h> + +static unsigned int pmif_check_idle(struct pmif *arb, unsigned int timeout_us) { + unsigned int reg_rdata; + struct stopwatch sw; + + stopwatch_init_usecs_expire(&sw, timeout_us); + do { + reg_rdata = read32(&arb->mtk_pmif->swinf_0_sta + 0x10 * arb->swinf_no); + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, "[%s] timeout\n", __func__); + return E_TIMEOUT; + } + } while (GET_SWINF_0_FSM(reg_rdata) != SWINF_FSM_IDLE); + + return 0; +} + +static inline unsigned int pmif_check_vldclr(struct pmif *arb, unsigned int timeout_us) { + unsigned int reg_rdata; + struct stopwatch sw; + + stopwatch_init_usecs_expire(&sw, timeout_us); + do { + reg_rdata = read32(&arb->mtk_pmif->swinf_0_sta + 0x10 * arb->swinf_no); + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, "[%s] timeout\n", __func__); + return E_TIMEOUT; + } + } while (GET_SWINF_0_FSM(reg_rdata) != SWINF_FSM_WFVLDCLR); + + return 0; +} + +static int pmif_send_cmd(struct pmif *arb, unsigned int write, + unsigned int opc, unsigned int slvid, unsigned int addr, + unsigned int *rdata, unsigned int wdata, unsigned int len) +{ + unsigned int ret = 0, data = 0; + unsigned int bc = len - 1; + + bc = 0; + /* Wait for Software Interface FSM state to be IDLE. */ + ret = pmif_check_idle(arb, PMIF_WAIT_IDLE_US); + if(ret) + return ret; + + /* Set the write data */ + if (write == 1) { + /* Set the write data. */ + write32(&arb->mtk_pmif->swinf_0_wdata_31_0 + 0x10 * arb->swinf_no, wdata); + } + + /* Send the command. */ + write32(&arb->mtk_pmif->swinf_0_acc + 0x10 * arb->swinf_no, + (opc << 30) | (write << 29) | (slvid << 24) | (bc << 16) | addr); + + if (write == 0) { + /* Wait for Software Interface FSM state to be WFVLDCLR, + * + * read the data and clear the valid flag. + */ + ret = pmif_check_vldclr(arb, PMIF_READ_US); + if(ret) + return ret; + + data = read32(&arb->mtk_pmif->swinf_0_rdata_31_0 + 0x10 * arb->swinf_no); + *rdata = data; + write32(&arb->mtk_pmif->swinf_0_vld_clr + 0x10 * arb->swinf_no, 0x1); + } + + return 0; +} + +static int pmif_spmi_read_cmd(struct pmif *arb,unsigned int slvid, + unsigned int addr, unsigned int *rdata) +{ + + return pmif_send_cmd(arb, 0, PMIF_CMD_EXT_REG_LONG, slvid, addr, rdata, 0, (PMIF_BYTECNT_MAX - 1)); +} + +static int pmif_spmi_write_cmd(struct pmif *arb, unsigned int slvid, + unsigned int addr, unsigned int wdata) +{ + return pmif_send_cmd(arb, 1, PMIF_CMD_EXT_REG_LONG, slvid, addr, NULL, wdata, (PMIF_BYTECNT_MAX - 1)); +} + +static int pmif_spi_read_cmd(struct pmif *arb, unsigned int slvid, + unsigned int addr, unsigned int *rdata) +{ + + return pmif_send_cmd(arb, 0, PMIF_CMD_REG_0, slvid, addr, rdata, 0, (PMIF_BYTECNT_MAX - 1)); +} + +static int pmif_spi_write_cmd(struct pmif *arb, unsigned int slvid, + unsigned int addr, unsigned int wdata) +{ + return pmif_send_cmd(arb, 1, PMIF_CMD_REG_0, slvid, addr, NULL, wdata, (PMIF_BYTECNT_MAX - 1)); +} + +static int is_pmif_init_done(struct pmif *arb) +{ + if ((read32(&arb->mtk_pmif->init_done) & 0x1)) + return 0; + + return -E_NODEV; +} + +static struct pmif pmif_spmi_arb[] = { + { + .mtk_pmif = (struct mtk_pmif_regs *)PMIF_SPMI_BASE, + .swinf_ch_start = PMIF_SWINF_0_CHAN_NO, + .swinf_no = PMIF_AP_SWINF_NO, + .mstid = SPMI_MASTER_0, + .pmifid = PMIF_SPMI, + .write_cmd = pmif_spmi_write_cmd, + .read_cmd = pmif_spmi_read_cmd, + .is_pmif_init_done = is_pmif_init_done, + }, +}; + +static struct pmif pmif_spi_arb[] = { + { + .mtk_pmif = (struct mtk_pmif_regs *)PMIF_SPI_BASE, + .swinf_no = PMIF_AP_SWINF_NO, + .pmifid = PMIF_SPI, + .write_cmd = pmif_spi_write_cmd, + .read_cmd = pmif_spi_read_cmd, + .is_pmif_init_done = is_pmif_init_done, + }, +}; + +struct pmif *get_pmif_controller(int inf, int mstid) +{ + if (inf == PMIF_SPMI) + return &pmif_spmi_arb[mstid]; + else if (inf == PMIF_SPI) + return &pmif_spi_arb[0]; + + return NULL; +} + +int mtk_pmif_init(void) +{ + int ret = 1; + + ret = pmif_clk_init(); + if (ret) + goto FAIL; + + ret = pmif_spmi_init(&pmif_spmi_arb[SPMI_MASTER_0]); + if (ret) + goto FAIL; + + ret = pmif_spi_init(&pmif_spi_arb[0]); + if (ret) + goto FAIL; + + return 0; + +FAIL: + /* assert(0); */ + return ret; +} diff --git a/src/soc/mediatek/mt8192/pmif_clk.c b/src/soc/mediatek/mt8192/pmif_clk.c new file mode 100644 index 0000000..96dfe0e --- /dev/null +++ b/src/soc/mediatek/mt8192/pmif_clk.c @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <delay.h> +#include <device/mmio.h> +#include <soc/infracfg.h> +#include <soc/pll.h> +#include <soc/pll_common.h> +#include <soc/pmif.h> +#include <soc/pmif_sw.h> +#include <soc/pmif_spmi.h> + +#define FREQ_260MHZ 260 +/* calibation miss rate, unit: 0.1% */ +#define CAL_MIS_RATE 40 +/* + * FREQ METER ID + * Ask clkmgr owner to find this information + * at clock table[fmeter]. + */ +#define FREQ_METER_ABIST_AD_OSC_CK 37 +#define CAL_MAX_VAL 0x7f + +static unsigned int mt_get_abist_freq(unsigned int ID) +{ + int output = 0, i = 0; + unsigned int temp, clk26cali_0, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1; + + clk_dbg_cfg = read32(&mtk_topckgen->clk_dbg_cfg); + /* sel abist_cksw and enable freq meter sel abist */ + write32(&mtk_topckgen->clk_dbg_cfg, (clk_dbg_cfg & 0xFFC0FFFC)|(ID << 16)); + + clk_misc_cfg_0 = read32(&mtk_topckgen->clk_misc_cfg_0); + /* select divider, div 4 */ + write32(&mtk_topckgen->clk_misc_cfg_0, (clk_misc_cfg_0 & 0x00FFFFFF) | (3 << 24)); + + clk26cali_0 = read32(&mtk_topckgen->clk26cali_0); + clk26cali_1 = read32(&mtk_topckgen->clk26cali_1); + write32(&mtk_topckgen->clk26cali_0, 0x1000); + write32(&mtk_topckgen->clk26cali_0, 0x1010); + + /* wait frequency meter finish */ + while (read32(&mtk_topckgen->clk26cali_0) & 0x10) + { + udelay(10); + i++; + if(i > 100) + break; + } + + temp = read32(&mtk_topckgen->clk26cali_1) & 0xFFFF; + output = ((temp * 26000) ) / 1024; /* Khz */ + + write32(&mtk_topckgen->clk_dbg_cfg, clk_dbg_cfg); + write32(&mtk_topckgen->clk_misc_cfg_0, clk_misc_cfg_0); + write32(&mtk_topckgen->clk26cali_0, clk26cali_0); + write32(&mtk_topckgen->clk26cali_1, clk26cali_1); + + return output * 4; +} + +static void pmif_ulposc_config(void) +{ + /* Config ULPOSC_CON0 */ + /* OSC_CP_EN = 0 */ + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) &~(0x1 << 24)); + + /* OSC_DIV = 1110 */ + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) &~(0x3f << 18)); + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) | (0xe << 18)); + + /* OSC_FBAND = 0010 */ + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) &~(0xf << 14)); + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) | (0x2 << 14)); + + /* OSC_IBAND = 1010010 */ + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) &~(0x7f << 7)); + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) | (0x52 << 7)); + + /* OSC_CALI = 1000000 */ + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) &~(0x7f)); + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) | 0x40); + + /* + **** Config ULPOSC_CON1 *** + */ + + /* OSC_DIV2_EN= 1b'0 */ + write32(&mtk_apmixed->ulposc1_con1, read32(&mtk_apmixed->ulposc1_con1) &~(0x1 << 26)); + + /* OSC_MOD = 00 */ + write32(&mtk_apmixed->ulposc1_con1, read32(&mtk_apmixed->ulposc1_con1) &~(0x3 << 24)); + + /* OSC_RSV2= 8b'00000000 */ + write32(&mtk_apmixed->ulposc1_con1, read32(&mtk_apmixed->ulposc1_con1) &~(0xff << 16)); + + /* OSC_RSV1= 8b'00101001 */ + write32(&mtk_apmixed->ulposc1_con1, read32(&mtk_apmixed->ulposc1_con1) &~(0xff << 8)); + write32(&mtk_apmixed->ulposc1_con1, read32(&mtk_apmixed->ulposc1_con1) | (0x29 << 8)); + + /* OSC_32KCALI = 8b'00000000 */ + write32(&mtk_apmixed->ulposc1_con1, read32(&mtk_apmixed->ulposc1_con1) &~(0xff)); + + /* + **** Config ULPOSC_CON2 *** + */ + + /* OSC_BIAS= 8b'01000010 */ + write32(&mtk_apmixed->ulposc1_con2, read32(&mtk_apmixed->ulposc1_con2) &~(0xff)); + write32(&mtk_apmixed->ulposc1_con2, read32(&mtk_apmixed->ulposc1_con2) | (0x40)); + +} + +static u32 pmif_get_ulposc_freq(u32 cali_val) +{ + u32 result = 0; + + /* set calibration value */ + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) &~(0x7f)); + write32(&mtk_apmixed->ulposc1_con0, read32(&mtk_apmixed->ulposc1_con0) | cali_val); + + udelay(50); + + result = mt_get_abist_freq(FREQ_METER_ABIST_AD_OSC_CK); + + return result / 1000; +} + +static int pmif_ulposc_cali(void) +{ + u32 current_val = 0, min = 0, max = CAL_MAX_VAL, middle; + u32 diff_by_min = 0, diff_by_max = 0xffff, cal_result; + int ret = 0; + + do { + middle = (min + max) / 2; + if (middle == min) + break; + + current_val = pmif_get_ulposc_freq(middle); + + if (current_val > FREQ_260MHZ) + max = middle; + else + min = middle; + } while (min <= max); + + current_val = pmif_get_ulposc_freq(min); + if (current_val > FREQ_260MHZ) + diff_by_min = current_val - FREQ_260MHZ; + else + diff_by_min = FREQ_260MHZ - current_val; + + current_val = pmif_get_ulposc_freq(max); + if (current_val > FREQ_260MHZ) + diff_by_max = current_val - FREQ_260MHZ; + else + diff_by_max = FREQ_260MHZ - current_val; + + if (diff_by_min < diff_by_max) { + cal_result = min; + current_val = pmif_get_ulposc_freq(min); + } else { + cal_result = max; + current_val = pmif_get_ulposc_freq(max); + } + + /* check if calibrated value is in the range of target value +- 15% */ + if (current_val < (FREQ_260MHZ * (1000 - CAL_MIS_RATE) / 1000) + || current_val > (FREQ_260MHZ * (1000 + CAL_MIS_RATE) / 1000)) { + printk(BIOS_ERR, "[%s]calibration fail: %dM\n", __func__, current_val); + ret = 1; + } + + return ret; +} + +static int pmif_init_ulposc(void) +{ + int ret = 1; + + /* calibrate ULPOSC1 */ + pmif_ulposc_config(); + + /* enable spm swinf */ + if ((read32(&mtk_spm->poweron_config_en) & 0x1) != 0x1) + write32(&mtk_spm->poweron_config_en, (0xb16 << 16) | 0x1); + + /* turn on ulposc */ + write32(&mtk_spm->ulposc_con, read32(&mtk_spm->ulposc_con) | 0x1); + udelay(100); + write32(&mtk_spm->ulposc_con, read32(&mtk_spm->ulposc_con) | 0x1 << 2); + + ret = pmif_ulposc_cali(); + return ret; +} + +int pmif_clk_init(void) +{ + int ret = 1; + + ret = pmif_init_ulposc(); + if(ret) + return -E_NODEV; + + /* turn off pmic_cg_tmr, cg_ap, cg_md, cg_conn clock */ + write32(&mt8192_infracfg->module_sw_cg_0_set, 0xf); + /* Use MTS: modem_temp_share_cg need to enable + * DRV_WriteReg32(MODULE_SW_CG_2_SET, 0x00000020); + * Use TIA: modem_temp_share_cg not need + */ + write32(&mtk_topckgen->clk_cfg_8_clr, (0x1 << 15) | (0x1 << 12) | (0x7 << 8)); + write32(&mtk_topckgen->clk_cfg_update1, 0x1 << 2); + + /* use ULPOSC1 clock */ + write32(&mt8192_infracfg->pmicw_clock_ctrl_clr, 0xf); + + /* toggle SPMI sw reset */ + write32(&mt8192_infracfg->infra_globalcon_rst2_set, 0x1 << 14); + write32(&mt8192_infracfg->infra_globalcon_rst2_clr, 0x1 << 14); + + /* toggle SPI sw reset */ + write32(&mt8192_infracfg->infra_globalcon_rst2_set, 0x1); + write32(&mt8192_infracfg->infra_globalcon_rst2_clr, 0x1); + + /* turn on pmic_cg_tmr, cg_ap, cg_md, cg_conn clock */ + write32(&mt8192_infracfg->module_sw_cg_0_clr, 0xf); + /* Use MTS: modem_temp_share_cg need to enable + * DRV_WriteReg32(MODULE_SW_CG_2_CLR, 0x00000020); + * Use TIA: modem_temp_share_cg not need + */ + + return 0; +} diff --git a/src/soc/mediatek/mt8192/pmif_spi.c b/src/soc/mediatek/mt8192/pmif_spi.c new file mode 100644 index 0000000..e1d77aa --- /dev/null +++ b/src/soc/mediatek/mt8192/pmif_spi.c @@ -0,0 +1,319 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <delay.h> +#include <device/mmio.h> +#include <soc/infracfg.h> +#include <soc/pll.h> +#include <soc/pmif.h> +#include <soc/pmif_spi.h> +#include <soc/pmif_sw.h> +#include <timer.h> + +/* PMIF, SPI_MODE_CTRL */ +DEFINE_BIT(SPI_MODE_CTRL_VLD_SRCLK_EN_CTRL, 5) +DEFINE_BIT(SPI_MODE_CTRL_PMIF_RDY, 9) +DEFINE_BIT(SPI_MODE_CTRL_SRCLK_EN, 10) +DEFINE_BIT(SPI_MODE_CTRL_SRVOL_EN, 11) + +/* PMIF, SLEEP_PROTECTION_CTRL */ +DEFINE_BITFIELD(SPM_SLEEP_REQ_SEL, 1, 0) +DEFINE_BITFIELD(SCP_SLEEP_REQ_SEL, 10, 9) + +/* PMIF, STAUPD_CTRL */ +DEFINE_BITFIELD(STAUPD_CTRL_PRD, 3, 0) +DEFINE_BIT(STAUPD_CTRL_PMIC0_SIG_STA, 4) +DEFINE_BIT(STAUPD_CTRL_PMIC0_EINT_STA, 6) + +/* SPIMST, Manual_Mode_Access */ +DEFINE_BIT(SPI_RW, 13) +DEFINE_BITFIELD(SPI_OP, 12, 8) + +static void pmif_spi_config(struct pmif *arb) +{ + /* Set srclk_en always valid regardless of ulposc_sel_for_scp */ + SET32_BITFIELDS(&arb->mtk_pmif->spi_mode_ctrl, SPI_MODE_CTRL_VLD_SRCLK_EN_CTRL, 0); + + + /* Set SPI mode controlled by srclk_en and srvol_en instead of pmif_rdy */ + SET32_BITFIELDS(&arb->mtk_pmif->spi_mode_ctrl, SPI_MODE_CTRL_SRCLK_EN, 1, SPI_MODE_CTRL_SRVOL_EN, 1); + SET32_BITFIELDS(&arb->mtk_pmif->spi_mode_ctrl, SPI_MODE_CTRL_PMIF_RDY, 0); + + SET32_BITFIELDS(&arb->mtk_pmif->sleep_protection_ctrl, SPM_SLEEP_REQ_SEL, 0); + SET32_BITFIELDS(&arb->mtk_pmif->sleep_protection_ctrl, SCP_SLEEP_REQ_SEL, 0); + + /* Enable SWINF for AP */ + write32(&arb->mtk_pmif->inf_en, PMIF_SPI_AP_SWINF_CHAN_NO); + + /* Enable arbitration for SWINF for AP */ + write32(&arb->mtk_pmif->arb_en, PMIF_SPI_AP_SWINF_CHAN_NO); + + /* Enable PMIF_SPI Command Issue */ + write32(&arb->mtk_pmif->cmdissue_en, 1); +} + +static signed int reset_spislv(void) +{ + unsigned int pmicspi_mst_dio_en_backup, rdata; + struct stopwatch sw; + + write32(&mtk_pmicspi_mst->wrap_en, 0); + write32(&mtk_pmicspi_mst->mux_sel, 1); + write32(&mtk_pmicspi_mst->man_en, 1); + pmicspi_mst_dio_en_backup = read32(&mtk_pmicspi_mst->dio_en); + write32(&mtk_pmicspi_mst->dio_en, 0); + + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_CSL); + /* Reset counter */ + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_OUTS); + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_CSH); + /* + * In order to pull CSN signal to PMIC, + * PMIC will count it then reset spi slave + */ + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_OUTS); + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_OUTS); + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_OUTS); + SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, SPI_RW, OP_WR, SPI_OP, OP_OUTS); + + /* Wait for PMIC SPI Master to be idle */ + stopwatch_init_usecs_expire(&sw, PMIF_WAIT_IDLE_US); + do { + rdata = read32(&mtk_pmicspi_mst->other_busy_sta_0); + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, "[%s] timeout\n", __func__); + return E_TIMEOUT; + } + } while (GET_PMICSPI_BUSY(rdata) != 0x0); + + write32(&mtk_pmicspi_mst->man_en, 0); + write32(&mtk_pmicspi_mst->mux_sel, 0); + write32(&mtk_pmicspi_mst->wrap_en, 1); + write32(&mtk_pmicspi_mst->dio_en, pmicspi_mst_dio_en_backup); + + return 0; +} + +static void init_reg_clock(struct pmif *arb) +{ + unsigned int rdata; + + /* Set SoC SPI IO driving strength to 4 mA */ + write32(&mtk_iocfg_tl->drv_cfg0_clr, 0x7 << 21); + write32(&mtk_iocfg_tl->drv_cfg0_set, 0x1 << 21); + + /* Configure SPI protocol */ + write32(&mtk_pmicspi_mst->ext_ck_write, 1); + write32(&mtk_pmicspi_mst->ext_ck_read, 0); + write32(&mtk_pmicspi_mst->cshext_write, 0); + write32(&mtk_pmicspi_mst->cshext_read, 0); + write32(&mtk_pmicspi_mst->cslext_write, 0); + write32(&mtk_pmicspi_mst->cslext_read, 0x100); + + /* Set Read Dummy Cycle Number (Slave Clock is 18MHz) */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_DEW_RDDMY_NO, DUMMY_READ_CYCLES); + write32(&mtk_pmicspi_mst->rddmy, DUMMY_READ_CYCLES); + + /* Enable DIO mode */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_DEW_DIO_EN, 0x1); + + /* Wait for completion of sending the commands */ + do { + rdata = read32(&arb->mtk_pmif->inf_busy_sta); + } while ((rdata & PMIF_SPI_AP_SWINF_CHAN_NO) != 0x0); + + do { + rdata = read32(&arb->mtk_pmif->other_busy_sta_0); + } while (GET_CMDISSUE_BUSY(rdata) != 0x0); + + do { + rdata = read32(&mtk_pmicspi_mst->other_busy_sta_0); + } while (GET_PMICSPI_BUSY(rdata) != 0x0); + + write32(&mtk_pmicspi_mst->dio_en, 1); +} + +static void init_spislv(struct pmif *arb) +{ + /* Turn on SPI IO filter function */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_FILTER_CON0, SPI_FILTER); + /* Turn on SPI IO SMT function to improve noise immunity */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_SMT_CON1, SPI_SMT); + /* Turn off SPI IO pull function for power saving */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_GPIO_PULLEN0_CLR, SPI_PULL_DISABLE); + /* Enable SPI access in SODI-3.0 and Suspend modes */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_RG_SPI_CON0, 0x2); + /* Set SPI IO driving strength to 4 mA */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_DRV_CON1, SPI_DRIVING); +} + +static s32 init_sistrobe(struct pmif *arb) +{ + unsigned int rdata = 0; + int si_sample_ctrl; + int test_data[30] = { + 0x6996, 0x9669, 0x6996, 0x9669, 0x6996, 0x9669, 0x6996, + 0x9669, 0x6996, 0x9669, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, + 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x1B27, + 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, + 0x1B27, 0x1B27}; + + for (si_sample_ctrl = 0; si_sample_ctrl < 16; si_sample_ctrl++) { + write32(&mtk_pmicspi_mst->si_sampling_ctrl, si_sample_ctrl << 5); + + arb->read_cmd(arb, DEFAULT_SLVID, PMIC_DEW_READ_TEST, &rdata); + if (rdata == DEFAULT_VALUE_READ_TEST) + break; + } + + if (si_sample_ctrl == 16) + return E_CLK_EDGE; + + if (si_sample_ctrl == 15) + return E_CLK_LAST_SETTING; + + /* + * Add the delay time of SPI data from PMIC to align the start boundary + * to current sampling clock edge. + */ + for (int si_dly = 0; si_dly < 10; si_dly++) { + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_RG_SPI_CON2, si_dly); + + int start_boundary_found = 0; + for (size_t i = 0; i < 30; i++) { + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_DEW_WRITE_TEST, test_data[i]); + arb->read_cmd(arb, DEFAULT_SLVID, PMIC_DEW_WRITE_TEST, &rdata); + if ((rdata & 0x7fff) != (test_data[i] & 0x7fff)) { + start_boundary_found = 1; + break; + } + } + if (start_boundary_found == 1) + break; + } + + /* + * Change the sampling clock edge to the next one which is the middle + * of SPI data window. + */ + write32(&mtk_pmicspi_mst->si_sampling_ctrl, ++si_sample_ctrl << 5); + + /* Read Test */ + arb->read_cmd(arb, DEFAULT_SLVID, PMIC_DEW_READ_TEST, &rdata); + if (rdata != DEFAULT_VALUE_READ_TEST) { + printk(BIOS_ERR, "[%s] rdata = %#x, exp = %#x\n", + __func__, rdata, DEFAULT_VALUE_READ_TEST); + return E_READ_TEST_FAIL; + } + + return 0; +} + +static void initstaupd(struct pmif *arb) +{ + unsigned int rdata; + + /* Unlock SPI Slave registers */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_SPISLV_KEY, 0xbade); + + /* Enable CRC of PMIC 0 */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_DEW_CRC_EN, 0x1); + + /* Wait for completion of sending the commands */ + do { + rdata = read32(&arb->mtk_pmif->inf_busy_sta); + } while ((rdata & PMIF_SPI_AP_SWINF_CHAN_NO) != 0x0); + + do { + rdata = read32(&arb->mtk_pmif->other_busy_sta_0); + } while (GET_CMDISSUE_BUSY(rdata) != 0x0); + + do { + rdata = read32(&mtk_pmicspi_mst->other_busy_sta_0); + } while (GET_PMICSPI_BUSY(rdata) != 0x0); + + /* Configure CRC of PMIC Interface */ + write32(&arb->mtk_pmif->crc_ctrl, 0x1); + write32(&arb->mtk_pmif->sig_mode, 0x0); + + /* Lock SPI Slave registers */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_SPISLV_KEY, 0x0); + + /* Setup PMIC Siganature */ + write32(&arb->mtk_pmif->pmic_sig_addr, PMIC_DEW_CRC_VAL); + + /* Setup PMIC EINT */ + write32(&arb->mtk_pmif->pmic_eint_sta_addr, PMIC_INT_STA); + + SET32_BITFIELDS(&arb->mtk_pmif->staupd_ctrl, STAUPD_CTRL_PRD, 5, + STAUPD_CTRL_PMIC0_SIG_STA, 1, STAUPD_CTRL_PMIC0_EINT_STA, 1); +} + +int pmif_spi_init(struct pmif *arb) +{ + int sub_return = 0; + + pmif_spi_config(arb); + + /* Reset spislv */ + sub_return = reset_spislv(); + if (sub_return != 0) + return E_SPI_INIT_RESET_SPI; + + /* Enable WRAP */ + write32(&mtk_pmicspi_mst->wrap_en, 0x1); + + /* SPI Waveform Configuration */ + init_reg_clock(arb); + + /* SPI Slave Configuration */ + init_spislv(arb); + + /* Input data calibration flow; */ + sub_return = init_sistrobe(arb); + if (sub_return != 0) { + printk(BIOS_ERR, "[%s] data calibration fail,ret=%d\n", + __func__, sub_return); + return E_SPI_INIT_SIDLY; + } + + /* Lock SPISLV Registers */ + arb->write_cmd(arb, DEFAULT_SLVID, PMIC_SPISLV_KEY, 0x0); + + /* + * Status update function initialization + * 1. Signature Checking using CRC (CRC 0 only) + * 2. EINT update + * 3. Read back Auxadc thermal data for GPS + */ + initstaupd(arb); + + /* Configure PMIF Timer */ + write32(&arb->mtk_pmif->timer_ctrl, 0x3); + + /* Enable interfaces and arbitration */ + write32(&arb->mtk_pmif->inf_en, 0x307f | + PMIF_SPI_MD_SWINF_CHAN_NO | + PMIF_SPI_AP_SECURE_SWINF_CHAN_NO | + PMIF_SPI_AP_SWINF_CHAN_NO); + + write32(&arb->mtk_pmif->arb_en, 0x707f | + PMIF_SPI_MD_SWINF_CHAN_NO | + PMIF_SPI_AP_SECURE_SWINF_CHAN_NO | + PMIF_SPI_AP_SWINF_CHAN_NO); + + /* Enable GPS AUXADC HW 0 and 1 */ + write32(&arb->mtk_pmif->arb_en, read32(&arb->mtk_pmif->arb_en) | (0x3 << 19)); + write32(&arb->mtk_pmif->other_inf_en, read32(&arb->mtk_pmif->other_inf_en) | (0x3 << 4)); + + /* Set INIT_DONE */ + write32(&arb->mtk_pmif->init_done, 0x1); + + /* Configure MD ADC Interface */ + udelay(100); + + /* write MODEM_TEMP_SHARE_CTRL start */ + write32(&mtk_modem_temp_share->ctrl, 0xf0); + + return 0; +} diff --git a/src/soc/mediatek/mt8192/pmif_spmi.c b/src/soc/mediatek/mt8192/pmif_spmi.c new file mode 100644 index 0000000..4a9af68 --- /dev/null +++ b/src/soc/mediatek/mt8192/pmif_spmi.c @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <soc/pmif.h> +#include <soc/spmi.h> +#include <soc/pmif_sw.h> +#include <soc/pmif_spmi.h> +#include <soc/addressmap.h> +#include <device/mmio.h> +#include <string.h> +#include <console/console.h> +#include <soc/pll.h> +#include <soc/pll_common.h> + +#define PMIF_CMD_PER_3 (0x1 << PMIF_CMD_EXT_REG_LONG) +#define PMIF_CMD_PER_1_3 \ + ((0x1 << PMIF_CMD_REG) | (0x1 << PMIF_CMD_EXT_REG_LONG)) +#define PMIF_CMD_PER_2_3 \ + ((0x1 << PMIF_CMD_EXT_REG) | (0x1 << PMIF_CMD_EXT_REG_LONG)) + +/* spmi master setting */ +struct spmi_device spmi_dev[] = { + { + .slvid = SPMI_SLAVE_6, + .grpiden = 0x800, + .type = BUCK_CPU, + .type_id = BUCK_CPU_ID, + }, { + .slvid = SPMI_SLAVE_7, + .grpiden = 0x800, + .type = BUCK_GPU, + .type_id = BUCK_GPU_ID, + }, +}; + +static int spmi_config_io(void) +{ + /* 0'b010 SPMI_SCL[5:3]; */ + write32(&mtk_iocfg_bm->drv_cfg2_set, 0x2 << SPMI_SCL_DRV_SHIFT); + write32(&mtk_iocfg_bm->drv_cfg2_clr, 0x5 << SPMI_SCL_DRV_SHIFT); + /* 0'b010 SPMI_SDA[6:8] */ + write32(&mtk_iocfg_bm->drv_cfg2_set, 0x2 << SPMI_SDA_DRV_SHIFT); + write32(&mtk_iocfg_bm->drv_cfg2_clr, 0x5 << SPMI_SDA_DRV_SHIFT); + + return 0; +} + +static int spmi_config_master(void) +{ + /* Software reset */ + write32(&mtk_rug->wdt_swsysrst2, + (WDT_UNLOCK_KEY << WDT_UNLOCK_SHIFT) | \ + (0x1 << SPMIMST_RST_SHIFT)); + + write32(&mtk_topckgen->clk_cfg_15_clr, (0x700) | (0x1 << 12) | (0x1 << 15)); + write32(&mtk_topckgen->clk_cfg_update2, (0x1 << 30)); + + /* Software reset */ + write32(&mtk_rug->wdt_swsysrst2, (WDT_UNLOCK_KEY << WDT_UNLOCK_SHIFT)); + + /* Enable SPMI */ + write32(&mtk_spmi_mst->mst_req_en, 1); + + return 0; +} + +static int spmi_read_check(struct pmif *pmif_arb, int slvid) +{ + unsigned int rdata = 0; + + + /* MT6315_PMIC_HWCID_H_ADDR/MT6315_HWCID_H 0x9 */ + pmif_arb->read_cmd(pmif_arb, slvid, 0x9, &rdata); + if (rdata != 0x15) { + printk(BIOS_ERR, "%s next, slvid:%d rdata = 0x%x.\n", + __func__, slvid, rdata); + return -E_IO; + } + + /*MT6315_PMIC_SWCID_H_ADDR/MT6315_SWCID_H 0xb*/ + pmif_arb->read_cmd(pmif_arb, slvid, 0xb, &rdata); + if (rdata != 0x15) { + printk(BIOS_ERR, "%s next, slvid:%d rdata = 0x%x.\n", + __func__, slvid, rdata); + return -E_IO; + } + + return 0; +} + +static int spmi_cali_rd_clock_polarity(struct pmif *pmif_arb, struct spmi_device *dev) +{ + unsigned int i = 0; + struct cali cali_data[] = { + {SPMI_CK_DLY_1T, SPMI_CK_POL_POS}, + {SPMI_CK_NO_DLY, SPMI_CK_POL_POS}, + {SPMI_CK_NO_DLY, SPMI_CK_POL_NEG} + }; + + /* Indicate sampling clock polarity, 1: Positive 0: Negative */ + for (i = 0;i < 3; i++) { + write32(&mtk_spmi_mst->mst_sampl, (cali_data[i].dly << 0x1) | cali_data[i].pol); + if (spmi_read_check(pmif_arb, dev->slvid) == 0) + break; + } + + if (i == 3) { + printk(BIOS_ERR, "FATAL ERROR"); + /* ASSERT(0); */ + } + + return 0; +} + +static int spmi_mst_init(struct pmif *pmif_arb) +{ + int i; + unsigned char spmi_device_cnt; + + if (pmif_arb == NULL) { + printk(BIOS_ERR, "arguments err\n"); + return -E_INVAL; + } + + /* config IOCFG */ + spmi_config_io(); + spmi_config_master(); + + spmi_device_cnt = sizeof(spmi_dev)/sizeof(spmi_dev[0]); + for (i = 0; i < spmi_device_cnt; i++) { + //spmi_dev[i].pmif_arb = pmif_spmi_arb_ctrl[pmif_arb->mstid]; + spmi_cali_rd_clock_polarity(pmif_arb, &spmi_dev[i]); + } + + return 0; +} + +static void pmif_spmi_force_normal_mode(int mstid) +{ + struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); + unsigned int value; + + /* listen srclken_0 only for entering normal or sleep mode */ + value = read32(&arb->mtk_pmif->spi_mode_ctrl) & (~(0x1 << 7)); + write32(&arb->mtk_pmif->spi_mode_ctrl, value); + + /* enable srclken_en or srvol_en(VREQ) control */ + value |= ((0x1 << 12) | (0x1 << 13)); + /* disable srclken_rc control */ + value &= (~(0x1 << 11)); + write32(&arb->mtk_pmif->spi_mode_ctrl, value); + + /* enable spm/scp sleep request */ + value = read32(&arb->mtk_pmif->sleep_protection_ctrl); + value &= (~0x3); + value &= (~(0x3 << 9)); + write32(&arb->mtk_pmif->sleep_protection_ctrl, value); +} + +static void pmif_spmi_enable_swinf(int mstid, unsigned int chan_no, + unsigned int swinf_no) +{ + struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); + + /* Enable swinf chan_no = 4, swinf_no = 2*/ + write32(&arb->mtk_pmif->inf_en, 0x1 << (chan_no + swinf_no)); + + /* Enable arbitration */ + write32(&arb->mtk_pmif->arb_en, 0x1 << (chan_no + swinf_no)); +} + +static void pmif_spmi_enable_cmdIssue(int mstid, bool en) +{ + struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); + + /* Enable cmdIssue */ + write32(&arb->mtk_pmif->cmdissue_en, en); +} + +static void pmif_spmi_enable(int mstid) +{ + struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); + unsigned int bytecnt_per = 0, hw_bytecnt = 0; + unsigned int cmd_per = 0; + + /* clear all cmd permission for per channel */ + write32(&arb->mtk_pmif->inf_cmd_per_0, 0); + write32(&arb->mtk_pmif->inf_cmd_per_1, 0); + write32(&arb->mtk_pmif->inf_cmd_per_2, 0); + write32(&arb->mtk_pmif->inf_cmd_per_3, 0); + + /* enable if we need cmd 0~3 permission for per channel */ + cmd_per = PMIF_CMD_PER_3 << 28 | PMIF_CMD_PER_3 << 24 | + PMIF_CMD_PER_3 << 20 | PMIF_CMD_PER_3 << 16 | + PMIF_CMD_PER_3 << 8 | PMIF_CMD_PER_3 << 4 | + PMIF_CMD_PER_1_3 << 0; + write32(&arb->mtk_pmif->inf_cmd_per_0, cmd_per); + cmd_per = PMIF_CMD_PER_3 << 4; + write32(&arb->mtk_pmif->inf_cmd_per_1, cmd_per); + + /* set bytecnt max limitation*/ + write32(&arb->mtk_pmif->inf_max_bytecnt_per_0, 0); + write32(&arb->mtk_pmif->inf_max_bytecnt_per_1, 0); + write32(&arb->mtk_pmif->inf_max_bytecnt_per_2, 0); + write32(&arb->mtk_pmif->inf_max_bytecnt_per_3, 0); + + /* hw bytecnt indicate when we set 0, it can send 1 byte; + * set 1, it can send 2 byte. + */ + hw_bytecnt = PMIF_BYTECNT_MAX -1; + if (hw_bytecnt > 0) { + bytecnt_per = hw_bytecnt << 28 | hw_bytecnt << 24 | + hw_bytecnt << 20 | hw_bytecnt << 16 | + hw_bytecnt << 12 | hw_bytecnt << 8 | + hw_bytecnt << 4 | hw_bytecnt << 0; + } + write32(&arb->mtk_pmif->inf_max_bytecnt_per_0, bytecnt_per); + write32(&arb->mtk_pmif->inf_max_bytecnt_per_1, bytecnt_per); + write32(&arb->mtk_pmif->inf_max_bytecnt_per_2, bytecnt_per); + write32(&arb->mtk_pmif->inf_max_bytecnt_per_3, bytecnt_per); + + /* Add latency limitation */ + write32(&arb->mtk_pmif->lat_cnter_en, 0x2F7); + write32(&arb->mtk_pmif->lat_limit_0, 0); + write32(&arb->mtk_pmif->lat_limit_1, 0x4); + write32(&arb->mtk_pmif->lat_limit_2, 0x8); + write32(&arb->mtk_pmif->lat_limit_4, 0x8); + write32(&arb->mtk_pmif->lat_limit_6, 0x3FF); + write32(&arb->mtk_pmif->lat_limit_9, 0x4); + write32(&arb->mtk_pmif->lat_limit_loading, 0x2F7); + + write32(&arb->mtk_pmif->inf_en, 0x2F7); + write32(&arb->mtk_pmif->arb_en, 0x2F7); + write32(&arb->mtk_pmif->timer_ctrl, 0x3); + write32(&arb->mtk_pmif->init_done, 1); +} + +int pmif_spmi_init(struct pmif *arb) +{ + int ret = 0; + + if (arb->is_pmif_init_done(arb) != 0) { + pmif_spmi_force_normal_mode(arb->mstid); + pmif_spmi_enable_swinf(arb->mstid, PMIF_SWINF_0_CHAN_NO, arb->swinf_no); + pmif_spmi_enable_cmdIssue(arb->mstid, true); + pmif_spmi_enable(arb->mstid); + ret = arb->is_pmif_init_done(arb); + if(ret) + return -E_NODEV; + } + + ret = spmi_mst_init(arb); + if(ret) + return -E_NODEV; + + return 0; +}