summaryrefslogtreecommitdiff
path: root/src/soc/mediatek/common/pmif_spmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/mediatek/common/pmif_spmi.c')
-rw-r--r--src/soc/mediatek/common/pmif_spmi.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/soc/mediatek/common/pmif_spmi.c b/src/soc/mediatek/common/pmif_spmi.c
new file mode 100644
index 0000000000..5f68c23507
--- /dev/null
+++ b/src/soc/mediatek/common/pmif_spmi.c
@@ -0,0 +1,203 @@
+/* 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>
+
+#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))
+
+/* 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)
+
+static const struct spmi_device spmi_dev[] = {
+ {
+ .slvid = SPMI_SLAVE_6,
+ .type = BUCK_CPU,
+ .type_id = BUCK_CPU_ID,
+ },
+ {
+ .slvid = SPMI_SLAVE_7,
+ .type = BUCK_GPU,
+ .type_id = BUCK_GPU_ID,
+ },
+};
+
+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_ERR, "%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_ERR, "%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)
+{
+ int i;
+
+ if (!pmif_arb) {
+ printk(BIOS_ERR, "%s: null pointer for pmif dev.\n", __func__);
+ return -E_INVAL;
+ }
+
+ pmif_spmi_iocfg();
+ spmi_config_master();
+
+ for (i = 0; i < ARRAY_SIZE(spmi_dev); 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);
+ u32 cmd_per;
+
+ /* 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.
+ * 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;
+}