blob: 0ed44a041fdceab8c7bbc4cac4054a9684dddc25 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/mmio.h>
#include <soc/infracfg.h>
#include <soc/pll.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, OTHER_INF_EN */
DEFINE_BITFIELD(INTGPSADCINF_EN, 5, 4)
/* 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_BITFIELD(MAN_ACC_SPI_OP, 12, 8)
DEFINE_BIT(MAN_ACC_SPI_RW, 13)
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,
SPI_MODE_CTRL_PMIF_RDY, 0);
SET32_BITFIELDS(&arb->mtk_pmif->sleep_protection_ctrl, SPM_SLEEP_REQ_SEL, 0,
SCP_SLEEP_REQ_SEL, 0);
/* Enable SWINF for AP */
write32(&arb->mtk_pmif->inf_en, PMIF_SPI_AP);
/* Enable arbitration for SWINF for AP */
write32(&arb->mtk_pmif->arb_en, PMIF_SPI_AP);
/* Enable PMIF_SPI Command Issue */
write32(&arb->mtk_pmif->cmdissue_en, 1);
}
static int check_idle(void *addr, u32 expected)
{
u32 reg_rdata;
struct stopwatch sw;
stopwatch_init_usecs_expire(&sw, PMIF_WAIT_IDLE_US);
do {
reg_rdata = read32(addr);
if (stopwatch_expired(&sw))
return E_TIMEOUT;
} while ((reg_rdata & expected) != 0);
return 0;
}
static int reset_spislv(void)
{
u32 pmicspi_mst_dio_en_backup;
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, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_SPI_OP, OP_CSL);
/* Reset counter */
SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_SPI_OP, OP_OUTS);
SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_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, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_SPI_OP, OP_OUTS);
SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_SPI_OP, OP_OUTS);
SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_SPI_OP, OP_OUTS);
SET32_BITFIELDS(&mtk_pmicspi_mst->man_acc, MAN_ACC_SPI_RW, OP_WR,
MAN_ACC_SPI_OP, OP_OUTS);
/* Wait for PMIC SPI Master to be idle */
if (check_idle(&mtk_pmicspi_mst->other_busy_sta_0, SPIMST_STA)) {
printk(BIOS_ERR, "[%s] spi master busy, timeout\n", __func__);
return E_TIMEOUT;
}
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)
{
pmif_spi_iocfg();
/* 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(arb, DEFAULT_SLVID, PMIC_DEW_RDDMY_NO, DUMMY_READ_CYCLES);
write32(&mtk_pmicspi_mst->rddmy, DUMMY_READ_CYCLES);
/* Enable DIO mode */
arb->write(arb, DEFAULT_SLVID, PMIC_DEW_DIO_EN, 0x1);
/* Wait for completion of sending the commands */
if (check_idle(&arb->mtk_pmif->inf_busy_sta, PMIF_SPI_AP)) {
printk(BIOS_ERR, "[%s] pmif channel busy, timeout\n", __func__);
return;
}
if (check_idle(&arb->mtk_pmif->other_busy_sta_0, PMIF_CMD_STA)) {
printk(BIOS_ERR, "[%s] pmif cmd busy, timeout\n", __func__);
return;
}
if (check_idle(&mtk_pmicspi_mst->other_busy_sta_0, SPIMST_STA)) {
printk(BIOS_ERR, "[%s] spi master busy, timeout\n", __func__);
return;
}
write32(&mtk_pmicspi_mst->dio_en, 1);
}
static void init_spislv(struct pmif *arb)
{
/* Turn on SPI IO filter function */
arb->write(arb, DEFAULT_SLVID, PMIC_FILTER_CON0, SPI_FILTER);
/* Turn on SPI IO SMT function to improve noise immunity */
arb->write(arb, DEFAULT_SLVID, PMIC_SMT_CON1, SPI_SMT);
/* Turn off SPI IO pull function for power saving */
arb->write(arb, DEFAULT_SLVID, PMIC_GPIO_PULLEN0_CLR, SPI_PULL_DISABLE);
/* Enable SPI access in SODI-3.0 and Suspend modes */
arb->write(arb, DEFAULT_SLVID, PMIC_RG_SPI_CON0, 0x2);
/* Set SPI IO driving strength to 4 mA */
arb->write(arb, DEFAULT_SLVID, PMIC_DRV_CON1, SPI_DRIVING);
}
static int init_sistrobe(struct pmif *arb)
{
u32 rdata = 0;
int si_sample_ctrl;
/* Random data for testing */
const u32 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(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(arb, DEFAULT_SLVID, PMIC_RG_SPI_CON2, si_dly);
int start_boundary_found = 0;
for (int i = 0; i < ARRAY_SIZE(test_data); i++) {
arb->write(arb, DEFAULT_SLVID, PMIC_DEW_WRITE_TEST, test_data[i]);
arb->read(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(arb, DEFAULT_SLVID, PMIC_DEW_READ_TEST, &rdata);
if (rdata != DEFAULT_VALUE_READ_TEST) {
printk(BIOS_ERR, "[%s] Failed for read test, data = %#x.\n",
__func__, rdata);
return E_READ_TEST_FAIL;
}
return 0;
}
static void init_staupd(struct pmif *arb)
{
/* Unlock SPI Slave registers */
arb->write(arb, DEFAULT_SLVID, PMIC_SPISLV_KEY, 0xbade);
/* Enable CRC of PMIC 0 */
arb->write(arb, DEFAULT_SLVID, PMIC_DEW_CRC_EN, 0x1);
/* Wait for completion of sending the commands */
if (check_idle(&arb->mtk_pmif->inf_busy_sta, PMIF_SPI_AP)) {
printk(BIOS_ERR, "[%s] pmif channel busy, timeout\n", __func__);
return;
}
if (check_idle(&arb->mtk_pmif->other_busy_sta_0, PMIF_CMD_STA)) {
printk(BIOS_ERR, "[%s] pmif cmd busy, timeout\n", __func__);
return;
}
if (check_idle(&mtk_pmicspi_mst->other_busy_sta_0, SPIMST_STA)) {
printk(BIOS_ERR, "[%s] spi master busy, timeout\n", __func__);
return;
}
/* 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(arb, DEFAULT_SLVID, PMIC_SPISLV_KEY, 0x0);
/* Set up PMIC Siganature */
write32(&arb->mtk_pmif->pmic_sig_addr, PMIC_DEW_CRC_VAL);
/* Set up 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)
{
pmif_spi_config(arb);
/* Reset spislv */
if (reset_spislv())
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; */
if (init_sistrobe(arb)) {
printk(BIOS_ERR, "[%s] data calibration fail\n", __func__);
return E_SPI_INIT_SIDLY;
}
/* Lock SPISLV Registers */
arb->write(arb, DEFAULT_SLVID, PMIC_SPISLV_KEY, 0x0);
/*
* Status update function initialization
* 1. Check signature using CRC (CRC 0 only)
* 2. Update EINT
* 3. Read back AUXADC thermal data for GPS
*/
init_staupd(arb);
/* Configure PMIF Timer */
write32(&arb->mtk_pmif->timer_ctrl, 0x3);
/* Enable interfaces and arbitration */
write32(&arb->mtk_pmif->inf_en, PMIF_SPI_HW_INF | PMIF_SPI_MD |
PMIF_SPI_AP_SECURE | PMIF_SPI_AP);
write32(&arb->mtk_pmif->arb_en, PMIF_SPI_HW_INF | PMIF_SPI_MD | PMIF_SPI_AP_SECURE |
PMIF_SPI_AP | PMIF_SPI_STAUPD | PMIF_SPI_TSX_HW | PMIF_SPI_DCXO_HW);
/* Enable GPS AUXADC HW 0 and 1 */
SET32_BITFIELDS(&arb->mtk_pmif->other_inf_en, INTGPSADCINF_EN, 0x3);
/* Set INIT_DONE */
write32(&arb->mtk_pmif->init_done, 0x1);
return 0;
}