1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015-2016 MediaTek Inc. |
4 | * Author: Yong Wu <yong.wu@mediatek.com> |
5 | */ |
6 | #include <linux/arm-smccc.h> |
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> |
12 | #include <linux/iopoll.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of.h> |
15 | #include <linux/of_platform.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/pm_runtime.h> |
18 | #include <linux/soc/mediatek/mtk_sip_svc.h> |
19 | #include <soc/mediatek/smi.h> |
20 | #include <dt-bindings/memory/mt2701-larb-port.h> |
21 | #include <dt-bindings/memory/mtk-memory-port.h> |
22 | |
23 | /* SMI COMMON */ |
24 | #define SMI_L1LEN 0x100 |
25 | |
26 | #define SMI_L1_ARB 0x200 |
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)) |
31 | |
32 | #define SMI_READ_FIFO_TH 0x230 |
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 | |
39 | /* SMI LARB */ |
40 | #define SMI_LARB_SLP_CON 0xc |
41 | #define SLP_PROT_EN BIT(0) |
42 | #define SLP_PROT_RDY BIT(16) |
43 | |
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)) |
53 | |
54 | /* Below are about mmu enable registers, they are different in SoCs */ |
55 | /* gen1: mt2701 */ |
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 | |
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) ({ \ |
84 | u32 _id = (id) & 0x3; \ |
85 | (_id << 8 | _id << 10 | _id << 12 | _id << 14); \ |
86 | }) |
87 | |
88 | #define SMI_COMMON_INIT_REGS_NR 6 |
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) |
93 | #define MTK_SMI_FLAG_SLEEP_CTL BIT(2) |
94 | #define MTK_SMI_FLAG_CFG_PORT_SEC_CTL BIT(3) |
95 | #define MTK_SMI_CAPS(flags, _x) (!!((flags) & (_x))) |
96 | |
97 | struct mtk_smi_reg_pair { |
98 | unsigned int offset; |
99 | u32 value; |
100 | }; |
101 | |
102 | enum mtk_smi_type { |
103 | MTK_SMI_GEN1, |
104 | MTK_SMI_GEN2, /* gen2 smi common */ |
105 | MTK_SMI_GEN2_SUB_COMM, /* gen2 smi sub common */ |
106 | }; |
107 | |
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. |
115 | * sub common: Require apb/smi/gals0 clocks in has_gals case. Otherwise, only apb/smi are required. |
116 | */ |
117 | static const char * const mtk_smi_common_clks[] = {"apb" , "smi" , "gals0" , "gals1" }; |
118 | #define MTK_SMI_CLK_NR_MAX ARRAY_SIZE(mtk_smi_common_clks) |
119 | #define MTK_SMI_COM_REQ_CLK_NR 2 |
120 | #define MTK_SMI_COM_GALS_REQ_CLK_NR MTK_SMI_CLK_NR_MAX |
121 | #define MTK_SMI_SUB_COM_GALS_REQ_CLK_NR 3 |
122 | |
123 | struct mtk_smi_common_plat { |
124 | enum mtk_smi_type type; |
125 | bool has_gals; |
126 | u32 bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */ |
127 | |
128 | const struct mtk_smi_reg_pair *init; |
129 | }; |
130 | |
131 | struct mtk_smi_larb_gen { |
132 | int port_in_larb[MTK_LARB_NR_MAX + 1]; |
133 | int (*config_port)(struct device *dev); |
134 | unsigned int larb_direct_to_common_mask; |
135 | unsigned int flags_general; |
136 | const u8 (*ostd)[SMI_LARB_PORT_NR_MAX]; |
137 | }; |
138 | |
139 | struct mtk_smi { |
140 | struct device *dev; |
141 | unsigned int clk_num; |
142 | struct clk_bulk_data clks[MTK_SMI_CLK_NR_MAX]; |
143 | struct clk *clk_async; /*only needed by mt2701*/ |
144 | union { |
145 | void __iomem *smi_ao_base; /* only for gen1 */ |
146 | void __iomem *base; /* only for gen2 */ |
147 | }; |
148 | struct device *smi_common_dev; /* for sub common */ |
149 | const struct mtk_smi_common_plat *plat; |
150 | }; |
151 | |
152 | struct mtk_smi_larb { /* larb: local arbiter */ |
153 | struct mtk_smi smi; |
154 | void __iomem *base; |
155 | struct device *smi_common_dev; /* common or sub-common dev */ |
156 | const struct mtk_smi_larb_gen *larb_gen; |
157 | int larbid; |
158 | u32 *mmu; |
159 | unsigned char *bank; |
160 | }; |
161 | |
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); |
166 | struct mtk_smi_larb_iommu *larb_mmu = data; |
167 | unsigned int i; |
168 | |
169 | for (i = 0; i < MTK_LARB_NR_MAX; i++) { |
170 | if (dev == larb_mmu[i].dev) { |
171 | larb->larbid = i; |
172 | larb->mmu = &larb_mmu[i].mmu; |
173 | larb->bank = larb_mmu[i].bank; |
174 | return 0; |
175 | } |
176 | } |
177 | return -ENODEV; |
178 | } |
179 | |
180 | static void |
181 | mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) |
182 | { |
183 | /* Do nothing as the iommu is always enabled. */ |
184 | } |
185 | |
186 | static const struct component_ops mtk_smi_larb_component_ops = { |
187 | .bind = mtk_smi_larb_bind, |
188 | .unbind = mtk_smi_larb_unbind, |
189 | }; |
190 | |
191 | static int mtk_smi_larb_config_port_gen1(struct device *dev) |
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(dev: 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(addr: 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(val: reg_val, |
217 | addr: common->smi_ao_base |
218 | + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); |
219 | } |
220 | return 0; |
221 | } |
222 | |
223 | static int mtk_smi_larb_config_port_mt8167(struct device *dev) |
224 | { |
225 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); |
226 | |
227 | writel(val: *larb->mmu, addr: larb->base + MT8167_SMI_LARB_MMU_EN); |
228 | return 0; |
229 | } |
230 | |
231 | static int mtk_smi_larb_config_port_mt8173(struct device *dev) |
232 | { |
233 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); |
234 | |
235 | writel(val: *larb->mmu, addr: larb->base + MT8173_SMI_LARB_MMU_EN); |
236 | return 0; |
237 | } |
238 | |
239 | static int mtk_smi_larb_config_port_gen2_general(struct device *dev) |
240 | { |
241 | struct mtk_smi_larb *larb = dev_get_drvdata(dev); |
242 | u32 reg, flags_general = larb->larb_gen->flags_general; |
243 | const u8 *larbostd = larb->larb_gen->ostd ? larb->larb_gen->ostd[larb->larbid] : NULL; |
244 | struct arm_smccc_res res; |
245 | int i; |
246 | |
247 | if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask) |
248 | return 0; |
249 | |
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 | |
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 | |
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(val: reg, addr: larb->base + SMI_LARB_NONSEC_CON(i)); |
282 | } |
283 | return 0; |
284 | } |
285 | |
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 | |
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 | |
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 | |
388 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = { |
389 | .config_port = mtk_smi_larb_config_port_gen2_general, |
390 | .larb_direct_to_common_mask = BIT(8) | BIT(9), /* bdpsys */ |
391 | }; |
392 | |
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 | |
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 | |
410 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = { |
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 | |
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 | |
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 | |
428 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = { |
429 | .config_port = mtk_smi_larb_config_port_gen2_general, |
430 | }; |
431 | |
432 | static const struct mtk_smi_larb_gen mtk_smi_larb_mt8195 = { |
433 | .config_port = mtk_smi_larb_config_port_gen2_general, |
434 | .flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG | |
435 | MTK_SMI_FLAG_SLEEP_CTL, |
436 | .ostd = mtk_smi_larb_mt8195_ostd, |
437 | }; |
438 | |
439 | static const struct of_device_id mtk_smi_larb_of_ids[] = { |
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}, |
443 | {.compatible = "mediatek,mt6795-smi-larb" , .data = &mtk_smi_larb_mt8173}, |
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}, |
447 | {.compatible = "mediatek,mt8186-smi-larb" , .data = &mtk_smi_larb_mt8186}, |
448 | {.compatible = "mediatek,mt8188-smi-larb" , .data = &mtk_smi_larb_mt8188}, |
449 | {.compatible = "mediatek,mt8192-smi-larb" , .data = &mtk_smi_larb_mt8192}, |
450 | {.compatible = "mediatek,mt8195-smi-larb" , .data = &mtk_smi_larb_mt8195}, |
451 | {} |
452 | }; |
453 | |
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 | |
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(np: dev->of_node, phandle_name: "mediatek,smi" , index: 0); |
482 | if (!smi_com_node) |
483 | return -EINVAL; |
484 | |
485 | smi_com_pdev = of_find_device_by_node(np: smi_com_node); |
486 | of_node_put(node: smi_com_node); |
487 | if (smi_com_pdev) { |
488 | /* smi common is the supplier, Make sure it is ready before */ |
489 | if (!platform_get_drvdata(pdev: smi_com_pdev)) { |
490 | put_device(dev: &smi_com_pdev->dev); |
491 | return -EPROBE_DEFER; |
492 | } |
493 | smi_com_dev = &smi_com_pdev->dev; |
494 | link = device_link_add(consumer: dev, supplier: 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" ); |
498 | put_device(dev: &smi_com_pdev->dev); |
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 | |
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, num_clks: clk_nr_required, clks: 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, num_clks: clk_nr_optional, |
525 | clks: smi->clks + clk_nr_required); |
526 | smi->clk_num = clk_nr_required + clk_nr_optional; |
527 | return ret; |
528 | } |
529 | |
530 | static int mtk_smi_larb_probe(struct platform_device *pdev) |
531 | { |
532 | struct mtk_smi_larb *larb; |
533 | struct device *dev = &pdev->dev; |
534 | int ret; |
535 | |
536 | larb = devm_kzalloc(dev, size: sizeof(*larb), GFP_KERNEL); |
537 | if (!larb) |
538 | return -ENOMEM; |
539 | |
540 | larb->larb_gen = of_device_get_match_data(dev); |
541 | larb->base = devm_platform_ioremap_resource(pdev, index: 0); |
542 | if (IS_ERR(ptr: larb->base)) |
543 | return PTR_ERR(ptr: larb->base); |
544 | |
545 | ret = mtk_smi_dts_clk_init(dev, smi: &larb->smi, clks: mtk_smi_larb_clks, |
546 | MTK_SMI_LARB_REQ_CLK_NR, MTK_SMI_LARB_OPT_CLK_NR); |
547 | if (ret) |
548 | return ret; |
549 | |
550 | larb->smi.dev = dev; |
551 | |
552 | ret = mtk_smi_device_link_common(dev, com_dev: &larb->smi_common_dev); |
553 | if (ret < 0) |
554 | return ret; |
555 | |
556 | pm_runtime_enable(dev); |
557 | platform_set_drvdata(pdev, data: larb); |
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(consumer: dev, supplier: larb->smi_common_dev); |
566 | return ret; |
567 | } |
568 | |
569 | static int mtk_smi_larb_remove(struct platform_device *pdev) |
570 | { |
571 | struct mtk_smi_larb *larb = platform_get_drvdata(pdev); |
572 | |
573 | device_link_remove(consumer: &pdev->dev, supplier: larb->smi_common_dev); |
574 | pm_runtime_disable(dev: &pdev->dev); |
575 | component_del(&pdev->dev, &mtk_smi_larb_component_ops); |
576 | return 0; |
577 | } |
578 | |
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 | |
585 | ret = clk_bulk_prepare_enable(num_clks: larb->smi.clk_num, clks: larb->smi.clks); |
586 | if (ret) |
587 | return ret; |
588 | |
589 | if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL)) |
590 | mtk_smi_larb_sleep_ctrl_disable(larb); |
591 | |
592 | /* Configure the basic setting for this larb */ |
593 | return larb_gen->config_port(dev); |
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); |
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 | } |
606 | |
607 | clk_bulk_disable_unprepare(num_clks: larb->smi.clk_num, clks: larb->smi.clks); |
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) |
613 | SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
614 | pm_runtime_force_resume) |
615 | }; |
616 | |
617 | static struct platform_driver mtk_smi_larb_driver = { |
618 | .probe = mtk_smi_larb_probe, |
619 | .remove = mtk_smi_larb_remove, |
620 | .driver = { |
621 | .name = "mtk-smi-larb" , |
622 | .of_match_table = mtk_smi_larb_of_ids, |
623 | .pm = &smi_larb_pm_ops, |
624 | } |
625 | }; |
626 | |
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 | |
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 | |
643 | static const struct mtk_smi_common_plat mtk_smi_common_gen1 = { |
644 | .type = MTK_SMI_GEN1, |
645 | }; |
646 | |
647 | static const struct mtk_smi_common_plat mtk_smi_common_gen2 = { |
648 | .type = MTK_SMI_GEN2, |
649 | }; |
650 | |
651 | static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = { |
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), |
656 | }; |
657 | |
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 | |
664 | static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = { |
665 | .type = MTK_SMI_GEN2, |
666 | .has_gals = true, |
667 | .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) | |
668 | F_MMU1_LARB(7), |
669 | }; |
670 | |
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 | |
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 | |
689 | static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = { |
690 | .type = MTK_SMI_GEN2, |
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 | |
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), |
701 | .init = mtk_smi_common_mt8195_init, |
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), |
708 | .init = mtk_smi_common_mt8195_init, |
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 | |
716 | static const struct mtk_smi_common_plat mtk_smi_common_mt8365 = { |
717 | .type = MTK_SMI_GEN2, |
718 | .bus_sel = F_MMU1_LARB(2) | F_MMU1_LARB(4), |
719 | }; |
720 | |
721 | static const struct of_device_id mtk_smi_common_of_ids[] = { |
722 | {.compatible = "mediatek,mt2701-smi-common" , .data = &mtk_smi_common_gen1}, |
723 | {.compatible = "mediatek,mt2712-smi-common" , .data = &mtk_smi_common_gen2}, |
724 | {.compatible = "mediatek,mt6779-smi-common" , .data = &mtk_smi_common_mt6779}, |
725 | {.compatible = "mediatek,mt6795-smi-common" , .data = &mtk_smi_common_mt6795}, |
726 | {.compatible = "mediatek,mt8167-smi-common" , .data = &mtk_smi_common_gen2}, |
727 | {.compatible = "mediatek,mt8173-smi-common" , .data = &mtk_smi_common_gen2}, |
728 | {.compatible = "mediatek,mt8183-smi-common" , .data = &mtk_smi_common_mt8183}, |
729 | {.compatible = "mediatek,mt8186-smi-common" , .data = &mtk_smi_common_mt8186}, |
730 | {.compatible = "mediatek,mt8188-smi-common-vdo" , .data = &mtk_smi_common_mt8188_vdo}, |
731 | {.compatible = "mediatek,mt8188-smi-common-vpp" , .data = &mtk_smi_common_mt8188_vpp}, |
732 | {.compatible = "mediatek,mt8192-smi-common" , .data = &mtk_smi_common_mt8192}, |
733 | {.compatible = "mediatek,mt8195-smi-common-vdo" , .data = &mtk_smi_common_mt8195_vdo}, |
734 | {.compatible = "mediatek,mt8195-smi-common-vpp" , .data = &mtk_smi_common_mt8195_vpp}, |
735 | {.compatible = "mediatek,mt8195-smi-sub-common" , .data = &mtk_smi_sub_common_mt8195}, |
736 | {.compatible = "mediatek,mt8365-smi-common" , .data = &mtk_smi_common_mt8365}, |
737 | {} |
738 | }; |
739 | |
740 | static int mtk_smi_common_probe(struct platform_device *pdev) |
741 | { |
742 | struct device *dev = &pdev->dev; |
743 | struct mtk_smi *common; |
744 | int ret, clk_required = MTK_SMI_COM_REQ_CLK_NR; |
745 | |
746 | common = devm_kzalloc(dev, size: sizeof(*common), GFP_KERNEL); |
747 | if (!common) |
748 | return -ENOMEM; |
749 | common->dev = dev; |
750 | common->plat = of_device_get_match_data(dev); |
751 | |
752 | if (common->plat->has_gals) { |
753 | if (common->plat->type == MTK_SMI_GEN2) |
754 | clk_required = MTK_SMI_COM_GALS_REQ_CLK_NR; |
755 | else if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) |
756 | clk_required = MTK_SMI_SUB_COM_GALS_REQ_CLK_NR; |
757 | } |
758 | ret = mtk_smi_dts_clk_init(dev, smi: common, clks: mtk_smi_common_clks, clk_nr_required: clk_required, clk_nr_optional: 0); |
759 | if (ret) |
760 | return ret; |
761 | |
762 | /* |
763 | * for mtk smi gen 1, we need to get the ao(always on) base to config |
764 | * m4u port, and we need to enable the aync clock for transform the smi |
765 | * clock into emi clock domain, but for mtk smi gen2, there's no smi ao |
766 | * base. |
767 | */ |
768 | if (common->plat->type == MTK_SMI_GEN1) { |
769 | common->smi_ao_base = devm_platform_ioremap_resource(pdev, index: 0); |
770 | if (IS_ERR(ptr: common->smi_ao_base)) |
771 | return PTR_ERR(ptr: common->smi_ao_base); |
772 | |
773 | common->clk_async = devm_clk_get(dev, id: "async" ); |
774 | if (IS_ERR(ptr: common->clk_async)) |
775 | return PTR_ERR(ptr: common->clk_async); |
776 | |
777 | ret = clk_prepare_enable(clk: common->clk_async); |
778 | if (ret) |
779 | return ret; |
780 | } else { |
781 | common->base = devm_platform_ioremap_resource(pdev, index: 0); |
782 | if (IS_ERR(ptr: common->base)) |
783 | return PTR_ERR(ptr: common->base); |
784 | } |
785 | |
786 | /* link its smi-common if this is smi-sub-common */ |
787 | if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) { |
788 | ret = mtk_smi_device_link_common(dev, com_dev: &common->smi_common_dev); |
789 | if (ret < 0) |
790 | return ret; |
791 | } |
792 | |
793 | pm_runtime_enable(dev); |
794 | platform_set_drvdata(pdev, data: common); |
795 | return 0; |
796 | } |
797 | |
798 | static int mtk_smi_common_remove(struct platform_device *pdev) |
799 | { |
800 | struct mtk_smi *common = dev_get_drvdata(dev: &pdev->dev); |
801 | |
802 | if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) |
803 | device_link_remove(consumer: &pdev->dev, supplier: common->smi_common_dev); |
804 | pm_runtime_disable(dev: &pdev->dev); |
805 | return 0; |
806 | } |
807 | |
808 | static int __maybe_unused mtk_smi_common_resume(struct device *dev) |
809 | { |
810 | struct mtk_smi *common = dev_get_drvdata(dev); |
811 | const struct mtk_smi_reg_pair *init = common->plat->init; |
812 | u32 bus_sel = common->plat->bus_sel; /* default is 0 */ |
813 | int ret, i; |
814 | |
815 | ret = clk_bulk_prepare_enable(num_clks: common->clk_num, clks: common->clks); |
816 | if (ret) |
817 | return ret; |
818 | |
819 | if (common->plat->type != MTK_SMI_GEN2) |
820 | return 0; |
821 | |
822 | for (i = 0; i < SMI_COMMON_INIT_REGS_NR && init && init[i].offset; i++) |
823 | writel_relaxed(init[i].value, common->base + init[i].offset); |
824 | |
825 | writel(val: bus_sel, addr: common->base + SMI_BUS_SEL); |
826 | return 0; |
827 | } |
828 | |
829 | static int __maybe_unused mtk_smi_common_suspend(struct device *dev) |
830 | { |
831 | struct mtk_smi *common = dev_get_drvdata(dev); |
832 | |
833 | clk_bulk_disable_unprepare(num_clks: common->clk_num, clks: common->clks); |
834 | return 0; |
835 | } |
836 | |
837 | static const struct dev_pm_ops smi_common_pm_ops = { |
838 | SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL) |
839 | SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
840 | pm_runtime_force_resume) |
841 | }; |
842 | |
843 | static struct platform_driver mtk_smi_common_driver = { |
844 | .probe = mtk_smi_common_probe, |
845 | .remove = mtk_smi_common_remove, |
846 | .driver = { |
847 | .name = "mtk-smi-common" , |
848 | .of_match_table = mtk_smi_common_of_ids, |
849 | .pm = &smi_common_pm_ops, |
850 | } |
851 | }; |
852 | |
853 | static struct platform_driver * const smidrivers[] = { |
854 | &mtk_smi_common_driver, |
855 | &mtk_smi_larb_driver, |
856 | }; |
857 | |
858 | static int __init mtk_smi_init(void) |
859 | { |
860 | return platform_register_drivers(smidrivers, ARRAY_SIZE(smidrivers)); |
861 | } |
862 | module_init(mtk_smi_init); |
863 | |
864 | static void __exit mtk_smi_exit(void) |
865 | { |
866 | platform_unregister_drivers(drivers: smidrivers, ARRAY_SIZE(smidrivers)); |
867 | } |
868 | module_exit(mtk_smi_exit); |
869 | |
870 | MODULE_DESCRIPTION("MediaTek SMI driver" ); |
871 | MODULE_LICENSE("GPL v2" ); |
872 | |