CK HU would like hsin-hsiung wang to review this change.

View Change

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;
+}

To view, visit change 45398. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I32fc28f72d9522133baa06f9d67c383f814d862c
Gerrit-Change-Number: 45398
Gerrit-PatchSet: 1
Gerrit-Owner: CK HU <ck.hu@mediatek.com>
Gerrit-Reviewer: Martin Roth <martinroth@google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi@google.com>
Gerrit-Reviewer: hsin-hsiung wang <hsin-hsiung.wang@mediatek.com>
Gerrit-MessageType: newchange