1 /*
2  * Copyright (c) 2021, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <cdefs.h>
8 #include <common/debug.h>
9 #include <lib/mmio.h>
10 #include <lib/utils_def.h>
11 #include <mt_mcdi.h>
12 
13 /* Read/Write */
14 #define APMCU_MCUPM_MBOX_AP_READY	U(0)
15 #define APMCU_MCUPM_MBOX_RESERVED_1	U(1)
16 #define APMCU_MCUPM_MBOX_RESERVED_2	U(2)
17 #define APMCU_MCUPM_MBOX_RESERVED_3	U(3)
18 #define APMCU_MCUPM_MBOX_PWR_CTRL_EN	U(4)
19 #define APMCU_MCUPM_MBOX_L3_CACHE_MODE	U(5)
20 #define APMCU_MCUPM_MBOX_BUCK_MODE	U(6)
21 #define APMCU_MCUPM_MBOX_ARMPLL_MODE	U(7)
22 /* Read only */
23 #define APMCU_MCUPM_MBOX_TASK_STA	U(8)
24 #define APMCU_MCUPM_MBOX_RESERVED_9	U(9)
25 #define APMCU_MCUPM_MBOX_RESERVED_10	U(10)
26 #define APMCU_MCUPM_MBOX_RESERVED_11	U(11)
27 
28 /* CPC mode - Read/Write */
29 #define APMCU_MCUPM_MBOX_WAKEUP_CPU	U(12)
30 
31 /* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */
32 #define MCUPM_MCUSYS_CTRL		BIT(0)
33 #define MCUPM_BUCK_CTRL			BIT(1)
34 #define MCUPM_ARMPLL_CTRL		BIT(2)
35 #define MCUPM_CM_CTRL			BIT(3)
36 #define MCUPM_PWR_CTRL_MASK		GENMASK(3, 0)
37 
38 /* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */
39 #define MCUPM_BUCK_NORMAL_MODE		U(0) /* default */
40 #define MCUPM_BUCK_LP_MODE		U(1)
41 #define MCUPM_BUCK_OFF_MODE		U(2)
42 #define NF_MCUPM_BUCK_MODE		U(3)
43 
44 /* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */
45 #define MCUPM_ARMPLL_ON			U(0) /* default */
46 #define MCUPM_ARMPLL_GATING		U(1)
47 #define MCUPM_ARMPLL_OFF		U(2)
48 #define NF_MCUPM_ARMPLL_MODE		U(3)
49 
50 /* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */
51 #define MCUPM_TASK_UNINIT		U(0)
52 #define MCUPM_TASK_INIT			U(1)
53 #define MCUPM_TASK_INIT_FINISH		U(2)
54 #define MCUPM_TASK_WAIT			U(3)
55 #define MCUPM_TASK_RUN			U(4)
56 #define MCUPM_TASK_PAUSE		U(5)
57 
58 #define SSPM_MBOX_3_BASE		U(0x10420000)
59 
60 #define MCDI_NOT_INIT			U(0)
61 #define MCDI_INIT_1			U(1)
62 #define MCDI_INIT_2			U(2)
63 #define MCDI_INIT_DONE			U(3)
64 
65 static int mcdi_init_status __section("tzfw_coherent_mem");
66 
mcdi_mbox_read(uint32_t id)67 static inline uint32_t mcdi_mbox_read(uint32_t id)
68 {
69 	return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2));
70 }
71 
mcdi_mbox_write(uint32_t id,uint32_t val)72 static inline void mcdi_mbox_write(uint32_t id, uint32_t val)
73 {
74 	mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val);
75 }
76 
mtk_mcupm_pwr_ctrl_setting(uint32_t dev)77 static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev)
78 {
79 	mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev);
80 }
81 
mtk_set_mcupm_pll_mode(uint32_t mode)82 static void mtk_set_mcupm_pll_mode(uint32_t mode)
83 {
84 	if (mode < NF_MCUPM_ARMPLL_MODE) {
85 		mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode);
86 	}
87 }
88 
mtk_set_mcupm_buck_mode(uint32_t mode)89 static void mtk_set_mcupm_buck_mode(uint32_t mode)
90 {
91 	if (mode < NF_MCUPM_BUCK_MODE) {
92 		mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode);
93 	}
94 }
95 
mtk_mcupm_is_ready(void)96 static int mtk_mcupm_is_ready(void)
97 {
98 	unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
99 
100 	return ((sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH));
101 }
102 
mcdi_init_1(void)103 static int mcdi_init_1(void)
104 {
105 	unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
106 
107 	if (sta != MCUPM_TASK_INIT) {
108 		return -1;
109 	}
110 
111 	mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
112 	mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
113 
114 	mtk_mcupm_pwr_ctrl_setting(
115 			 MCUPM_MCUSYS_CTRL |
116 			 MCUPM_BUCK_CTRL |
117 			 MCUPM_ARMPLL_CTRL);
118 
119 	mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1);
120 
121 	return 0;
122 }
123 
mcdi_init_2(void)124 static int mcdi_init_2(void)
125 {
126 	return mtk_mcupm_is_ready() ? 0 : -1;
127 }
128 
mcdi_try_init(void)129 int mcdi_try_init(void)
130 {
131 	if (mcdi_init_status == MCDI_INIT_DONE) {
132 		return 0;
133 	}
134 
135 	if (mcdi_init_status == MCDI_NOT_INIT) {
136 		mcdi_init_status = MCDI_INIT_1;
137 	}
138 
139 	if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) {
140 		mcdi_init_status = MCDI_INIT_2;
141 	}
142 
143 	if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) {
144 		mcdi_init_status = MCDI_INIT_DONE;
145 	}
146 
147 	INFO("mcdi ready for mcusys-off-idle and system suspend\n");
148 
149 	return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
150 }
151