106cb65efSGarmin.Chang /* 206cb65efSGarmin.Chang * Copyright (c) 2021, MediaTek Inc. All rights reserved. 306cb65efSGarmin.Chang * 406cb65efSGarmin.Chang * SPDX-License-Identifier: BSD-3-Clause 506cb65efSGarmin.Chang */ 606cb65efSGarmin.Chang 706cb65efSGarmin.Chang #include <cdefs.h> 806cb65efSGarmin.Chang #include <common/debug.h> 906cb65efSGarmin.Chang #include <lib/mmio.h> 1006cb65efSGarmin.Chang #include <lib/utils_def.h> 1106cb65efSGarmin.Chang #include <mt_mcdi.h> 1206cb65efSGarmin.Chang 1306cb65efSGarmin.Chang /* Read/Write */ 1406cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_AP_READY U(0) 1506cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_RESERVED_1 U(1) 1606cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_RESERVED_2 U(2) 1706cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_RESERVED_3 U(3) 1806cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_PWR_CTRL_EN U(4) 1906cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_L3_CACHE_MODE U(5) 2006cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_BUCK_MODE U(6) 2106cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_ARMPLL_MODE U(7) 2206cb65efSGarmin.Chang /* Read only */ 2306cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_TASK_STA U(8) 2406cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_RESERVED_9 U(9) 2506cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_RESERVED_10 U(10) 2606cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_RESERVED_11 U(11) 2706cb65efSGarmin.Chang 2806cb65efSGarmin.Chang /* CPC mode - Read/Write */ 2906cb65efSGarmin.Chang #define APMCU_MCUPM_MBOX_WAKEUP_CPU U(12) 3006cb65efSGarmin.Chang 3106cb65efSGarmin.Chang /* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */ 3206cb65efSGarmin.Chang #define MCUPM_MCUSYS_CTRL BIT(0) 3306cb65efSGarmin.Chang #define MCUPM_BUCK_CTRL BIT(1) 3406cb65efSGarmin.Chang #define MCUPM_ARMPLL_CTRL BIT(2) 3506cb65efSGarmin.Chang #define MCUPM_CM_CTRL BIT(3) 3606cb65efSGarmin.Chang #define MCUPM_PWR_CTRL_MASK GENMASK(3, 0) 3706cb65efSGarmin.Chang 3806cb65efSGarmin.Chang /* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */ 3906cb65efSGarmin.Chang #define MCUPM_BUCK_NORMAL_MODE U(0) /* default */ 4006cb65efSGarmin.Chang #define MCUPM_BUCK_LP_MODE U(1) 4106cb65efSGarmin.Chang #define MCUPM_BUCK_OFF_MODE U(2) 4206cb65efSGarmin.Chang #define NF_MCUPM_BUCK_MODE U(3) 4306cb65efSGarmin.Chang 4406cb65efSGarmin.Chang /* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */ 4506cb65efSGarmin.Chang #define MCUPM_ARMPLL_ON U(0) /* default */ 4606cb65efSGarmin.Chang #define MCUPM_ARMPLL_GATING U(1) 4706cb65efSGarmin.Chang #define MCUPM_ARMPLL_OFF U(2) 4806cb65efSGarmin.Chang #define NF_MCUPM_ARMPLL_MODE U(3) 4906cb65efSGarmin.Chang 5006cb65efSGarmin.Chang /* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */ 5106cb65efSGarmin.Chang #define MCUPM_TASK_UNINIT U(0) 5206cb65efSGarmin.Chang #define MCUPM_TASK_INIT U(1) 5306cb65efSGarmin.Chang #define MCUPM_TASK_INIT_FINISH U(2) 5406cb65efSGarmin.Chang #define MCUPM_TASK_WAIT U(3) 5506cb65efSGarmin.Chang #define MCUPM_TASK_RUN U(4) 5606cb65efSGarmin.Chang #define MCUPM_TASK_PAUSE U(5) 5706cb65efSGarmin.Chang 5806cb65efSGarmin.Chang #define SSPM_MBOX_3_BASE U(0x10420000) 5906cb65efSGarmin.Chang 6006cb65efSGarmin.Chang #define MCDI_NOT_INIT U(0) 6106cb65efSGarmin.Chang #define MCDI_INIT_1 U(1) 6206cb65efSGarmin.Chang #define MCDI_INIT_2 U(2) 6306cb65efSGarmin.Chang #define MCDI_INIT_DONE U(3) 6406cb65efSGarmin.Chang 65*da04341eSChris Kay static int mcdi_init_status __section(".tzfw_coherent_mem"); 6606cb65efSGarmin.Chang 6706cb65efSGarmin.Chang static inline uint32_t mcdi_mbox_read(uint32_t id) 6806cb65efSGarmin.Chang { 6906cb65efSGarmin.Chang return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2)); 7006cb65efSGarmin.Chang } 7106cb65efSGarmin.Chang 7206cb65efSGarmin.Chang static inline void mcdi_mbox_write(uint32_t id, uint32_t val) 7306cb65efSGarmin.Chang { 7406cb65efSGarmin.Chang mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val); 7506cb65efSGarmin.Chang } 7606cb65efSGarmin.Chang 7706cb65efSGarmin.Chang static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev) 7806cb65efSGarmin.Chang { 7906cb65efSGarmin.Chang mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev); 8006cb65efSGarmin.Chang } 8106cb65efSGarmin.Chang 8206cb65efSGarmin.Chang static void mtk_set_mcupm_pll_mode(uint32_t mode) 8306cb65efSGarmin.Chang { 8406cb65efSGarmin.Chang if (mode < NF_MCUPM_ARMPLL_MODE) { 8506cb65efSGarmin.Chang mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode); 8606cb65efSGarmin.Chang } 8706cb65efSGarmin.Chang } 8806cb65efSGarmin.Chang 8906cb65efSGarmin.Chang static void mtk_set_mcupm_buck_mode(uint32_t mode) 9006cb65efSGarmin.Chang { 9106cb65efSGarmin.Chang if (mode < NF_MCUPM_BUCK_MODE) { 9206cb65efSGarmin.Chang mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode); 9306cb65efSGarmin.Chang } 9406cb65efSGarmin.Chang } 9506cb65efSGarmin.Chang 9606cb65efSGarmin.Chang static int mtk_mcupm_is_ready(void) 9706cb65efSGarmin.Chang { 9806cb65efSGarmin.Chang unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA); 9906cb65efSGarmin.Chang 10006cb65efSGarmin.Chang return ((sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH)); 10106cb65efSGarmin.Chang } 10206cb65efSGarmin.Chang 10306cb65efSGarmin.Chang static int mcdi_init_1(void) 10406cb65efSGarmin.Chang { 10506cb65efSGarmin.Chang unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA); 10606cb65efSGarmin.Chang 10706cb65efSGarmin.Chang if (sta != MCUPM_TASK_INIT) { 10806cb65efSGarmin.Chang return -1; 10906cb65efSGarmin.Chang } 11006cb65efSGarmin.Chang 11106cb65efSGarmin.Chang mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF); 11206cb65efSGarmin.Chang mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE); 11306cb65efSGarmin.Chang 11406cb65efSGarmin.Chang mtk_mcupm_pwr_ctrl_setting( 11506cb65efSGarmin.Chang MCUPM_MCUSYS_CTRL | 11606cb65efSGarmin.Chang MCUPM_BUCK_CTRL | 11706cb65efSGarmin.Chang MCUPM_ARMPLL_CTRL); 11806cb65efSGarmin.Chang 11906cb65efSGarmin.Chang mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1); 12006cb65efSGarmin.Chang 12106cb65efSGarmin.Chang return 0; 12206cb65efSGarmin.Chang } 12306cb65efSGarmin.Chang 12406cb65efSGarmin.Chang static int mcdi_init_2(void) 12506cb65efSGarmin.Chang { 12606cb65efSGarmin.Chang return mtk_mcupm_is_ready() ? 0 : -1; 12706cb65efSGarmin.Chang } 12806cb65efSGarmin.Chang 12906cb65efSGarmin.Chang int mcdi_try_init(void) 13006cb65efSGarmin.Chang { 13106cb65efSGarmin.Chang if (mcdi_init_status == MCDI_INIT_DONE) { 13206cb65efSGarmin.Chang return 0; 13306cb65efSGarmin.Chang } 13406cb65efSGarmin.Chang 13506cb65efSGarmin.Chang if (mcdi_init_status == MCDI_NOT_INIT) { 13606cb65efSGarmin.Chang mcdi_init_status = MCDI_INIT_1; 13706cb65efSGarmin.Chang } 13806cb65efSGarmin.Chang 13906cb65efSGarmin.Chang if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) { 14006cb65efSGarmin.Chang mcdi_init_status = MCDI_INIT_2; 14106cb65efSGarmin.Chang } 14206cb65efSGarmin.Chang 14306cb65efSGarmin.Chang if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) { 14406cb65efSGarmin.Chang mcdi_init_status = MCDI_INIT_DONE; 14506cb65efSGarmin.Chang } 14606cb65efSGarmin.Chang 14706cb65efSGarmin.Chang INFO("mcdi ready for mcusys-off-idle and system suspend\n"); 14806cb65efSGarmin.Chang 14906cb65efSGarmin.Chang return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status; 15006cb65efSGarmin.Chang } 151