summaryrefslogtreecommitdiff
path: root/src/soc/mediatek/mt8183/pmic_wrap.c
diff options
context:
space:
mode:
authorHsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>2018-10-24 17:57:55 +0800
committerJulius Werner <jwerner@chromium.org>2018-11-29 01:40:31 +0000
commita6db8f3cc3879cc1650f8f42dcec7074dd3f8604 (patch)
treed3574619d3a1094ad1935140d117207bc5335aff /src/soc/mediatek/mt8183/pmic_wrap.c
parentac4865c05f3c2d7e751d5493120ad97cc48f31c1 (diff)
downloadcoreboot-a6db8f3cc3879cc1650f8f42dcec7074dd3f8604.tar.xz
mediatek/mt8183: Add PMIC wrapper support
The PMIC wrapper is a proprietary hardware to connect the PMIC. This patch implements PMIC wrapper driver for the communication with PMIC. BUG=b:80501386 BRANCH=none TEST=Boots correctly on Kukui Change-Id: Idbdb15f11227ded3f5d18fe6504c8c646973b733 Signed-off-by: Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com> Reviewed-on: https://review.coreboot.org/c/29421 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'src/soc/mediatek/mt8183/pmic_wrap.c')
-rw-r--r--src/soc/mediatek/mt8183/pmic_wrap.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/src/soc/mediatek/mt8183/pmic_wrap.c b/src/soc/mediatek/mt8183/pmic_wrap.c
new file mode 100644
index 0000000000..f074646e6d
--- /dev/null
+++ b/src/soc/mediatek/mt8183/pmic_wrap.c
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 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.
+ */
+
+#include <arch/io.h>
+#include <soc/infracfg.h>
+#include <soc/pll.h>
+#include <soc/pmic_wrap.h>
+
+#define PRIORITY_FIELD(x) ((x % 4) * 8)
+#define PRIORITY_IN(id, priority) (id << PRIORITY_FIELD(priority))
+#define PRIORITY_OUT(id, priority) (priority << PRIORITY_FIELD(id))
+
+enum {
+ MD_ADCINF0 = 8,
+ MD_ADCINF1 = 9,
+ STAUPD = 10,
+ GPSINF0 = 11,
+
+ PRIORITY_IN_SEL_2 = PRIORITY_IN(MD_ADCINF0, 9) |
+ PRIORITY_IN(MD_ADCINF1, 10) |
+ PRIORITY_IN(STAUPD, 8) |
+ PRIORITY_IN(GPSINF0, 11),
+
+ PRIORITY_OUT_SEL_2 = PRIORITY_OUT(MD_ADCINF0, 9) |
+ PRIORITY_OUT(MD_ADCINF1, 10) |
+ PRIORITY_OUT(STAUPD, 8) |
+ PRIORITY_OUT(GPSINF0, 11),
+};
+
+#define PENDING_US(x) x
+enum {
+ STARVE_ENABLE = 0x1 << 10,
+ COUNTER0_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x2),
+ COUNTER1_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3),
+ COUNTER2_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3),
+ COUNTER3_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3),
+ COUNTER4_PENDING_THRES = STARVE_ENABLE | PENDING_US(0xf),
+ COUNTER5_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x20),
+ COUNTER6_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x28),
+ COUNTER7_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x28),
+ COUNTER8_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x13),
+ COUNTER9_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17),
+ COUNTER10_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17),
+ COUNTER11_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7c),
+ COUNTER12_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7c),
+ COUNTER13_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x340),
+ COUNTER16_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x340),
+};
+
+
+static void pwrap_soft_reset(void)
+{
+ write32(&mt8183_infracfg->infra_globalcon_rst2_set, 0x1);
+ write32(&mt8183_infracfg->infra_globalcon_rst2_clr, 0x1);
+}
+
+static void pwrap_spi_clk_set(void)
+{
+ write32(&mtk_topckgen->clk_cfg_5_clr,
+ ULPOSC_OFF | ULPOSC_INV | ULPOSC_SEL_1 | ULPOSC_SEL_2);
+ write32(&mtk_topckgen->clk_cfg_5_set, ULPOSC_SEL_1);
+ write32(&mtk_topckgen->clk_cfg_update, ULPOSC_CLK);
+
+ write32(&mt8183_infracfg->module_sw_cg_0_set,
+ TIMER_CG | AP_CG | MD_CG | CONN_CG);
+ write32(&mt8183_infracfg->module_sw_cg_2_set, MODEM_TEMP_SHARE_CG);
+
+ pwrap_soft_reset();
+
+ write32(&mt8183_infracfg->module_sw_cg_0_clr,
+ TIMER_CG | AP_CG | MD_CG | CONN_CG);
+ write32(&mt8183_infracfg->module_sw_cg_2_clr, MODEM_TEMP_SHARE_CG);
+}
+
+static s32 pwrap_init_dio(u16 dio_en)
+{
+ pwrap_write_nochk(PMIC_DEW_DIO_EN, dio_en);
+
+ if (!wait_us(100,
+ !wait_for_idle_and_sync(read32(&mtk_pwrap->wacs2_rdata))))
+ return -1;
+
+ write32(&mtk_pwrap->dio_en, dio_en);
+ return 0;
+}
+
+static void pwrap_lock_spislvreg(void)
+{
+ pwrap_write_nochk(PMIC_SPISLV_KEY, 0x0);
+}
+
+static void pwrap_initstaupd(void)
+{
+ write32(&mtk_pwrap->staupd_grpen,
+ SIG_PMIC_0 | INT_STA_PMIC_0 | MD_ADC_DATA0 |
+ MD_ADC_DATA1 | GPS_ADC_DATA0 | GPS_ADC_DATA1);
+
+ /* CRC */
+ pwrap_write_nochk(PMIC_DEW_CRC_EN, 0x1);
+ write32(&mtk_pwrap->crc_en, 0x1);
+ write32(&mtk_pwrap->sig_adr, PMIC_DEW_CRC_VAL);
+
+ write32(&mtk_pwrap->eint_sta0_adr, PMIC_CPU_INT_STA);
+
+ /* MD ADC Interface */
+ write32(&mtk_pwrap->md_auxadc_rdata_latest_addr,
+ (PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31);
+ write32(&mtk_pwrap->md_auxadc_rdata_wp_addr,
+ (PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31);
+ for (size_t i = 0; i < 32; i++)
+ write32(&mtk_pwrap->md_auxadc_rdata[i],
+ (PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31);
+
+ write32(&mtk_pwrap->int_gps_auxadc_cmd_addr,
+ (PMIC_AUXADC_RQST1 << 16) + PMIC_AUXADC_RQST0);
+ write32(&mtk_pwrap->int_gps_auxadc_cmd, (GPS_MAIN << 16) + GPS_SUBSYS);
+ write32(&mtk_pwrap->int_gps_auxadc_rdata_addr,
+ (PMIC_AUXADC_ADC32 << 16) + PMIC_AUXADC_ADC17);
+
+ write32(&mtk_pwrap->ext_gps_auxadc_rdata_addr, PMIC_AUXADC_ADC31);
+}
+
+static void pwrap_starve_set(void)
+{
+ write32(&mtk_pwrap->harb_hprio, ARB_PRIORITY);
+ write32(&mtk_pwrap->starv_counter_0, COUNTER0_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_1, COUNTER1_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_2, COUNTER2_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_3, COUNTER3_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_4, COUNTER4_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_5, COUNTER5_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_6, COUNTER6_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_7, COUNTER7_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_8, COUNTER8_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_9, COUNTER9_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_10, COUNTER10_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_11, COUNTER11_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_12, COUNTER12_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_13, COUNTER13_PENDING_THRES);
+ write32(&mtk_pwrap->starv_counter_16, COUNTER16_PENDING_THRES);
+}
+
+static void pwrap_enable(void)
+{
+ write32(&mtk_pwrap->hiprio_arb_en, ARB_USER_EN);
+ write32(&mtk_pwrap->wacs0_en, 0x1);
+ write32(&mtk_pwrap->wacs2_en, 0x1);
+ write32(&mtk_pwrap->wacs_p2p_en, 0x1);
+ write32(&mtk_pwrap->wacs_md32_en, 0x1);
+ write32(&mtk_pwrap->staupd_ctrl, STA_PD_98_5_US);
+ write32(&mtk_pwrap->wdt_unit, WATCHDOG_TIMER_7_5_MS);
+ write32(&mtk_pwrap->wdt_src_en_0, WDT_MONITOR_ALL);
+ write32(&mtk_pwrap->wdt_src_en_1, WDT_MONITOR_ALL);
+ write32(&mtk_pwrap->timer_en, 0x1);
+ write32(&mtk_pwrap->int0_en, INT0_MONITOR);
+ write32(&mtk_pwrap->int1_en, INT1_MONITOR);
+}
+
+static s32 pwrap_init_sistrobe(void)
+{
+ u16 rdata;
+ 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_pwrap->si_sample_ctrl, si_sample_ctrl << 5);
+
+ pwrap_read_nochk(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++) {
+ pwrap_write_nochk(PMIC_RG_SPI_CON2, si_dly);
+
+ int start_boundary_found = 0;
+ for (size_t i = 0; i < 30; i++) {
+ pwrap_write_nochk(PMIC_DEW_WRITE_TEST, test_data[i]);
+ pwrap_read_nochk(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_pwrap->si_sample_ctrl, ++si_sample_ctrl << 5);
+
+ /* Read Test */
+ pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata);
+ if (rdata != DEFAULT_VALUE_READ_TEST) {
+ pwrap_err("rdata = %#x, exp = %#x\n", rdata,
+ DEFAULT_VALUE_READ_TEST);
+ return E_PWR_READ_TEST_FAIL;
+ }
+
+ return 0;
+}
+
+static void pwrap_init_spislv(void)
+{
+ /* Turn on IO filter function */
+ pwrap_write_nochk(PMIC_FILTER_CON0, SPI_FILTER);
+ /* Turn on IO SMT function to improve noise immunity */
+ pwrap_write_nochk(PMIC_SMT_CON1, SPI_SMT);
+ /* Turn off IO pull function for power saving */
+ pwrap_write_nochk(PMIC_GPIO_PULLEN0_CLR, SPI_PULL_DISABLE);
+ /* Enable SPI R/W in suspend mode */
+ pwrap_write_nochk(PMIC_RG_SPI_CON0, 0x1);
+ /* Set PMIC GPIO driving current to 4mA */
+ pwrap_write_nochk(PMIC_DRV_CON1, SPI_DRIVING);
+}
+
+static void pwrap_init_reg_clock(void)
+{
+ write32(&mtk_pwrap->ext_ck_write, 0x1);
+
+ pwrap_write_nochk(PMIC_DEW_RDDMY_NO, DUMMY_READ_CYCLES);
+ write32(&mtk_pwrap->rddmy, DUMMY_READ_CYCLES);
+
+ write32(&mtk_pwrap->cshext_write, 0);
+ write32(&mtk_pwrap->cshext_read, 0);
+ write32(&mtk_pwrap->cslext_write, 0);
+ write32(&mtk_pwrap->cslext_read, 0);
+}
+
+s32 pwrap_init(void)
+{
+ s32 sub_return = 0, sub_return1 = 0;
+ u16 rdata;
+
+ pwrap_spi_clk_set();
+
+ /* Reset spislv */
+ sub_return = pwrap_reset_spislv();
+ if (sub_return != 0) {
+ pwrap_err("reset_spislv fail, ret=%d\n", sub_return);
+ return E_PWR_INIT_RESET_SPI;
+ }
+
+ /* Enable WRAP */
+ write32(&mtk_pwrap->wrap_en, 0x1);
+
+ /* Enable WACS2 */
+ write32(&mtk_pwrap->wacs2_en, 0x1);
+ write32(&mtk_pwrap->hiprio_arb_en, WACS2); /* ONLY WACS2 */
+
+ /* SPI Waveform Configuration */
+ pwrap_init_reg_clock();
+
+ /* SPI Slave Configuration */
+ pwrap_init_spislv();
+
+ /* Enable DIO mode */
+ sub_return = pwrap_init_dio(1);
+ if (sub_return != 0) {
+ pwrap_err("dio test error, ret=%d\n", sub_return);
+ return E_PWR_INIT_DIO;
+ }
+
+ /* Input data calibration flow; */
+ sub_return = pwrap_init_sistrobe();
+ if (sub_return != 0) {
+ pwrap_err("InitSiStrobe fail,ret=%d\n", sub_return);
+ return E_PWR_INIT_SIDLY;
+ }
+
+ /*
+ * Write test using WACS2,
+ * make sure the read/write function ready.
+ */
+ sub_return = pwrap_write_nochk(PMIC_DEW_WRITE_TEST, WRITE_TEST_VALUE);
+ sub_return1 = pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata);
+ if (rdata != WRITE_TEST_VALUE || sub_return || sub_return1) {
+ pwrap_err("write error, rdata=%#x, return=%d, return1=%d\n",
+ rdata, sub_return, sub_return1);
+ return E_PWR_INIT_WRITE_TEST;
+ }
+
+ /*
+ * Status update function initialization
+ * 1. Signature Checking using CRC (CRC 0 only)
+ * 2. EINT update
+ * 3. Read back Auxadc thermal data for GPS
+ */
+ pwrap_initstaupd();
+
+ write32(&mtk_pwrap->priority_user_sel_2, PRIORITY_IN_SEL_2);
+ write32(&mtk_pwrap->arbiter_out_sel_2, PRIORITY_OUT_SEL_2);
+
+ pwrap_starve_set();
+
+ pwrap_enable();
+
+ /* Initialization Done */
+ write32(&mtk_pwrap->init_done0, 0x1);
+ write32(&mtk_pwrap->init_done2, 0x1);
+ write32(&mtk_pwrap->init_done_p2p, 0x1);
+ write32(&mtk_pwrap->init_done_md32, 0x1);
+
+ /* Lock SPISLV Registers */
+ pwrap_lock_spislvreg();
+
+ return 0;
+}