blob: a001e41f50741282e51a536840ddbdd579bfa2e6 [file] [log] [blame]
Thomas Gleixner1802d0b2019-05-27 08:55:21 +02001// SPDX-License-Identifier: GPL-2.0-only
Yong Wucc8bbe12016-02-23 01:20:49 +08002/*
3 * Copyright (c) 2015-2016 MediaTek Inc.
4 * Author: Yong Wu <yong.wu@mediatek.com>
Yong Wucc8bbe12016-02-23 01:20:49 +08005 */
6#include <linux/clk.h>
7#include <linux/component.h>
8#include <linux/device.h>
9#include <linux/err.h>
10#include <linux/io.h>
Yong Wu4f608d32017-08-21 19:00:21 +080011#include <linux/module.h>
Yong Wucc8bbe12016-02-23 01:20:49 +080012#include <linux/of.h>
13#include <linux/of_platform.h>
14#include <linux/platform_device.h>
15#include <linux/pm_runtime.h>
16#include <soc/mediatek/smi.h>
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +080017#include <dt-bindings/memory/mt2701-larb-port.h>
Yong Wu66a28912021-01-11 19:18:49 +080018#include <dt-bindings/memory/mtk-memory-port.h>
Yong Wucc8bbe12016-02-23 01:20:49 +080019
Yong Wu534e0ad2021-09-14 19:36:55 +080020/* SMI COMMON */
21#define SMI_BUS_SEL 0x220
22#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
23/* All are MMU0 defaultly. Only specialize mmu1 here. */
24#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
Yong Wue6dec922017-08-21 19:00:16 +080025
Yong Wu534e0ad2021-09-14 19:36:55 +080026/* SMI LARB */
Fabien Parenta8529f32020-09-06 20:09:38 +020027
Yong Wu534e0ad2021-09-14 19:36:55 +080028/* Below are about mmu enable registers, they are different in SoCs */
29/* gen1: mt2701 */
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +080030#define REG_SMI_SECUR_CON_BASE 0x5c0
31
32/* every register control 8 port, register offset 0x4 */
33#define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2)
34#define REG_SMI_SECUR_CON_ADDR(id) \
35 (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id))
36
37/*
38 * every port have 4 bit to control, bit[port + 3] control virtual or physical,
39 * bit[port + 2 : port + 1] control the domain, bit[port] control the security
40 * or non-security.
41 */
42#define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2)))
43#define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3)
44/* mt2701 domain should be set to 3 */
45#define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1))
46
Yong Wu534e0ad2021-09-14 19:36:55 +080047/* gen2: */
48/* mt8167 */
49#define MT8167_SMI_LARB_MMU_EN 0xfc0
50
51/* mt8173 */
52#define MT8173_SMI_LARB_MMU_EN 0xf00
53
54/* general */
55#define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4))
56#define F_MMU_EN BIT(0)
57#define BANK_SEL(id) ({ \
Yong Wu8d2c7492021-01-11 19:19:11 +080058 u32 _id = (id) & 0x3; \
59 (_id << 8 | _id << 10 | _id << 12 | _id << 14); \
60})
Yong Wue6dec922017-08-21 19:00:16 +080061
Yong Wua5c18982021-09-14 19:36:54 +080062enum mtk_smi_type {
Yong Wu42d42c72019-08-24 11:01:49 +080063 MTK_SMI_GEN1,
Yong Wu47404752021-09-14 19:36:57 +080064 MTK_SMI_GEN2, /* gen2 smi common */
65 MTK_SMI_GEN2_SUB_COMM, /* gen2 smi sub common */
Yong Wu42d42c72019-08-24 11:01:49 +080066};
67
Yong Wu0e149172021-09-14 19:36:53 +080068#define MTK_SMI_CLK_NR_MAX 4
69
70/* larbs: Require apb/smi clocks while gals is optional. */
71static const char * const mtk_smi_larb_clks[] = {"apb", "smi", "gals"};
72#define MTK_SMI_LARB_REQ_CLK_NR 2
73#define MTK_SMI_LARB_OPT_CLK_NR 1
74
75/*
76 * common: Require these four clocks in has_gals case. Otherwise, only apb/smi are required.
Yong Wu3e4f74e2021-09-14 19:36:58 +080077 * sub common: Require apb/smi/gals0 clocks in has_gals case. Otherwise, only apb/smi are required.
Yong Wu0e149172021-09-14 19:36:53 +080078 */
79static const char * const mtk_smi_common_clks[] = {"apb", "smi", "gals0", "gals1"};
80#define MTK_SMI_COM_REQ_CLK_NR 2
81#define MTK_SMI_COM_GALS_REQ_CLK_NR MTK_SMI_CLK_NR_MAX
Yong Wu3e4f74e2021-09-14 19:36:58 +080082#define MTK_SMI_SUB_COM_GALS_REQ_CLK_NR 3
Yong Wu0e149172021-09-14 19:36:53 +080083
Yong Wu42d42c72019-08-24 11:01:49 +080084struct mtk_smi_common_plat {
Yong Wua5c18982021-09-14 19:36:54 +080085 enum mtk_smi_type type;
86 bool has_gals;
87 u32 bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */
Yong Wu42d42c72019-08-24 11:01:49 +080088};
89
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +080090struct mtk_smi_larb_gen {
91 int port_in_larb[MTK_LARB_NR_MAX + 1];
Krzysztof Kozlowski3aa5a6c2020-07-24 09:40:28 +020092 void (*config_port)(struct device *dev);
Yong Wu2e9b0902019-08-24 11:01:48 +080093 unsigned int larb_direct_to_common_mask;
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +080094};
Yong Wucc8bbe12016-02-23 01:20:49 +080095
96struct mtk_smi {
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +080097 struct device *dev;
Yong Wu0e149172021-09-14 19:36:53 +080098 unsigned int clk_num;
99 struct clk_bulk_data clks[MTK_SMI_CLK_NR_MAX];
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800100 struct clk *clk_async; /*only needed by mt2701*/
Yong Wu567e58c2019-08-24 11:02:05 +0800101 union {
102 void __iomem *smi_ao_base; /* only for gen1 */
103 void __iomem *base; /* only for gen2 */
104 };
Yong Wu47404752021-09-14 19:36:57 +0800105 struct device *smi_common_dev; /* for sub common */
Yong Wu42d42c72019-08-24 11:01:49 +0800106 const struct mtk_smi_common_plat *plat;
Yong Wucc8bbe12016-02-23 01:20:49 +0800107};
108
109struct mtk_smi_larb { /* larb: local arbiter */
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800110 struct mtk_smi smi;
111 void __iomem *base;
Yong Wu47404752021-09-14 19:36:57 +0800112 struct device *smi_common_dev; /* common or sub-common dev */
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800113 const struct mtk_smi_larb_gen *larb_gen;
114 int larbid;
115 u32 *mmu;
Yong Wu8d2c7492021-01-11 19:19:11 +0800116 unsigned char *bank;
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800117};
118
Yong Wucc8bbe12016-02-23 01:20:49 +0800119int mtk_smi_larb_get(struct device *larbdev)
120{
Zhang Qilonga2d522f2020-11-23 18:21:18 +0800121 int ret = pm_runtime_resume_and_get(larbdev);
Yong Wucc8bbe12016-02-23 01:20:49 +0800122
Yong Wu4f0a1a12019-08-24 11:02:04 +0800123 return (ret < 0) ? ret : 0;
Yong Wucc8bbe12016-02-23 01:20:49 +0800124}
Philipp Zabelcb1b5df2016-04-27 10:48:00 +0200125EXPORT_SYMBOL_GPL(mtk_smi_larb_get);
Yong Wucc8bbe12016-02-23 01:20:49 +0800126
127void mtk_smi_larb_put(struct device *larbdev)
128{
Yong Wu4f0a1a12019-08-24 11:02:04 +0800129 pm_runtime_put_sync(larbdev);
Yong Wucc8bbe12016-02-23 01:20:49 +0800130}
Philipp Zabelcb1b5df2016-04-27 10:48:00 +0200131EXPORT_SYMBOL_GPL(mtk_smi_larb_put);
Yong Wucc8bbe12016-02-23 01:20:49 +0800132
133static int
134mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
135{
136 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
Yong Wu1ee9feb2019-08-24 11:02:08 +0800137 struct mtk_smi_larb_iommu *larb_mmu = data;
Yong Wucc8bbe12016-02-23 01:20:49 +0800138 unsigned int i;
139
Yong Wuec2da072019-08-24 11:02:07 +0800140 for (i = 0; i < MTK_LARB_NR_MAX; i++) {
Yong Wu1ee9feb2019-08-24 11:02:08 +0800141 if (dev == larb_mmu[i].dev) {
Yong Wuec2da072019-08-24 11:02:07 +0800142 larb->larbid = i;
Yong Wu1ee9feb2019-08-24 11:02:08 +0800143 larb->mmu = &larb_mmu[i].mmu;
Yong Wu8d2c7492021-01-11 19:19:11 +0800144 larb->bank = larb_mmu[i].bank;
Yong Wucc8bbe12016-02-23 01:20:49 +0800145 return 0;
146 }
147 }
148 return -ENODEV;
149}
150
Yong Wu534e0ad2021-09-14 19:36:55 +0800151static void
152mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
Yong Wue6dec922017-08-21 19:00:16 +0800153{
Yong Wu534e0ad2021-09-14 19:36:55 +0800154 /* Do nothing as the iommu is always enabled. */
Yong Wue6dec922017-08-21 19:00:16 +0800155}
156
Yong Wu534e0ad2021-09-14 19:36:55 +0800157static const struct component_ops mtk_smi_larb_component_ops = {
158 .bind = mtk_smi_larb_bind,
159 .unbind = mtk_smi_larb_unbind,
160};
Fabien Parenta8529f32020-09-06 20:09:38 +0200161
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800162static void mtk_smi_larb_config_port_gen1(struct device *dev)
163{
164 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
165 const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
166 struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
167 int i, m4u_port_id, larb_port_num;
168 u32 sec_con_val, reg_val;
169
170 m4u_port_id = larb_gen->port_in_larb[larb->larbid];
171 larb_port_num = larb_gen->port_in_larb[larb->larbid + 1]
172 - larb_gen->port_in_larb[larb->larbid];
173
174 for (i = 0; i < larb_port_num; i++, m4u_port_id++) {
175 if (*larb->mmu & BIT(i)) {
176 /* bit[port + 3] controls the virtual or physical */
177 sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id);
178 } else {
179 /* do not need to enable m4u for this port */
180 continue;
181 }
182 reg_val = readl(common->smi_ao_base
183 + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
184 reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id);
185 reg_val |= sec_con_val;
186 reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id);
187 writel(reg_val,
188 common->smi_ao_base
189 + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
190 }
191}
192
Yong Wu534e0ad2021-09-14 19:36:55 +0800193static void mtk_smi_larb_config_port_mt8167(struct device *dev)
Yong Wucc8bbe12016-02-23 01:20:49 +0800194{
Yong Wu534e0ad2021-09-14 19:36:55 +0800195 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
196
197 writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
Yong Wucc8bbe12016-02-23 01:20:49 +0800198}
199
Yong Wu534e0ad2021-09-14 19:36:55 +0800200static void mtk_smi_larb_config_port_mt8173(struct device *dev)
201{
202 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
Yong Wucc8bbe12016-02-23 01:20:49 +0800203
Yong Wu534e0ad2021-09-14 19:36:55 +0800204 writel(*larb->mmu, larb->base + MT8173_SMI_LARB_MMU_EN);
205}
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800206
Yong Wu534e0ad2021-09-14 19:36:55 +0800207static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
208{
209 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
210 u32 reg;
211 int i;
212
213 if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
214 return;
215
216 for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
217 reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
218 reg |= F_MMU_EN;
219 reg |= BANK_SEL(larb->bank[i]);
220 writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
221 }
222}
Fabien Parenta8529f32020-09-06 20:09:38 +0200223
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800224static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
225 .port_in_larb = {
226 LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
227 LARB2_PORT_OFFSET, LARB3_PORT_OFFSET
228 },
229 .config_port = mtk_smi_larb_config_port_gen1,
230};
231
Yong Wue6dec922017-08-21 19:00:16 +0800232static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = {
Yong Wu2e9b0902019-08-24 11:01:48 +0800233 .config_port = mtk_smi_larb_config_port_gen2_general,
234 .larb_direct_to_common_mask = BIT(8) | BIT(9), /* bdpsys */
Yong Wue6dec922017-08-21 19:00:16 +0800235};
236
Ming-Fan Chenfc492f32020-01-08 14:41:30 +0800237static const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = {
238 .config_port = mtk_smi_larb_config_port_gen2_general,
239 .larb_direct_to_common_mask =
240 BIT(4) | BIT(6) | BIT(11) | BIT(12) | BIT(13),
241 /* DUMMY | IPU0 | IPU1 | CCU | MDLA */
242};
243
Yong Wu534e0ad2021-09-14 19:36:55 +0800244static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
245 /* mt8167 do not need the port in larb */
246 .config_port = mtk_smi_larb_config_port_mt8167,
247};
248
249static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
250 /* mt8173 do not need the port in larb */
251 .config_port = mtk_smi_larb_config_port_mt8173,
252};
253
Yong Wu907ba6a2019-08-24 11:02:02 +0800254static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
Yong Wu907ba6a2019-08-24 11:02:02 +0800255 .config_port = mtk_smi_larb_config_port_gen2_general,
256 .larb_direct_to_common_mask = BIT(2) | BIT(3) | BIT(7),
257 /* IPU0 | IPU1 | CCU */
258};
259
Yong Wu02c02dd2020-11-03 13:42:00 +0800260static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
261 .config_port = mtk_smi_larb_config_port_gen2_general,
262};
263
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800264static const struct of_device_id mtk_smi_larb_of_ids[] = {
Yong Wu534e0ad2021-09-14 19:36:55 +0800265 {.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701},
266 {.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712},
267 {.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779},
268 {.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167},
269 {.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
270 {.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
271 {.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192},
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800272 {}
273};
274
Yong Wu47404752021-09-14 19:36:57 +0800275static int mtk_smi_device_link_common(struct device *dev, struct device **com_dev)
276{
277 struct platform_device *smi_com_pdev;
278 struct device_node *smi_com_node;
279 struct device *smi_com_dev;
280 struct device_link *link;
281
282 smi_com_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
283 if (!smi_com_node)
284 return -EINVAL;
285
286 smi_com_pdev = of_find_device_by_node(smi_com_node);
287 of_node_put(smi_com_node);
288 if (smi_com_pdev) {
289 /* smi common is the supplier, Make sure it is ready before */
290 if (!platform_get_drvdata(smi_com_pdev))
291 return -EPROBE_DEFER;
292 smi_com_dev = &smi_com_pdev->dev;
293 link = device_link_add(dev, smi_com_dev,
294 DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
295 if (!link) {
296 dev_err(dev, "Unable to link smi-common dev\n");
297 return -ENODEV;
298 }
299 *com_dev = smi_com_dev;
300 } else {
301 dev_err(dev, "Failed to get the smi_common device\n");
302 return -EINVAL;
303 }
304 return 0;
305}
306
Yong Wu0e149172021-09-14 19:36:53 +0800307static int mtk_smi_dts_clk_init(struct device *dev, struct mtk_smi *smi,
308 const char * const clks[],
309 unsigned int clk_nr_required,
310 unsigned int clk_nr_optional)
311{
312 int i, ret;
313
314 for (i = 0; i < clk_nr_required; i++)
315 smi->clks[i].id = clks[i];
316 ret = devm_clk_bulk_get(dev, clk_nr_required, smi->clks);
317 if (ret)
318 return ret;
319
320 for (i = clk_nr_required; i < clk_nr_required + clk_nr_optional; i++)
321 smi->clks[i].id = clks[i];
322 ret = devm_clk_bulk_get_optional(dev, clk_nr_optional,
323 smi->clks + clk_nr_required);
324 smi->clk_num = clk_nr_required + clk_nr_optional;
325 return ret;
326}
327
Yong Wucc8bbe12016-02-23 01:20:49 +0800328static int mtk_smi_larb_probe(struct platform_device *pdev)
329{
330 struct mtk_smi_larb *larb;
Yong Wucc8bbe12016-02-23 01:20:49 +0800331 struct device *dev = &pdev->dev;
Yong Wu0e149172021-09-14 19:36:53 +0800332 int ret;
Yong Wucc8bbe12016-02-23 01:20:49 +0800333
Yong Wucc8bbe12016-02-23 01:20:49 +0800334 larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
335 if (!larb)
336 return -ENOMEM;
337
Honghui Zhang75487862017-08-04 09:32:25 +0800338 larb->larb_gen = of_device_get_match_data(dev);
Yong Wu912fea82021-09-14 19:36:59 +0800339 larb->base = devm_platform_ioremap_resource(pdev, 0);
Yong Wucc8bbe12016-02-23 01:20:49 +0800340 if (IS_ERR(larb->base))
341 return PTR_ERR(larb->base);
342
Yong Wu0e149172021-09-14 19:36:53 +0800343 ret = mtk_smi_dts_clk_init(dev, &larb->smi, mtk_smi_larb_clks,
344 MTK_SMI_LARB_REQ_CLK_NR, MTK_SMI_LARB_OPT_CLK_NR);
345 if (ret)
346 return ret;
Yong Wucc8bbe12016-02-23 01:20:49 +0800347
Yong Wucc8bbe12016-02-23 01:20:49 +0800348 larb->smi.dev = dev;
Yong Wucc8bbe12016-02-23 01:20:49 +0800349
Yong Wu47404752021-09-14 19:36:57 +0800350 ret = mtk_smi_device_link_common(dev, &larb->smi_common_dev);
351 if (ret < 0)
352 return ret;
Yong Wucc8bbe12016-02-23 01:20:49 +0800353
354 pm_runtime_enable(dev);
355 platform_set_drvdata(pdev, larb);
Yong Wu30b869e2021-09-14 19:36:56 +0800356 ret = component_add(dev, &mtk_smi_larb_component_ops);
357 if (ret)
358 goto err_pm_disable;
359 return 0;
360
361err_pm_disable:
362 pm_runtime_disable(dev);
363 device_link_remove(dev, larb->smi_common_dev);
364 return ret;
Yong Wucc8bbe12016-02-23 01:20:49 +0800365}
366
367static int mtk_smi_larb_remove(struct platform_device *pdev)
368{
Yong Wu6ce2c052021-04-10 17:11:16 +0800369 struct mtk_smi_larb *larb = platform_get_drvdata(pdev);
370
371 device_link_remove(&pdev->dev, larb->smi_common_dev);
Yong Wucc8bbe12016-02-23 01:20:49 +0800372 pm_runtime_disable(&pdev->dev);
373 component_del(&pdev->dev, &mtk_smi_larb_component_ops);
374 return 0;
375}
376
Yong Wu4f0a1a12019-08-24 11:02:04 +0800377static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
378{
379 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
380 const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
381 int ret;
382
Yong Wu0e149172021-09-14 19:36:53 +0800383 ret = clk_bulk_prepare_enable(larb->smi.clk_num, larb->smi.clks);
384 if (ret < 0)
Yong Wu4f0a1a12019-08-24 11:02:04 +0800385 return ret;
Yong Wu4f0a1a12019-08-24 11:02:04 +0800386
387 /* Configure the basic setting for this larb */
388 larb_gen->config_port(dev);
389
390 return 0;
391}
392
393static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
394{
395 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
396
Yong Wu0e149172021-09-14 19:36:53 +0800397 clk_bulk_disable_unprepare(larb->smi.clk_num, larb->smi.clks);
Yong Wu4f0a1a12019-08-24 11:02:04 +0800398 return 0;
399}
400
401static const struct dev_pm_ops smi_larb_pm_ops = {
402 SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL)
Yong Wufb030822019-10-09 19:59:33 +0800403 SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
404 pm_runtime_force_resume)
Yong Wu4f0a1a12019-08-24 11:02:04 +0800405};
406
Yong Wucc8bbe12016-02-23 01:20:49 +0800407static struct platform_driver mtk_smi_larb_driver = {
408 .probe = mtk_smi_larb_probe,
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800409 .remove = mtk_smi_larb_remove,
Yong Wucc8bbe12016-02-23 01:20:49 +0800410 .driver = {
411 .name = "mtk-smi-larb",
412 .of_match_table = mtk_smi_larb_of_ids,
Yong Wu4f0a1a12019-08-24 11:02:04 +0800413 .pm = &smi_larb_pm_ops,
Yong Wucc8bbe12016-02-23 01:20:49 +0800414 }
415};
416
Yong Wu42d42c72019-08-24 11:01:49 +0800417static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
Yong Wua5c18982021-09-14 19:36:54 +0800418 .type = MTK_SMI_GEN1,
Yong Wu42d42c72019-08-24 11:01:49 +0800419};
420
421static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
Yong Wua5c18982021-09-14 19:36:54 +0800422 .type = MTK_SMI_GEN2,
Yong Wu42d42c72019-08-24 11:01:49 +0800423};
424
Ming-Fan Chenfc492f32020-01-08 14:41:30 +0800425static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = {
Yong Wua5c18982021-09-14 19:36:54 +0800426 .type = MTK_SMI_GEN2,
427 .has_gals = true,
428 .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) |
429 F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
Ming-Fan Chenfc492f32020-01-08 14:41:30 +0800430};
431
Yong Wu907ba6a2019-08-24 11:02:02 +0800432static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
Yong Wua5c18982021-09-14 19:36:54 +0800433 .type = MTK_SMI_GEN2,
Yong Wu907ba6a2019-08-24 11:02:02 +0800434 .has_gals = true,
Yong Wu567e58c2019-08-24 11:02:05 +0800435 .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
436 F_MMU1_LARB(7),
Yong Wu907ba6a2019-08-24 11:02:02 +0800437};
438
Yong Wu02c02dd2020-11-03 13:42:00 +0800439static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
Yong Wua5c18982021-09-14 19:36:54 +0800440 .type = MTK_SMI_GEN2,
Yong Wu02c02dd2020-11-03 13:42:00 +0800441 .has_gals = true,
442 .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
443 F_MMU1_LARB(6),
444};
445
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800446static const struct of_device_id mtk_smi_common_of_ids[] = {
Yong Wu534e0ad2021-09-14 19:36:55 +0800447 {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
448 {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
449 {.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779},
450 {.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2},
451 {.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2},
452 {.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183},
453 {.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192},
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800454 {}
455};
456
Yong Wucc8bbe12016-02-23 01:20:49 +0800457static int mtk_smi_common_probe(struct platform_device *pdev)
458{
459 struct device *dev = &pdev->dev;
460 struct mtk_smi *common;
Yong Wu0e149172021-09-14 19:36:53 +0800461 int ret, clk_required = MTK_SMI_COM_REQ_CLK_NR;
Yong Wucc8bbe12016-02-23 01:20:49 +0800462
Yong Wucc8bbe12016-02-23 01:20:49 +0800463 common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
464 if (!common)
465 return -ENOMEM;
466 common->dev = dev;
Yong Wu42d42c72019-08-24 11:01:49 +0800467 common->plat = of_device_get_match_data(dev);
Yong Wucc8bbe12016-02-23 01:20:49 +0800468
Yong Wu3e4f74e2021-09-14 19:36:58 +0800469 if (common->plat->has_gals) {
470 if (common->plat->type == MTK_SMI_GEN2)
471 clk_required = MTK_SMI_COM_GALS_REQ_CLK_NR;
472 else if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
473 clk_required = MTK_SMI_SUB_COM_GALS_REQ_CLK_NR;
474 }
Yong Wu0e149172021-09-14 19:36:53 +0800475 ret = mtk_smi_dts_clk_init(dev, common, mtk_smi_common_clks, clk_required, 0);
476 if (ret)
477 return ret;
Yong Wu64fea742019-08-24 11:02:01 +0800478
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800479 /*
480 * for mtk smi gen 1, we need to get the ao(always on) base to config
481 * m4u port, and we need to enable the aync clock for transform the smi
482 * clock into emi clock domain, but for mtk smi gen2, there's no smi ao
483 * base.
484 */
Yong Wua5c18982021-09-14 19:36:54 +0800485 if (common->plat->type == MTK_SMI_GEN1) {
Yong Wu912fea82021-09-14 19:36:59 +0800486 common->smi_ao_base = devm_platform_ioremap_resource(pdev, 0);
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800487 if (IS_ERR(common->smi_ao_base))
488 return PTR_ERR(common->smi_ao_base);
489
490 common->clk_async = devm_clk_get(dev, "async");
491 if (IS_ERR(common->clk_async))
492 return PTR_ERR(common->clk_async);
493
Arvind Yadav46cc8152017-08-10 10:47:32 +0530494 ret = clk_prepare_enable(common->clk_async);
495 if (ret)
496 return ret;
Yong Wu567e58c2019-08-24 11:02:05 +0800497 } else {
Yong Wu912fea82021-09-14 19:36:59 +0800498 common->base = devm_platform_ioremap_resource(pdev, 0);
Yong Wu567e58c2019-08-24 11:02:05 +0800499 if (IS_ERR(common->base))
500 return PTR_ERR(common->base);
Honghui Zhang3c8f4ad2016-06-08 17:50:59 +0800501 }
Yong Wu47404752021-09-14 19:36:57 +0800502
503 /* link its smi-common if this is smi-sub-common */
504 if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) {
505 ret = mtk_smi_device_link_common(dev, &common->smi_common_dev);
506 if (ret < 0)
507 return ret;
508 }
509
Yong Wucc8bbe12016-02-23 01:20:49 +0800510 pm_runtime_enable(dev);
511 platform_set_drvdata(pdev, common);
512 return 0;
513}
514
515static int mtk_smi_common_remove(struct platform_device *pdev)
516{
Yong Wu47404752021-09-14 19:36:57 +0800517 struct mtk_smi *common = dev_get_drvdata(&pdev->dev);
518
519 if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
520 device_link_remove(&pdev->dev, common->smi_common_dev);
Yong Wucc8bbe12016-02-23 01:20:49 +0800521 pm_runtime_disable(&pdev->dev);
522 return 0;
523}
524
Yong Wu4f0a1a12019-08-24 11:02:04 +0800525static int __maybe_unused mtk_smi_common_resume(struct device *dev)
526{
527 struct mtk_smi *common = dev_get_drvdata(dev);
Yong Wu567e58c2019-08-24 11:02:05 +0800528 u32 bus_sel = common->plat->bus_sel;
Yong Wu4f0a1a12019-08-24 11:02:04 +0800529 int ret;
530
Yong Wu0e149172021-09-14 19:36:53 +0800531 ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
532 if (ret)
Yong Wu4f0a1a12019-08-24 11:02:04 +0800533 return ret;
Yong Wu567e58c2019-08-24 11:02:05 +0800534
Yong Wua5c18982021-09-14 19:36:54 +0800535 if (common->plat->type == MTK_SMI_GEN2 && bus_sel)
Yong Wu567e58c2019-08-24 11:02:05 +0800536 writel(bus_sel, common->base + SMI_BUS_SEL);
Yong Wu4f0a1a12019-08-24 11:02:04 +0800537 return 0;
538}
539
540static int __maybe_unused mtk_smi_common_suspend(struct device *dev)
541{
542 struct mtk_smi *common = dev_get_drvdata(dev);
543
Yong Wu0e149172021-09-14 19:36:53 +0800544 clk_bulk_disable_unprepare(common->clk_num, common->clks);
Yong Wu4f0a1a12019-08-24 11:02:04 +0800545 return 0;
546}
547
548static const struct dev_pm_ops smi_common_pm_ops = {
549 SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL)
Yong Wufb030822019-10-09 19:59:33 +0800550 SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
551 pm_runtime_force_resume)
Yong Wu4f0a1a12019-08-24 11:02:04 +0800552};
553
Yong Wucc8bbe12016-02-23 01:20:49 +0800554static struct platform_driver mtk_smi_common_driver = {
555 .probe = mtk_smi_common_probe,
556 .remove = mtk_smi_common_remove,
557 .driver = {
558 .name = "mtk-smi-common",
559 .of_match_table = mtk_smi_common_of_ids,
Yong Wu4f0a1a12019-08-24 11:02:04 +0800560 .pm = &smi_common_pm_ops,
Yong Wucc8bbe12016-02-23 01:20:49 +0800561 }
562};
563
Yong Wu18212032021-01-21 14:24:27 +0800564static struct platform_driver * const smidrivers[] = {
565 &mtk_smi_common_driver,
566 &mtk_smi_larb_driver,
567};
568
Yong Wucc8bbe12016-02-23 01:20:49 +0800569static int __init mtk_smi_init(void)
570{
Yong Wu18212032021-01-21 14:24:27 +0800571 return platform_register_drivers(smidrivers, ARRAY_SIZE(smidrivers));
Yong Wucc8bbe12016-02-23 01:20:49 +0800572}
Yong Wu4f608d32017-08-21 19:00:21 +0800573module_init(mtk_smi_init);
Yong Wu50fc8d92021-01-26 14:00:55 +0800574
575static void __exit mtk_smi_exit(void)
576{
577 platform_unregister_drivers(smidrivers, ARRAY_SIZE(smidrivers));
578}
579module_exit(mtk_smi_exit);
580
581MODULE_DESCRIPTION("MediaTek SMI driver");
582MODULE_LICENSE("GPL v2");