| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <console/console.h> |
| #include <device/mmio.h> |
| #include <soc/addressmap.h> |
| #include <soc/pmif.h> |
| #include <soc/pmif_spmi.h> |
| #include <soc/pmif_sw.h> |
| #include <soc/spmi.h> |
| |
| /* SPMI_MST, SPMI_SAMPL_CTRL */ |
| DEFINE_BIT(SAMPL_CK_POL, 0) |
| DEFINE_BITFIELD(SAMPL_CK_DLY, 3, 1) |
| |
| /* PMIF, SPI_MODE_CTRL */ |
| DEFINE_BIT(SPI_MODE_CTRL, 7) |
| DEFINE_BIT(SRVOL_EN, 11) |
| DEFINE_BIT(SPI_MODE_EXT_CMD, 12) |
| DEFINE_BIT(SPI_EINT_MODE_GATING_EN, 13) |
| |
| /* PMIF, SLEEP_PROTECTION_CTRL */ |
| DEFINE_BITFIELD(SPM_SLEEP_REQ_SEL, 1, 0) |
| DEFINE_BITFIELD(SCP_SLEEP_REQ_SEL, 10, 9) |
| |
| __weak void pmif_spmi_config(struct pmif *arb, int mstid) |
| { |
| /* Do nothing. */ |
| } |
| |
| static int spmi_read_check(struct pmif *pmif_arb, int slvid) |
| { |
| u32 rdata = 0; |
| |
| pmif_arb->read(pmif_arb, slvid, MT6315_READ_TEST, &rdata); |
| if (rdata != MT6315_DEFAULT_VALUE_READ) { |
| printk(BIOS_INFO, "%s next, slvid:%d rdata = 0x%x.\n", |
| __func__, slvid, rdata); |
| return -E_NODEV; |
| } |
| |
| pmif_arb->read(pmif_arb, slvid, MT6315_READ_TEST_1, &rdata); |
| if (rdata != MT6315_DEFAULT_VALUE_READ) { |
| printk(BIOS_INFO, "%s next, slvid:%d rdata = 0x%x.\n", |
| __func__, slvid, rdata); |
| return -E_NODEV; |
| } |
| |
| return 0; |
| } |
| |
| static int spmi_cali_rd_clock_polarity(struct pmif *pmif_arb, const struct spmi_device *dev) |
| { |
| int i; |
| bool success = false; |
| const 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}, |
| {SPMI_CK_DLY_1T, SPMI_CK_POL_NEG}, |
| }; |
| |
| /* Indicate sampling clock polarity, 1: Positive 0: Negative */ |
| for (i = 0; i < ARRAY_SIZE(cali_data); i++) { |
| SET32_BITFIELDS(&mtk_spmi_mst->mst_sampl, SAMPL_CK_DLY, cali_data[i].dly, |
| SAMPL_CK_POL, cali_data[i].pol); |
| if (spmi_read_check(pmif_arb, dev->slvid) == 0) { |
| success = true; |
| break; |
| } |
| } |
| |
| if (!success) |
| die("ERROR - calibration fail for spmi clk"); |
| |
| return 0; |
| } |
| |
| static int spmi_mst_init(struct pmif *pmif_arb) |
| { |
| size_t i; |
| |
| if (!pmif_arb) { |
| printk(BIOS_ERR, "%s: null pointer for pmif dev.\n", __func__); |
| return -E_INVAL; |
| } |
| |
| if (!CONFIG(PMIF_SPMI_IOCFG_DEFAULT_SETTING)) |
| pmif_spmi_iocfg(); |
| spmi_config_master(); |
| |
| for (i = 0; i < spmi_dev_cnt; i++) |
| 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); |
| |
| /* listen srclken_0 only for entering normal or sleep mode */ |
| SET32_BITFIELDS(&arb->mtk_pmif->spi_mode_ctrl, |
| SPI_MODE_CTRL, 0, |
| SRVOL_EN, 0, |
| SPI_MODE_EXT_CMD, 1, |
| SPI_EINT_MODE_GATING_EN, 1); |
| |
| /* enable spm/scp sleep request */ |
| SET32_BITFIELDS(&arb->mtk_pmif->sleep_protection_ctrl, SPM_SLEEP_REQ_SEL, 0, |
| SCP_SLEEP_REQ_SEL, 0); |
| } |
| |
| static void pmif_spmi_enable_swinf(int mstid) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| |
| write32(&arb->mtk_pmif->inf_en, PMIF_SPMI_SW_CHAN); |
| write32(&arb->mtk_pmif->arb_en, PMIF_SPMI_SW_CHAN); |
| } |
| |
| 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); |
| |
| pmif_spmi_config(arb, mstid); |
| |
| /* |
| * set bytecnt max limitation. |
| * hw bytecnt indicate when we set 0, it can send 1 byte; |
| * set 1, it can send 2 byte. |
| */ |
| 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); |
| |
| /* Add latency limitation */ |
| write32(&arb->mtk_pmif->lat_cnter_en, PMIF_SPMI_INF); |
| 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, PMIF_SPMI_INF); |
| |
| write32(&arb->mtk_pmif->inf_en, PMIF_SPMI_INF); |
| write32(&arb->mtk_pmif->arb_en, PMIF_SPMI_INF); |
| write32(&arb->mtk_pmif->timer_ctrl, 0x3); |
| write32(&arb->mtk_pmif->init_done, 1); |
| } |
| |
| int pmif_spmi_init(struct pmif *arb) |
| { |
| if (arb->is_pmif_init_done(arb) != 0) { |
| pmif_spmi_force_normal_mode(arb->mstid); |
| pmif_spmi_enable_swinf(arb->mstid); |
| pmif_spmi_enable_cmdIssue(arb->mstid, true); |
| pmif_spmi_enable(arb->mstid); |
| if (arb->is_pmif_init_done(arb)) |
| return -E_NODEV; |
| } |
| |
| if (spmi_mst_init(arb)) { |
| printk(BIOS_ERR, "[%s] failed to init spmi master\n", __func__); |
| return -E_NODEV; |
| } |
| |
| return 0; |
| } |