Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
cc8bbe1a YW |
2 | /* |
3 | * Copyright (c) 2015-2016 MediaTek Inc. | |
4 | * Author: Yong Wu <yong.wu@mediatek.com> | |
cc8bbe1a | 5 | */ |
4e508b25 | 6 | #include <linux/arm-smccc.h> |
cc8bbe1a YW |
7 | #include <linux/clk.h> |
8 | #include <linux/component.h> | |
9 | #include <linux/device.h> | |
10 | #include <linux/err.h> | |
11 | #include <linux/io.h> | |
8956500e | 12 | #include <linux/iopoll.h> |
4f608d38 | 13 | #include <linux/module.h> |
cc8bbe1a YW |
14 | #include <linux/of.h> |
15 | #include <linux/of_platform.h> | |
16 | #include <linux/platform_device.h> | |
17 | #include <linux/pm_runtime.h> | |
4e508b25 | 18 | #include <linux/soc/mediatek/mtk_sip_svc.h> |
cc8bbe1a | 19 | #include <soc/mediatek/smi.h> |
3c8f4ad8 | 20 | #include <dt-bindings/memory/mt2701-larb-port.h> |
66a28915 | 21 | #include <dt-bindings/memory/mtk-memory-port.h> |
cc8bbe1a | 22 | |
534e0ad2 | 23 | /* SMI COMMON */ |
431e9cab YW |
24 | #define SMI_L1LEN 0x100 |
25 | ||
0d97f217 | 26 | #define SMI_L1_ARB 0x200 |
534e0ad2 YW |
27 | #define SMI_BUS_SEL 0x220 |
28 | #define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1) | |
29 | /* All are MMU0 defaultly. Only specialize mmu1 here. */ | |
30 | #define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid)) | |
e6dec923 | 31 | |
0d97f217 | 32 | #define SMI_READ_FIFO_TH 0x230 |
431e9cab YW |
33 | #define SMI_M4U_TH 0x234 |
34 | #define SMI_FIFO_TH1 0x238 | |
35 | #define SMI_FIFO_TH2 0x23c | |
36 | #define SMI_DCM 0x300 | |
37 | #define SMI_DUMMY 0x444 | |
38 | ||
534e0ad2 | 39 | /* SMI LARB */ |
8956500e YW |
40 | #define SMI_LARB_SLP_CON 0xc |
41 | #define SLP_PROT_EN BIT(0) | |
42 | #define SLP_PROT_RDY BIT(16) | |
43 | ||
fe6dd2a4 YW |
44 | #define SMI_LARB_CMD_THRT_CON 0x24 |
45 | #define SMI_LARB_THRT_RD_NU_LMT_MSK GENMASK(7, 4) | |
46 | #define SMI_LARB_THRT_RD_NU_LMT (5 << 4) | |
47 | ||
48 | #define SMI_LARB_SW_FLAG 0x40 | |
49 | #define SMI_LARB_SW_FLAG_1 0x1 | |
50 | ||
51 | #define SMI_LARB_OSTDL_PORT 0x200 | |
52 | #define SMI_LARB_OSTDL_PORTx(id) (SMI_LARB_OSTDL_PORT + (((id) & 0x1f) << 2)) | |
a8529f3b | 53 | |
534e0ad2 YW |
54 | /* Below are about mmu enable registers, they are different in SoCs */ |
55 | /* gen1: mt2701 */ | |
3c8f4ad8 HZ |
56 | #define REG_SMI_SECUR_CON_BASE 0x5c0 |
57 | ||
58 | /* every register control 8 port, register offset 0x4 */ | |
59 | #define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2) | |
60 | #define REG_SMI_SECUR_CON_ADDR(id) \ | |
61 | (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id)) | |
62 | ||
63 | /* | |
64 | * every port have 4 bit to control, bit[port + 3] control virtual or physical, | |
65 | * bit[port + 2 : port + 1] control the domain, bit[port] control the security | |
66 | * or non-security. | |
67 | */ | |
68 | #define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2))) | |
69 | #define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3) | |
70 | /* mt2701 domain should be set to 3 */ | |
71 | #define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1)) | |
72 | ||
534e0ad2 YW |
73 | /* gen2: */ |
74 | /* mt8167 */ | |
75 | #define MT8167_SMI_LARB_MMU_EN 0xfc0 | |
76 | ||
77 | /* mt8173 */ | |
78 | #define MT8173_SMI_LARB_MMU_EN 0xf00 | |
79 | ||
80 | /* general */ | |
81 | #define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4)) | |
82 | #define F_MMU_EN BIT(0) | |
83 | #define BANK_SEL(id) ({ \ | |
8d2c749e YW |
84 | u32 _id = (id) & 0x3; \ |
85 | (_id << 8 | _id << 10 | _id << 12 | _id << 14); \ | |
86 | }) | |
e6dec923 | 87 | |
431e9cab | 88 | #define SMI_COMMON_INIT_REGS_NR 6 |
fe6dd2a4 YW |
89 | #define SMI_LARB_PORT_NR_MAX 32 |
90 | ||
91 | #define MTK_SMI_FLAG_THRT_UPDATE BIT(0) | |
92 | #define MTK_SMI_FLAG_SW_FLAG BIT(1) | |
8956500e | 93 | #define MTK_SMI_FLAG_SLEEP_CTL BIT(2) |
4e508b25 | 94 | #define MTK_SMI_FLAG_CFG_PORT_SEC_CTL BIT(3) |
fe6dd2a4 | 95 | #define MTK_SMI_CAPS(flags, _x) (!!((flags) & (_x))) |
431e9cab YW |
96 | |
97 | struct mtk_smi_reg_pair { | |
98 | unsigned int offset; | |
99 | u32 value; | |
100 | }; | |
101 | ||
a5c18986 | 102 | enum mtk_smi_type { |
42d42c76 | 103 | MTK_SMI_GEN1, |
47404757 YW |
104 | MTK_SMI_GEN2, /* gen2 smi common */ |
105 | MTK_SMI_GEN2_SUB_COMM, /* gen2 smi sub common */ | |
42d42c76 YW |
106 | }; |
107 | ||
0e14917c YW |
108 | /* larbs: Require apb/smi clocks while gals is optional. */ |
109 | static const char * const mtk_smi_larb_clks[] = {"apb", "smi", "gals"}; | |
110 | #define MTK_SMI_LARB_REQ_CLK_NR 2 | |
111 | #define MTK_SMI_LARB_OPT_CLK_NR 1 | |
112 | ||
113 | /* | |
114 | * common: Require these four clocks in has_gals case. Otherwise, only apb/smi are required. | |
3e4f74e0 | 115 | * sub common: Require apb/smi/gals0 clocks in has_gals case. Otherwise, only apb/smi are required. |
0e14917c YW |
116 | */ |
117 | static const char * const mtk_smi_common_clks[] = {"apb", "smi", "gals0", "gals1"}; | |
205e1776 | 118 | #define MTK_SMI_CLK_NR_MAX ARRAY_SIZE(mtk_smi_common_clks) |
0e14917c YW |
119 | #define MTK_SMI_COM_REQ_CLK_NR 2 |
120 | #define MTK_SMI_COM_GALS_REQ_CLK_NR MTK_SMI_CLK_NR_MAX | |
3e4f74e0 | 121 | #define MTK_SMI_SUB_COM_GALS_REQ_CLK_NR 3 |
0e14917c | 122 | |
42d42c76 | 123 | struct mtk_smi_common_plat { |
a5c18986 YW |
124 | enum mtk_smi_type type; |
125 | bool has_gals; | |
126 | u32 bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */ | |
431e9cab YW |
127 | |
128 | const struct mtk_smi_reg_pair *init; | |
42d42c76 YW |
129 | }; |
130 | ||
3c8f4ad8 HZ |
131 | struct mtk_smi_larb_gen { |
132 | int port_in_larb[MTK_LARB_NR_MAX + 1]; | |
8c1561ed | 133 | int (*config_port)(struct device *dev); |
2e9b0908 | 134 | unsigned int larb_direct_to_common_mask; |
fe6dd2a4 YW |
135 | unsigned int flags_general; |
136 | const u8 (*ostd)[SMI_LARB_PORT_NR_MAX]; | |
3c8f4ad8 | 137 | }; |
cc8bbe1a YW |
138 | |
139 | struct mtk_smi { | |
3c8f4ad8 | 140 | struct device *dev; |
0e14917c YW |
141 | unsigned int clk_num; |
142 | struct clk_bulk_data clks[MTK_SMI_CLK_NR_MAX]; | |
3c8f4ad8 | 143 | struct clk *clk_async; /*only needed by mt2701*/ |
567e58cf YW |
144 | union { |
145 | void __iomem *smi_ao_base; /* only for gen1 */ | |
146 | void __iomem *base; /* only for gen2 */ | |
147 | }; | |
47404757 | 148 | struct device *smi_common_dev; /* for sub common */ |
42d42c76 | 149 | const struct mtk_smi_common_plat *plat; |
cc8bbe1a YW |
150 | }; |
151 | ||
152 | struct mtk_smi_larb { /* larb: local arbiter */ | |
3c8f4ad8 HZ |
153 | struct mtk_smi smi; |
154 | void __iomem *base; | |
47404757 | 155 | struct device *smi_common_dev; /* common or sub-common dev */ |
3c8f4ad8 HZ |
156 | const struct mtk_smi_larb_gen *larb_gen; |
157 | int larbid; | |
158 | u32 *mmu; | |
8d2c749e | 159 | unsigned char *bank; |
3c8f4ad8 HZ |
160 | }; |
161 | ||
cc8bbe1a YW |
162 | static int |
163 | mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) | |
164 | { | |
165 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); | |
1ee9feb2 | 166 | struct mtk_smi_larb_iommu *larb_mmu = data; |
cc8bbe1a YW |
167 | unsigned int i; |
168 | ||
ec2da07c | 169 | for (i = 0; i < MTK_LARB_NR_MAX; i++) { |
1ee9feb2 | 170 | if (dev == larb_mmu[i].dev) { |
ec2da07c | 171 | larb->larbid = i; |
1ee9feb2 | 172 | larb->mmu = &larb_mmu[i].mmu; |
8d2c749e | 173 | larb->bank = larb_mmu[i].bank; |
cc8bbe1a YW |
174 | return 0; |
175 | } | |
176 | } | |
177 | return -ENODEV; | |
178 | } | |
179 | ||
534e0ad2 YW |
180 | static void |
181 | mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) | |
e6dec923 | 182 | { |
534e0ad2 | 183 | /* Do nothing as the iommu is always enabled. */ |
e6dec923 | 184 | } |
3c8f4ad8 | 185 | |
534e0ad2 YW |
186 | static const struct component_ops mtk_smi_larb_component_ops = { |
187 | .bind = mtk_smi_larb_bind, | |
188 | .unbind = mtk_smi_larb_unbind, | |
189 | }; | |
a8529f3b | 190 | |
8c1561ed | 191 | static int mtk_smi_larb_config_port_gen1(struct device *dev) |
3c8f4ad8 HZ |
192 | { |
193 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); | |
194 | const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; | |
195 | struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); | |
196 | int i, m4u_port_id, larb_port_num; | |
197 | u32 sec_con_val, reg_val; | |
198 | ||
199 | m4u_port_id = larb_gen->port_in_larb[larb->larbid]; | |
200 | larb_port_num = larb_gen->port_in_larb[larb->larbid + 1] | |
201 | - larb_gen->port_in_larb[larb->larbid]; | |
202 | ||
203 | for (i = 0; i < larb_port_num; i++, m4u_port_id++) { | |
204 | if (*larb->mmu & BIT(i)) { | |
205 | /* bit[port + 3] controls the virtual or physical */ | |
206 | sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id); | |
207 | } else { | |
208 | /* do not need to enable m4u for this port */ | |
209 | continue; | |
210 | } | |
211 | reg_val = readl(common->smi_ao_base | |
212 | + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); | |
213 | reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id); | |
214 | reg_val |= sec_con_val; | |
215 | reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id); | |
216 | writel(reg_val, | |
217 | common->smi_ao_base | |
218 | + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); | |
219 | } | |
8c1561ed | 220 | return 0; |
3c8f4ad8 HZ |
221 | } |
222 | ||
8c1561ed | 223 | static int mtk_smi_larb_config_port_mt8167(struct device *dev) |
cc8bbe1a | 224 | { |
534e0ad2 YW |
225 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); |
226 | ||
227 | writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN); | |
8c1561ed | 228 | return 0; |
cc8bbe1a YW |
229 | } |
230 | ||
8c1561ed | 231 | static int mtk_smi_larb_config_port_mt8173(struct device *dev) |
534e0ad2 YW |
232 | { |
233 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); | |
cc8bbe1a | 234 | |
534e0ad2 | 235 | writel(*larb->mmu, larb->base + MT8173_SMI_LARB_MMU_EN); |
8c1561ed | 236 | return 0; |
534e0ad2 | 237 | } |
3c8f4ad8 | 238 | |
8c1561ed | 239 | static int mtk_smi_larb_config_port_gen2_general(struct device *dev) |
534e0ad2 YW |
240 | { |
241 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); | |
fe6dd2a4 | 242 | u32 reg, flags_general = larb->larb_gen->flags_general; |
383a44ae | 243 | const u8 *larbostd = larb->larb_gen->ostd ? larb->larb_gen->ostd[larb->larbid] : NULL; |
4e508b25 | 244 | struct arm_smccc_res res; |
534e0ad2 YW |
245 | int i; |
246 | ||
247 | if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask) | |
8c1561ed | 248 | return 0; |
534e0ad2 | 249 | |
fe6dd2a4 YW |
250 | if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_THRT_UPDATE)) { |
251 | reg = readl_relaxed(larb->base + SMI_LARB_CMD_THRT_CON); | |
252 | reg &= ~SMI_LARB_THRT_RD_NU_LMT_MSK; | |
253 | reg |= SMI_LARB_THRT_RD_NU_LMT; | |
254 | writel_relaxed(reg, larb->base + SMI_LARB_CMD_THRT_CON); | |
255 | } | |
256 | ||
257 | if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_SW_FLAG)) | |
258 | writel_relaxed(SMI_LARB_SW_FLAG_1, larb->base + SMI_LARB_SW_FLAG); | |
259 | ||
260 | for (i = 0; i < SMI_LARB_PORT_NR_MAX && larbostd && !!larbostd[i]; i++) | |
261 | writel_relaxed(larbostd[i], larb->base + SMI_LARB_OSTDL_PORTx(i)); | |
262 | ||
4e508b25 CX |
263 | /* |
264 | * When mmu_en bits are in security world, the bank_sel still is in the | |
265 | * LARB_NONSEC_CON below. And the mmu_en bits of LARB_NONSEC_CON have no | |
266 | * effect in this case. | |
267 | */ | |
268 | if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_CFG_PORT_SEC_CTL)) { | |
269 | arm_smccc_smc(MTK_SIP_KERNEL_IOMMU_CONTROL, IOMMU_ATF_CMD_CONFIG_SMI_LARB, | |
270 | larb->larbid, *larb->mmu, 0, 0, 0, 0, &res); | |
271 | if (res.a0 != 0) { | |
272 | dev_err(dev, "Enable iommu fail, ret %ld\n", res.a0); | |
273 | return -EINVAL; | |
274 | } | |
275 | } | |
276 | ||
534e0ad2 YW |
277 | for_each_set_bit(i, (unsigned long *)larb->mmu, 32) { |
278 | reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i)); | |
279 | reg |= F_MMU_EN; | |
280 | reg |= BANK_SEL(larb->bank[i]); | |
281 | writel(reg, larb->base + SMI_LARB_NONSEC_CON(i)); | |
282 | } | |
8c1561ed | 283 | return 0; |
534e0ad2 | 284 | } |
a8529f3b | 285 | |
673e71df CX |
286 | static const u8 mtk_smi_larb_mt8188_ostd[][SMI_LARB_PORT_NR_MAX] = { |
287 | [0] = {0x02, 0x18, 0x22, 0x22, 0x01, 0x02, 0x0a,}, | |
288 | [1] = {0x12, 0x02, 0x14, 0x14, 0x01, 0x18, 0x0a,}, | |
289 | [2] = {0x12, 0x12, 0x12, 0x12, 0x0a,}, | |
290 | [3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,}, | |
291 | [4] = {0x06, 0x01, 0x17, 0x06, 0x0a, 0x07, 0x07,}, | |
292 | [5] = {0x02, 0x01, 0x04, 0x02, 0x06, 0x01, 0x06, 0x0a,}, | |
293 | [6] = {0x06, 0x01, 0x06, 0x0a,}, | |
294 | [7] = {0x0c, 0x0c, 0x12,}, | |
295 | [8] = {0x0c, 0x01, 0x0a, 0x05, 0x02, 0x03, 0x01, 0x01, 0x14, 0x14, | |
296 | 0x0a, 0x14, 0x1e, 0x01, 0x0c, 0x0a, 0x05, 0x02, 0x02, 0x05, | |
297 | 0x03, 0x01, 0x1e, 0x01, 0x05,}, | |
298 | [9] = {0x1e, 0x01, 0x0a, 0x0a, 0x01, 0x01, 0x03, 0x1e, 0x1e, 0x10, | |
299 | 0x07, 0x01, 0x0a, 0x06, 0x03, 0x03, 0x0e, 0x01, 0x04, 0x28,}, | |
300 | [10] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c, | |
301 | 0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14, | |
302 | 0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,}, | |
303 | [11] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c, | |
304 | 0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14, | |
305 | 0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,}, | |
306 | [12] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c, | |
307 | 0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14, | |
308 | 0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,}, | |
309 | [13] = {0x07, 0x02, 0x04, 0x02, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, | |
310 | 0x07, 0x02, 0x04, 0x02, 0x05, 0x05,}, | |
311 | [14] = {0x02, 0x02, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x01, 0x02, 0x02, | |
312 | 0x02, 0x02, 0x0c, 0x0c, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | |
313 | 0x02, 0x02, 0x01, 0x01,}, | |
314 | [15] = {0x0c, 0x0c, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x0c, 0x0c, | |
315 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, | |
316 | 0x0c, 0x01, 0x01,}, | |
317 | [16] = {0x28, 0x28, 0x03, 0x01, 0x01, 0x03, 0x14, 0x14, 0x0a, 0x0d, | |
318 | 0x03, 0x05, 0x0e, 0x01, 0x01, 0x05, 0x06, 0x0d, 0x01,}, | |
319 | [17] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a, | |
320 | 0x12, 0x02, 0x02, 0x0a, 0x16, 0x02, 0x04,}, | |
321 | [18] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a, | |
322 | 0x12, 0x02, 0x02, 0x0a, 0x16, 0x02, 0x04,}, | |
323 | [19] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, | |
324 | [20] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, | |
325 | [21] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, | |
326 | 0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06, | |
327 | 0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,}, | |
328 | [22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, | |
329 | 0x01,}, | |
330 | [23] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x18, 0x01, 0x01,}, | |
331 | [24] = {0x12, 0x06, 0x12, 0x06,}, | |
332 | [25] = {0x01}, | |
333 | }; | |
334 | ||
fe6dd2a4 YW |
335 | static const u8 mtk_smi_larb_mt8195_ostd[][SMI_LARB_PORT_NR_MAX] = { |
336 | [0] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb0 */ | |
337 | [1] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb1 */ | |
338 | [2] = {0x12, 0x12, 0x12, 0x12, 0x0a,}, /* ... */ | |
339 | [3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,}, | |
340 | [4] = {0x06, 0x01, 0x17, 0x06, 0x0a,}, | |
341 | [5] = {0x06, 0x01, 0x17, 0x06, 0x06, 0x01, 0x06, 0x0a,}, | |
342 | [6] = {0x06, 0x01, 0x06, 0x0a,}, | |
343 | [7] = {0x0c, 0x0c, 0x12,}, | |
344 | [8] = {0x0c, 0x0c, 0x12,}, | |
345 | [9] = {0x0a, 0x08, 0x04, 0x06, 0x01, 0x01, 0x10, 0x18, 0x11, 0x0a, | |
346 | 0x08, 0x04, 0x11, 0x06, 0x02, 0x06, 0x01, 0x11, 0x11, 0x06,}, | |
347 | [10] = {0x18, 0x08, 0x01, 0x01, 0x20, 0x12, 0x18, 0x06, 0x05, 0x10, | |
348 | 0x08, 0x08, 0x10, 0x08, 0x08, 0x18, 0x0c, 0x09, 0x0b, 0x0d, | |
349 | 0x0d, 0x06, 0x10, 0x10,}, | |
350 | [11] = {0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x01, 0x01, 0x01, 0x01,}, | |
351 | [12] = {0x09, 0x09, 0x05, 0x05, 0x0c, 0x18, 0x02, 0x02, 0x04, 0x02,}, | |
352 | [13] = {0x02, 0x02, 0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x08, 0x01,}, | |
353 | [14] = {0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x16, 0x01, 0x16, 0x01, | |
354 | 0x01, 0x02, 0x02, 0x08, 0x02,}, | |
355 | [15] = {}, | |
356 | [16] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a, | |
357 | 0x12, 0x02, 0x0a, 0x16, 0x02, 0x04,}, | |
358 | [17] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, | |
359 | [18] = {0x12, 0x06, 0x12, 0x06,}, | |
360 | [19] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, | |
361 | 0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06, | |
362 | 0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,}, | |
363 | [20] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, | |
364 | 0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06, | |
365 | 0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,}, | |
366 | [21] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,}, | |
367 | [22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,}, | |
368 | [23] = {0x18, 0x01,}, | |
369 | [24] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, | |
370 | 0x01, 0x01,}, | |
371 | [25] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16, | |
372 | 0x02, 0x01,}, | |
373 | [26] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16, | |
374 | 0x02, 0x01,}, | |
375 | [27] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16, | |
376 | 0x02, 0x01,}, | |
377 | [28] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, | |
378 | }; | |
379 | ||
3c8f4ad8 HZ |
380 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = { |
381 | .port_in_larb = { | |
382 | LARB0_PORT_OFFSET, LARB1_PORT_OFFSET, | |
383 | LARB2_PORT_OFFSET, LARB3_PORT_OFFSET | |
384 | }, | |
385 | .config_port = mtk_smi_larb_config_port_gen1, | |
386 | }; | |
387 | ||
e6dec923 | 388 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = { |
2e9b0908 YW |
389 | .config_port = mtk_smi_larb_config_port_gen2_general, |
390 | .larb_direct_to_common_mask = BIT(8) | BIT(9), /* bdpsys */ | |
e6dec923 YW |
391 | }; |
392 | ||
fc492f33 MFC |
393 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = { |
394 | .config_port = mtk_smi_larb_config_port_gen2_general, | |
395 | .larb_direct_to_common_mask = | |
396 | BIT(4) | BIT(6) | BIT(11) | BIT(12) | BIT(13), | |
397 | /* DUMMY | IPU0 | IPU1 | CCU | MDLA */ | |
398 | }; | |
399 | ||
534e0ad2 YW |
400 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = { |
401 | /* mt8167 do not need the port in larb */ | |
402 | .config_port = mtk_smi_larb_config_port_mt8167, | |
403 | }; | |
404 | ||
405 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = { | |
406 | /* mt8173 do not need the port in larb */ | |
407 | .config_port = mtk_smi_larb_config_port_mt8173, | |
408 | }; | |
409 | ||
907ba6a1 | 410 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = { |
907ba6a1 YW |
411 | .config_port = mtk_smi_larb_config_port_gen2_general, |
412 | .larb_direct_to_common_mask = BIT(2) | BIT(3) | BIT(7), | |
413 | /* IPU0 | IPU1 | CCU */ | |
414 | }; | |
415 | ||
86a010bf YW |
416 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8186 = { |
417 | .config_port = mtk_smi_larb_config_port_gen2_general, | |
418 | .flags_general = MTK_SMI_FLAG_SLEEP_CTL, | |
419 | }; | |
420 | ||
673e71df CX |
421 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8188 = { |
422 | .config_port = mtk_smi_larb_config_port_gen2_general, | |
423 | .flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG | | |
424 | MTK_SMI_FLAG_SLEEP_CTL | MTK_SMI_FLAG_CFG_PORT_SEC_CTL, | |
425 | .ostd = mtk_smi_larb_mt8188_ostd, | |
426 | }; | |
427 | ||
02c02ddc YW |
428 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = { |
429 | .config_port = mtk_smi_larb_config_port_gen2_general, | |
430 | }; | |
431 | ||
cc4f9dcd YW |
432 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8195 = { |
433 | .config_port = mtk_smi_larb_config_port_gen2_general, | |
12fbfd66 ADR |
434 | .flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG | |
435 | MTK_SMI_FLAG_SLEEP_CTL, | |
fe6dd2a4 | 436 | .ostd = mtk_smi_larb_mt8195_ostd, |
cc4f9dcd YW |
437 | }; |
438 | ||
3c8f4ad8 | 439 | static const struct of_device_id mtk_smi_larb_of_ids[] = { |
534e0ad2 YW |
440 | {.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701}, |
441 | {.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712}, | |
442 | {.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779}, | |
0d97f217 | 443 | {.compatible = "mediatek,mt6795-smi-larb", .data = &mtk_smi_larb_mt8173}, |
534e0ad2 YW |
444 | {.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167}, |
445 | {.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173}, | |
446 | {.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183}, | |
86a010bf | 447 | {.compatible = "mediatek,mt8186-smi-larb", .data = &mtk_smi_larb_mt8186}, |
673e71df | 448 | {.compatible = "mediatek,mt8188-smi-larb", .data = &mtk_smi_larb_mt8188}, |
534e0ad2 | 449 | {.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192}, |
cc4f9dcd | 450 | {.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195}, |
3c8f4ad8 HZ |
451 | {} |
452 | }; | |
453 | ||
8956500e YW |
454 | static int mtk_smi_larb_sleep_ctrl_enable(struct mtk_smi_larb *larb) |
455 | { | |
456 | int ret; | |
457 | u32 tmp; | |
458 | ||
459 | writel_relaxed(SLP_PROT_EN, larb->base + SMI_LARB_SLP_CON); | |
460 | ret = readl_poll_timeout_atomic(larb->base + SMI_LARB_SLP_CON, | |
461 | tmp, !!(tmp & SLP_PROT_RDY), 10, 1000); | |
462 | if (ret) { | |
463 | /* TODO: Reset this larb if it fails here. */ | |
464 | dev_err(larb->smi.dev, "sleep ctrl is not ready(0x%x).\n", tmp); | |
465 | } | |
466 | return ret; | |
467 | } | |
468 | ||
469 | static void mtk_smi_larb_sleep_ctrl_disable(struct mtk_smi_larb *larb) | |
470 | { | |
471 | writel_relaxed(0, larb->base + SMI_LARB_SLP_CON); | |
472 | } | |
473 | ||
47404757 YW |
474 | static int mtk_smi_device_link_common(struct device *dev, struct device **com_dev) |
475 | { | |
476 | struct platform_device *smi_com_pdev; | |
477 | struct device_node *smi_com_node; | |
478 | struct device *smi_com_dev; | |
479 | struct device_link *link; | |
480 | ||
481 | smi_com_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0); | |
482 | if (!smi_com_node) | |
483 | return -EINVAL; | |
484 | ||
485 | smi_com_pdev = of_find_device_by_node(smi_com_node); | |
486 | of_node_put(smi_com_node); | |
487 | if (smi_com_pdev) { | |
488 | /* smi common is the supplier, Make sure it is ready before */ | |
038ae37c ML |
489 | if (!platform_get_drvdata(smi_com_pdev)) { |
490 | put_device(&smi_com_pdev->dev); | |
47404757 | 491 | return -EPROBE_DEFER; |
038ae37c | 492 | } |
47404757 YW |
493 | smi_com_dev = &smi_com_pdev->dev; |
494 | link = device_link_add(dev, smi_com_dev, | |
495 | DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); | |
496 | if (!link) { | |
497 | dev_err(dev, "Unable to link smi-common dev\n"); | |
038ae37c | 498 | put_device(&smi_com_pdev->dev); |
47404757 YW |
499 | return -ENODEV; |
500 | } | |
501 | *com_dev = smi_com_dev; | |
502 | } else { | |
503 | dev_err(dev, "Failed to get the smi_common device\n"); | |
504 | return -EINVAL; | |
505 | } | |
506 | return 0; | |
507 | } | |
508 | ||
0e14917c YW |
509 | static int mtk_smi_dts_clk_init(struct device *dev, struct mtk_smi *smi, |
510 | const char * const clks[], | |
511 | unsigned int clk_nr_required, | |
512 | unsigned int clk_nr_optional) | |
513 | { | |
514 | int i, ret; | |
515 | ||
516 | for (i = 0; i < clk_nr_required; i++) | |
517 | smi->clks[i].id = clks[i]; | |
518 | ret = devm_clk_bulk_get(dev, clk_nr_required, smi->clks); | |
519 | if (ret) | |
520 | return ret; | |
521 | ||
522 | for (i = clk_nr_required; i < clk_nr_required + clk_nr_optional; i++) | |
523 | smi->clks[i].id = clks[i]; | |
524 | ret = devm_clk_bulk_get_optional(dev, clk_nr_optional, | |
525 | smi->clks + clk_nr_required); | |
526 | smi->clk_num = clk_nr_required + clk_nr_optional; | |
527 | return ret; | |
528 | } | |
529 | ||
cc8bbe1a YW |
530 | static int mtk_smi_larb_probe(struct platform_device *pdev) |
531 | { | |
532 | struct mtk_smi_larb *larb; | |
cc8bbe1a | 533 | struct device *dev = &pdev->dev; |
0e14917c | 534 | int ret; |
cc8bbe1a | 535 | |
cc8bbe1a YW |
536 | larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); |
537 | if (!larb) | |
538 | return -ENOMEM; | |
539 | ||
75487860 | 540 | larb->larb_gen = of_device_get_match_data(dev); |
912fea8b | 541 | larb->base = devm_platform_ioremap_resource(pdev, 0); |
cc8bbe1a YW |
542 | if (IS_ERR(larb->base)) |
543 | return PTR_ERR(larb->base); | |
544 | ||
0e14917c YW |
545 | ret = mtk_smi_dts_clk_init(dev, &larb->smi, mtk_smi_larb_clks, |
546 | MTK_SMI_LARB_REQ_CLK_NR, MTK_SMI_LARB_OPT_CLK_NR); | |
547 | if (ret) | |
548 | return ret; | |
cc8bbe1a | 549 | |
0e14917c | 550 | larb->smi.dev = dev; |
cc8bbe1a | 551 | |
47404757 YW |
552 | ret = mtk_smi_device_link_common(dev, &larb->smi_common_dev); |
553 | if (ret < 0) | |
554 | return ret; | |
cc8bbe1a YW |
555 | |
556 | pm_runtime_enable(dev); | |
557 | platform_set_drvdata(pdev, larb); | |
30b869e7 YW |
558 | ret = component_add(dev, &mtk_smi_larb_component_ops); |
559 | if (ret) | |
560 | goto err_pm_disable; | |
561 | return 0; | |
562 | ||
563 | err_pm_disable: | |
564 | pm_runtime_disable(dev); | |
565 | device_link_remove(dev, larb->smi_common_dev); | |
566 | return ret; | |
cc8bbe1a YW |
567 | } |
568 | ||
569 | static int mtk_smi_larb_remove(struct platform_device *pdev) | |
570 | { | |
6ce2c05b YW |
571 | struct mtk_smi_larb *larb = platform_get_drvdata(pdev); |
572 | ||
573 | device_link_remove(&pdev->dev, larb->smi_common_dev); | |
cc8bbe1a YW |
574 | pm_runtime_disable(&pdev->dev); |
575 | component_del(&pdev->dev, &mtk_smi_larb_component_ops); | |
576 | return 0; | |
577 | } | |
578 | ||
4f0a1a1a YW |
579 | static int __maybe_unused mtk_smi_larb_resume(struct device *dev) |
580 | { | |
581 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); | |
582 | const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; | |
583 | int ret; | |
584 | ||
0e14917c | 585 | ret = clk_bulk_prepare_enable(larb->smi.clk_num, larb->smi.clks); |
a6945f45 | 586 | if (ret) |
4f0a1a1a | 587 | return ret; |
4f0a1a1a | 588 | |
8956500e YW |
589 | if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL)) |
590 | mtk_smi_larb_sleep_ctrl_disable(larb); | |
591 | ||
4f0a1a1a | 592 | /* Configure the basic setting for this larb */ |
8c1561ed | 593 | return larb_gen->config_port(dev); |
4f0a1a1a YW |
594 | } |
595 | ||
596 | static int __maybe_unused mtk_smi_larb_suspend(struct device *dev) | |
597 | { | |
598 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); | |
8956500e YW |
599 | int ret; |
600 | ||
601 | if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL)) { | |
602 | ret = mtk_smi_larb_sleep_ctrl_enable(larb); | |
603 | if (ret) | |
604 | return ret; | |
605 | } | |
4f0a1a1a | 606 | |
0e14917c | 607 | clk_bulk_disable_unprepare(larb->smi.clk_num, larb->smi.clks); |
4f0a1a1a YW |
608 | return 0; |
609 | } | |
610 | ||
611 | static const struct dev_pm_ops smi_larb_pm_ops = { | |
612 | SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL) | |
fb03082a YW |
613 | SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
614 | pm_runtime_force_resume) | |
4f0a1a1a YW |
615 | }; |
616 | ||
cc8bbe1a YW |
617 | static struct platform_driver mtk_smi_larb_driver = { |
618 | .probe = mtk_smi_larb_probe, | |
3c8f4ad8 | 619 | .remove = mtk_smi_larb_remove, |
cc8bbe1a YW |
620 | .driver = { |
621 | .name = "mtk-smi-larb", | |
622 | .of_match_table = mtk_smi_larb_of_ids, | |
4f0a1a1a | 623 | .pm = &smi_larb_pm_ops, |
cc8bbe1a YW |
624 | } |
625 | }; | |
626 | ||
0d97f217 ADR |
627 | static const struct mtk_smi_reg_pair mtk_smi_common_mt6795_init[SMI_COMMON_INIT_REGS_NR] = { |
628 | {SMI_L1_ARB, 0x1b}, | |
629 | {SMI_M4U_TH, 0xce810c85}, | |
630 | {SMI_FIFO_TH1, 0x43214c8}, | |
631 | {SMI_READ_FIFO_TH, 0x191f}, | |
632 | }; | |
633 | ||
431e9cab YW |
634 | static const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = { |
635 | {SMI_L1LEN, 0xb}, | |
636 | {SMI_M4U_TH, 0xe100e10}, | |
637 | {SMI_FIFO_TH1, 0x506090a}, | |
638 | {SMI_FIFO_TH2, 0x506090a}, | |
639 | {SMI_DCM, 0x4f1}, | |
640 | {SMI_DUMMY, 0x1}, | |
641 | }; | |
642 | ||
42d42c76 | 643 | static const struct mtk_smi_common_plat mtk_smi_common_gen1 = { |
a5c18986 | 644 | .type = MTK_SMI_GEN1, |
42d42c76 YW |
645 | }; |
646 | ||
647 | static const struct mtk_smi_common_plat mtk_smi_common_gen2 = { | |
a5c18986 | 648 | .type = MTK_SMI_GEN2, |
42d42c76 YW |
649 | }; |
650 | ||
fc492f33 | 651 | static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = { |
a5c18986 YW |
652 | .type = MTK_SMI_GEN2, |
653 | .has_gals = true, | |
654 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) | | |
655 | F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7), | |
fc492f33 MFC |
656 | }; |
657 | ||
0d97f217 ADR |
658 | static const struct mtk_smi_common_plat mtk_smi_common_mt6795 = { |
659 | .type = MTK_SMI_GEN2, | |
660 | .bus_sel = F_MMU1_LARB(0), | |
661 | .init = mtk_smi_common_mt6795_init, | |
662 | }; | |
663 | ||
907ba6a1 | 664 | static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = { |
a5c18986 | 665 | .type = MTK_SMI_GEN2, |
907ba6a1 | 666 | .has_gals = true, |
567e58cf YW |
667 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) | |
668 | F_MMU1_LARB(7), | |
907ba6a1 YW |
669 | }; |
670 | ||
86a010bf YW |
671 | static const struct mtk_smi_common_plat mtk_smi_common_mt8186 = { |
672 | .type = MTK_SMI_GEN2, | |
673 | .has_gals = true, | |
674 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(4) | F_MMU1_LARB(7), | |
675 | }; | |
676 | ||
673e71df CX |
677 | static const struct mtk_smi_common_plat mtk_smi_common_mt8188_vdo = { |
678 | .type = MTK_SMI_GEN2, | |
679 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(5) | F_MMU1_LARB(7), | |
680 | .init = mtk_smi_common_mt8195_init, | |
681 | }; | |
682 | ||
683 | static const struct mtk_smi_common_plat mtk_smi_common_mt8188_vpp = { | |
684 | .type = MTK_SMI_GEN2, | |
685 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7), | |
686 | .init = mtk_smi_common_mt8195_init, | |
687 | }; | |
688 | ||
02c02ddc | 689 | static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = { |
a5c18986 | 690 | .type = MTK_SMI_GEN2, |
02c02ddc YW |
691 | .has_gals = true, |
692 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) | | |
693 | F_MMU1_LARB(6), | |
694 | }; | |
695 | ||
cc4f9dcd YW |
696 | static const struct mtk_smi_common_plat mtk_smi_common_mt8195_vdo = { |
697 | .type = MTK_SMI_GEN2, | |
698 | .has_gals = true, | |
699 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(3) | F_MMU1_LARB(5) | | |
700 | F_MMU1_LARB(7), | |
431e9cab | 701 | .init = mtk_smi_common_mt8195_init, |
cc4f9dcd YW |
702 | }; |
703 | ||
704 | static const struct mtk_smi_common_plat mtk_smi_common_mt8195_vpp = { | |
705 | .type = MTK_SMI_GEN2, | |
706 | .has_gals = true, | |
707 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7), | |
431e9cab | 708 | .init = mtk_smi_common_mt8195_init, |
cc4f9dcd YW |
709 | }; |
710 | ||
711 | static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = { | |
712 | .type = MTK_SMI_GEN2_SUB_COMM, | |
713 | .has_gals = true, | |
714 | }; | |
715 | ||
3c8f4ad8 | 716 | static const struct of_device_id mtk_smi_common_of_ids[] = { |
534e0ad2 YW |
717 | {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1}, |
718 | {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2}, | |
719 | {.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779}, | |
0d97f217 | 720 | {.compatible = "mediatek,mt6795-smi-common", .data = &mtk_smi_common_mt6795}, |
534e0ad2 YW |
721 | {.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2}, |
722 | {.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2}, | |
723 | {.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183}, | |
86a010bf | 724 | {.compatible = "mediatek,mt8186-smi-common", .data = &mtk_smi_common_mt8186}, |
673e71df CX |
725 | {.compatible = "mediatek,mt8188-smi-common-vdo", .data = &mtk_smi_common_mt8188_vdo}, |
726 | {.compatible = "mediatek,mt8188-smi-common-vpp", .data = &mtk_smi_common_mt8188_vpp}, | |
534e0ad2 | 727 | {.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192}, |
cc4f9dcd YW |
728 | {.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo}, |
729 | {.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp}, | |
730 | {.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195}, | |
3c8f4ad8 HZ |
731 | {} |
732 | }; | |
733 | ||
cc8bbe1a YW |
734 | static int mtk_smi_common_probe(struct platform_device *pdev) |
735 | { | |
736 | struct device *dev = &pdev->dev; | |
737 | struct mtk_smi *common; | |
0e14917c | 738 | int ret, clk_required = MTK_SMI_COM_REQ_CLK_NR; |
cc8bbe1a | 739 | |
cc8bbe1a YW |
740 | common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); |
741 | if (!common) | |
742 | return -ENOMEM; | |
743 | common->dev = dev; | |
42d42c76 | 744 | common->plat = of_device_get_match_data(dev); |
cc8bbe1a | 745 | |
3e4f74e0 YW |
746 | if (common->plat->has_gals) { |
747 | if (common->plat->type == MTK_SMI_GEN2) | |
748 | clk_required = MTK_SMI_COM_GALS_REQ_CLK_NR; | |
749 | else if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) | |
750 | clk_required = MTK_SMI_SUB_COM_GALS_REQ_CLK_NR; | |
751 | } | |
0e14917c YW |
752 | ret = mtk_smi_dts_clk_init(dev, common, mtk_smi_common_clks, clk_required, 0); |
753 | if (ret) | |
754 | return ret; | |
64fea74a | 755 | |
3c8f4ad8 HZ |
756 | /* |
757 | * for mtk smi gen 1, we need to get the ao(always on) base to config | |
758 | * m4u port, and we need to enable the aync clock for transform the smi | |
759 | * clock into emi clock domain, but for mtk smi gen2, there's no smi ao | |
760 | * base. | |
761 | */ | |
a5c18986 | 762 | if (common->plat->type == MTK_SMI_GEN1) { |
912fea8b | 763 | common->smi_ao_base = devm_platform_ioremap_resource(pdev, 0); |
3c8f4ad8 HZ |
764 | if (IS_ERR(common->smi_ao_base)) |
765 | return PTR_ERR(common->smi_ao_base); | |
766 | ||
767 | common->clk_async = devm_clk_get(dev, "async"); | |
768 | if (IS_ERR(common->clk_async)) | |
769 | return PTR_ERR(common->clk_async); | |
770 | ||
46cc815d AY |
771 | ret = clk_prepare_enable(common->clk_async); |
772 | if (ret) | |
773 | return ret; | |
567e58cf | 774 | } else { |
912fea8b | 775 | common->base = devm_platform_ioremap_resource(pdev, 0); |
567e58cf YW |
776 | if (IS_ERR(common->base)) |
777 | return PTR_ERR(common->base); | |
3c8f4ad8 | 778 | } |
47404757 YW |
779 | |
780 | /* link its smi-common if this is smi-sub-common */ | |
781 | if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) { | |
782 | ret = mtk_smi_device_link_common(dev, &common->smi_common_dev); | |
783 | if (ret < 0) | |
784 | return ret; | |
785 | } | |
786 | ||
cc8bbe1a YW |
787 | pm_runtime_enable(dev); |
788 | platform_set_drvdata(pdev, common); | |
789 | return 0; | |
790 | } | |
791 | ||
792 | static int mtk_smi_common_remove(struct platform_device *pdev) | |
793 | { | |
47404757 YW |
794 | struct mtk_smi *common = dev_get_drvdata(&pdev->dev); |
795 | ||
796 | if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) | |
797 | device_link_remove(&pdev->dev, common->smi_common_dev); | |
cc8bbe1a YW |
798 | pm_runtime_disable(&pdev->dev); |
799 | return 0; | |
800 | } | |
801 | ||
4f0a1a1a YW |
802 | static int __maybe_unused mtk_smi_common_resume(struct device *dev) |
803 | { | |
804 | struct mtk_smi *common = dev_get_drvdata(dev); | |
431e9cab YW |
805 | const struct mtk_smi_reg_pair *init = common->plat->init; |
806 | u32 bus_sel = common->plat->bus_sel; /* default is 0 */ | |
807 | int ret, i; | |
4f0a1a1a | 808 | |
0e14917c YW |
809 | ret = clk_bulk_prepare_enable(common->clk_num, common->clks); |
810 | if (ret) | |
4f0a1a1a | 811 | return ret; |
567e58cf | 812 | |
431e9cab YW |
813 | if (common->plat->type != MTK_SMI_GEN2) |
814 | return 0; | |
815 | ||
816 | for (i = 0; i < SMI_COMMON_INIT_REGS_NR && init && init[i].offset; i++) | |
817 | writel_relaxed(init[i].value, common->base + init[i].offset); | |
818 | ||
819 | writel(bus_sel, common->base + SMI_BUS_SEL); | |
4f0a1a1a YW |
820 | return 0; |
821 | } | |
822 | ||
823 | static int __maybe_unused mtk_smi_common_suspend(struct device *dev) | |
824 | { | |
825 | struct mtk_smi *common = dev_get_drvdata(dev); | |
826 | ||
0e14917c | 827 | clk_bulk_disable_unprepare(common->clk_num, common->clks); |
4f0a1a1a YW |
828 | return 0; |
829 | } | |
830 | ||
831 | static const struct dev_pm_ops smi_common_pm_ops = { | |
832 | SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL) | |
fb03082a YW |
833 | SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
834 | pm_runtime_force_resume) | |
4f0a1a1a YW |
835 | }; |
836 | ||
cc8bbe1a YW |
837 | static struct platform_driver mtk_smi_common_driver = { |
838 | .probe = mtk_smi_common_probe, | |
839 | .remove = mtk_smi_common_remove, | |
840 | .driver = { | |
841 | .name = "mtk-smi-common", | |
842 | .of_match_table = mtk_smi_common_of_ids, | |
4f0a1a1a | 843 | .pm = &smi_common_pm_ops, |
cc8bbe1a YW |
844 | } |
845 | }; | |
846 | ||
18212031 YW |
847 | static struct platform_driver * const smidrivers[] = { |
848 | &mtk_smi_common_driver, | |
849 | &mtk_smi_larb_driver, | |
850 | }; | |
851 | ||
cc8bbe1a YW |
852 | static int __init mtk_smi_init(void) |
853 | { | |
18212031 | 854 | return platform_register_drivers(smidrivers, ARRAY_SIZE(smidrivers)); |
cc8bbe1a | 855 | } |
4f608d38 | 856 | module_init(mtk_smi_init); |
50fc8d92 YW |
857 | |
858 | static void __exit mtk_smi_exit(void) | |
859 | { | |
860 | platform_unregister_drivers(smidrivers, ARRAY_SIZE(smidrivers)); | |
861 | } | |
862 | module_exit(mtk_smi_exit); | |
863 | ||
864 | MODULE_DESCRIPTION("MediaTek SMI driver"); | |
865 | MODULE_LICENSE("GPL v2"); |