xref: /openbmc/linux/drivers/memory/mtk-smi.c (revision 42d42c76)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2cc8bbe1aSYong Wu /*
3cc8bbe1aSYong Wu  * Copyright (c) 2015-2016 MediaTek Inc.
4cc8bbe1aSYong Wu  * Author: Yong Wu <yong.wu@mediatek.com>
5cc8bbe1aSYong Wu  */
6cc8bbe1aSYong Wu #include <linux/clk.h>
7cc8bbe1aSYong Wu #include <linux/component.h>
8cc8bbe1aSYong Wu #include <linux/device.h>
9cc8bbe1aSYong Wu #include <linux/err.h>
10cc8bbe1aSYong Wu #include <linux/io.h>
114f608d38SYong Wu #include <linux/module.h>
12cc8bbe1aSYong Wu #include <linux/of.h>
13cc8bbe1aSYong Wu #include <linux/of_platform.h>
14cc8bbe1aSYong Wu #include <linux/platform_device.h>
15cc8bbe1aSYong Wu #include <linux/pm_runtime.h>
16cc8bbe1aSYong Wu #include <soc/mediatek/smi.h>
173c8f4ad8SHonghui Zhang #include <dt-bindings/memory/mt2701-larb-port.h>
18cc8bbe1aSYong Wu 
19e6dec923SYong Wu /* mt8173 */
20cc8bbe1aSYong Wu #define SMI_LARB_MMU_EN		0xf00
21e6dec923SYong Wu 
22e6dec923SYong Wu /* mt2701 */
233c8f4ad8SHonghui Zhang #define REG_SMI_SECUR_CON_BASE		0x5c0
243c8f4ad8SHonghui Zhang 
253c8f4ad8SHonghui Zhang /* every register control 8 port, register offset 0x4 */
263c8f4ad8SHonghui Zhang #define REG_SMI_SECUR_CON_OFFSET(id)	(((id) >> 3) << 2)
273c8f4ad8SHonghui Zhang #define REG_SMI_SECUR_CON_ADDR(id)	\
283c8f4ad8SHonghui Zhang 	(REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id))
293c8f4ad8SHonghui Zhang 
303c8f4ad8SHonghui Zhang /*
313c8f4ad8SHonghui Zhang  * every port have 4 bit to control, bit[port + 3] control virtual or physical,
323c8f4ad8SHonghui Zhang  * bit[port + 2 : port + 1] control the domain, bit[port] control the security
333c8f4ad8SHonghui Zhang  * or non-security.
343c8f4ad8SHonghui Zhang  */
353c8f4ad8SHonghui Zhang #define SMI_SECUR_CON_VAL_MSK(id)	(~(0xf << (((id) & 0x7) << 2)))
363c8f4ad8SHonghui Zhang #define SMI_SECUR_CON_VAL_VIRT(id)	BIT((((id) & 0x7) << 2) + 3)
373c8f4ad8SHonghui Zhang /* mt2701 domain should be set to 3 */
383c8f4ad8SHonghui Zhang #define SMI_SECUR_CON_VAL_DOMAIN(id)	(0x3 << ((((id) & 0x7) << 2) + 1))
393c8f4ad8SHonghui Zhang 
40e6dec923SYong Wu /* mt2712 */
41e6dec923SYong Wu #define SMI_LARB_NONSEC_CON(id)	(0x380 + ((id) * 4))
42e6dec923SYong Wu #define F_MMU_EN		BIT(0)
43e6dec923SYong Wu 
4442d42c76SYong Wu enum mtk_smi_gen {
4542d42c76SYong Wu 	MTK_SMI_GEN1,
4642d42c76SYong Wu 	MTK_SMI_GEN2
4742d42c76SYong Wu };
4842d42c76SYong Wu 
4942d42c76SYong Wu struct mtk_smi_common_plat {
5042d42c76SYong Wu 	enum mtk_smi_gen gen;
5142d42c76SYong Wu };
5242d42c76SYong Wu 
533c8f4ad8SHonghui Zhang struct mtk_smi_larb_gen {
54363932cdSHonghui Zhang 	bool need_larbid;
553c8f4ad8SHonghui Zhang 	int port_in_larb[MTK_LARB_NR_MAX + 1];
563c8f4ad8SHonghui Zhang 	void (*config_port)(struct device *);
572e9b0908SYong Wu 	unsigned int			larb_direct_to_common_mask;
583c8f4ad8SHonghui Zhang };
59cc8bbe1aSYong Wu 
60cc8bbe1aSYong Wu struct mtk_smi {
61cc8bbe1aSYong Wu 	struct device			*dev;
62cc8bbe1aSYong Wu 	struct clk			*clk_apb, *clk_smi;
633c8f4ad8SHonghui Zhang 	struct clk			*clk_async; /*only needed by mt2701*/
643c8f4ad8SHonghui Zhang 	void __iomem			*smi_ao_base;
6542d42c76SYong Wu 
6642d42c76SYong Wu 	const struct mtk_smi_common_plat *plat;
67cc8bbe1aSYong Wu };
68cc8bbe1aSYong Wu 
69cc8bbe1aSYong Wu struct mtk_smi_larb { /* larb: local arbiter */
70cc8bbe1aSYong Wu 	struct mtk_smi			smi;
71cc8bbe1aSYong Wu 	void __iomem			*base;
72cc8bbe1aSYong Wu 	struct device			*smi_common_dev;
733c8f4ad8SHonghui Zhang 	const struct mtk_smi_larb_gen	*larb_gen;
743c8f4ad8SHonghui Zhang 	int				larbid;
75cc8bbe1aSYong Wu 	u32				*mmu;
76cc8bbe1aSYong Wu };
77cc8bbe1aSYong Wu 
78cc8bbe1aSYong Wu static int mtk_smi_enable(const struct mtk_smi *smi)
79cc8bbe1aSYong Wu {
80cc8bbe1aSYong Wu 	int ret;
81cc8bbe1aSYong Wu 
82cc8bbe1aSYong Wu 	ret = pm_runtime_get_sync(smi->dev);
83cc8bbe1aSYong Wu 	if (ret < 0)
84cc8bbe1aSYong Wu 		return ret;
85cc8bbe1aSYong Wu 
86cc8bbe1aSYong Wu 	ret = clk_prepare_enable(smi->clk_apb);
87cc8bbe1aSYong Wu 	if (ret)
88cc8bbe1aSYong Wu 		goto err_put_pm;
89cc8bbe1aSYong Wu 
90cc8bbe1aSYong Wu 	ret = clk_prepare_enable(smi->clk_smi);
91cc8bbe1aSYong Wu 	if (ret)
92cc8bbe1aSYong Wu 		goto err_disable_apb;
93cc8bbe1aSYong Wu 
94cc8bbe1aSYong Wu 	return 0;
95cc8bbe1aSYong Wu 
96cc8bbe1aSYong Wu err_disable_apb:
97cc8bbe1aSYong Wu 	clk_disable_unprepare(smi->clk_apb);
98cc8bbe1aSYong Wu err_put_pm:
99cc8bbe1aSYong Wu 	pm_runtime_put_sync(smi->dev);
100cc8bbe1aSYong Wu 	return ret;
101cc8bbe1aSYong Wu }
102cc8bbe1aSYong Wu 
103cc8bbe1aSYong Wu static void mtk_smi_disable(const struct mtk_smi *smi)
104cc8bbe1aSYong Wu {
105cc8bbe1aSYong Wu 	clk_disable_unprepare(smi->clk_smi);
106cc8bbe1aSYong Wu 	clk_disable_unprepare(smi->clk_apb);
107cc8bbe1aSYong Wu 	pm_runtime_put_sync(smi->dev);
108cc8bbe1aSYong Wu }
109cc8bbe1aSYong Wu 
110cc8bbe1aSYong Wu int mtk_smi_larb_get(struct device *larbdev)
111cc8bbe1aSYong Wu {
112cc8bbe1aSYong Wu 	struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
1133c8f4ad8SHonghui Zhang 	const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
114cc8bbe1aSYong Wu 	struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
115cc8bbe1aSYong Wu 	int ret;
116cc8bbe1aSYong Wu 
117cc8bbe1aSYong Wu 	/* Enable the smi-common's power and clocks */
118cc8bbe1aSYong Wu 	ret = mtk_smi_enable(common);
119cc8bbe1aSYong Wu 	if (ret)
120cc8bbe1aSYong Wu 		return ret;
121cc8bbe1aSYong Wu 
122cc8bbe1aSYong Wu 	/* Enable the larb's power and clocks */
123cc8bbe1aSYong Wu 	ret = mtk_smi_enable(&larb->smi);
124cc8bbe1aSYong Wu 	if (ret) {
125cc8bbe1aSYong Wu 		mtk_smi_disable(common);
126cc8bbe1aSYong Wu 		return ret;
127cc8bbe1aSYong Wu 	}
128cc8bbe1aSYong Wu 
129cc8bbe1aSYong Wu 	/* Configure the iommu info for this larb */
1303c8f4ad8SHonghui Zhang 	larb_gen->config_port(larbdev);
131cc8bbe1aSYong Wu 
132cc8bbe1aSYong Wu 	return 0;
133cc8bbe1aSYong Wu }
134cb1b5dffSPhilipp Zabel EXPORT_SYMBOL_GPL(mtk_smi_larb_get);
135cc8bbe1aSYong Wu 
136cc8bbe1aSYong Wu void mtk_smi_larb_put(struct device *larbdev)
137cc8bbe1aSYong Wu {
138cc8bbe1aSYong Wu 	struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
139cc8bbe1aSYong Wu 	struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
140cc8bbe1aSYong Wu 
141cc8bbe1aSYong Wu 	/*
142cc8bbe1aSYong Wu 	 * Don't de-configure the iommu info for this larb since there may be
143cc8bbe1aSYong Wu 	 * several modules in this larb.
144cc8bbe1aSYong Wu 	 * The iommu info will be reset after power off.
145cc8bbe1aSYong Wu 	 */
146cc8bbe1aSYong Wu 
147cc8bbe1aSYong Wu 	mtk_smi_disable(&larb->smi);
148cc8bbe1aSYong Wu 	mtk_smi_disable(common);
149cc8bbe1aSYong Wu }
150cb1b5dffSPhilipp Zabel EXPORT_SYMBOL_GPL(mtk_smi_larb_put);
151cc8bbe1aSYong Wu 
152cc8bbe1aSYong Wu static int
153cc8bbe1aSYong Wu mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
154cc8bbe1aSYong Wu {
155cc8bbe1aSYong Wu 	struct mtk_smi_larb *larb = dev_get_drvdata(dev);
156cc8bbe1aSYong Wu 	struct mtk_smi_iommu *smi_iommu = data;
157cc8bbe1aSYong Wu 	unsigned int         i;
158cc8bbe1aSYong Wu 
159e6dec923SYong Wu 	if (larb->larb_gen->need_larbid) {
160e6dec923SYong Wu 		larb->mmu = &smi_iommu->larb_imu[larb->larbid].mmu;
161e6dec923SYong Wu 		return 0;
162e6dec923SYong Wu 	}
163e6dec923SYong Wu 
164e6dec923SYong Wu 	/*
165e6dec923SYong Wu 	 * If there is no larbid property, Loop to find the corresponding
166e6dec923SYong Wu 	 * iommu information.
167e6dec923SYong Wu 	 */
168cc8bbe1aSYong Wu 	for (i = 0; i < smi_iommu->larb_nr; i++) {
169cc8bbe1aSYong Wu 		if (dev == smi_iommu->larb_imu[i].dev) {
170cc8bbe1aSYong Wu 			/* The 'mmu' may be updated in iommu-attach/detach. */
171cc8bbe1aSYong Wu 			larb->mmu = &smi_iommu->larb_imu[i].mmu;
172cc8bbe1aSYong Wu 			return 0;
173cc8bbe1aSYong Wu 		}
174cc8bbe1aSYong Wu 	}
175cc8bbe1aSYong Wu 	return -ENODEV;
176cc8bbe1aSYong Wu }
177cc8bbe1aSYong Wu 
1782e9b0908SYong Wu static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
179e6dec923SYong Wu {
180e6dec923SYong Wu 	struct mtk_smi_larb *larb = dev_get_drvdata(dev);
181e6dec923SYong Wu 	u32 reg;
182e6dec923SYong Wu 	int i;
183e6dec923SYong Wu 
1842e9b0908SYong Wu 	if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
185e6dec923SYong Wu 		return;
186e6dec923SYong Wu 
187e6dec923SYong Wu 	for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
188e6dec923SYong Wu 		reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
189e6dec923SYong Wu 		reg |= F_MMU_EN;
190e6dec923SYong Wu 		writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
191e6dec923SYong Wu 	}
192e6dec923SYong Wu }
193e6dec923SYong Wu 
194e6dec923SYong Wu static void mtk_smi_larb_config_port_mt8173(struct device *dev)
1953c8f4ad8SHonghui Zhang {
1963c8f4ad8SHonghui Zhang 	struct mtk_smi_larb *larb = dev_get_drvdata(dev);
1973c8f4ad8SHonghui Zhang 
1983c8f4ad8SHonghui Zhang 	writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
1993c8f4ad8SHonghui Zhang }
2003c8f4ad8SHonghui Zhang 
2013c8f4ad8SHonghui Zhang static void mtk_smi_larb_config_port_gen1(struct device *dev)
2023c8f4ad8SHonghui Zhang {
2033c8f4ad8SHonghui Zhang 	struct mtk_smi_larb *larb = dev_get_drvdata(dev);
2043c8f4ad8SHonghui Zhang 	const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
2053c8f4ad8SHonghui Zhang 	struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
2063c8f4ad8SHonghui Zhang 	int i, m4u_port_id, larb_port_num;
2073c8f4ad8SHonghui Zhang 	u32 sec_con_val, reg_val;
2083c8f4ad8SHonghui Zhang 
2093c8f4ad8SHonghui Zhang 	m4u_port_id = larb_gen->port_in_larb[larb->larbid];
2103c8f4ad8SHonghui Zhang 	larb_port_num = larb_gen->port_in_larb[larb->larbid + 1]
2113c8f4ad8SHonghui Zhang 			- larb_gen->port_in_larb[larb->larbid];
2123c8f4ad8SHonghui Zhang 
2133c8f4ad8SHonghui Zhang 	for (i = 0; i < larb_port_num; i++, m4u_port_id++) {
2143c8f4ad8SHonghui Zhang 		if (*larb->mmu & BIT(i)) {
2153c8f4ad8SHonghui Zhang 			/* bit[port + 3] controls the virtual or physical */
2163c8f4ad8SHonghui Zhang 			sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id);
2173c8f4ad8SHonghui Zhang 		} else {
2183c8f4ad8SHonghui Zhang 			/* do not need to enable m4u for this port */
2193c8f4ad8SHonghui Zhang 			continue;
2203c8f4ad8SHonghui Zhang 		}
2213c8f4ad8SHonghui Zhang 		reg_val = readl(common->smi_ao_base
2223c8f4ad8SHonghui Zhang 			+ REG_SMI_SECUR_CON_ADDR(m4u_port_id));
2233c8f4ad8SHonghui Zhang 		reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id);
2243c8f4ad8SHonghui Zhang 		reg_val |= sec_con_val;
2253c8f4ad8SHonghui Zhang 		reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id);
2263c8f4ad8SHonghui Zhang 		writel(reg_val,
2273c8f4ad8SHonghui Zhang 			common->smi_ao_base
2283c8f4ad8SHonghui Zhang 			+ REG_SMI_SECUR_CON_ADDR(m4u_port_id));
2293c8f4ad8SHonghui Zhang 	}
2303c8f4ad8SHonghui Zhang }
2313c8f4ad8SHonghui Zhang 
232cc8bbe1aSYong Wu static void
233cc8bbe1aSYong Wu mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
234cc8bbe1aSYong Wu {
235cc8bbe1aSYong Wu 	/* Do nothing as the iommu is always enabled. */
236cc8bbe1aSYong Wu }
237cc8bbe1aSYong Wu 
238cc8bbe1aSYong Wu static const struct component_ops mtk_smi_larb_component_ops = {
239cc8bbe1aSYong Wu 	.bind = mtk_smi_larb_bind,
240cc8bbe1aSYong Wu 	.unbind = mtk_smi_larb_unbind,
241cc8bbe1aSYong Wu };
242cc8bbe1aSYong Wu 
2433c8f4ad8SHonghui Zhang static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
2443c8f4ad8SHonghui Zhang 	/* mt8173 do not need the port in larb */
245e6dec923SYong Wu 	.config_port = mtk_smi_larb_config_port_mt8173,
2463c8f4ad8SHonghui Zhang };
2473c8f4ad8SHonghui Zhang 
2483c8f4ad8SHonghui Zhang static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
249363932cdSHonghui Zhang 	.need_larbid = true,
2503c8f4ad8SHonghui Zhang 	.port_in_larb = {
2513c8f4ad8SHonghui Zhang 		LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
2523c8f4ad8SHonghui Zhang 		LARB2_PORT_OFFSET, LARB3_PORT_OFFSET
2533c8f4ad8SHonghui Zhang 	},
2543c8f4ad8SHonghui Zhang 	.config_port = mtk_smi_larb_config_port_gen1,
2553c8f4ad8SHonghui Zhang };
2563c8f4ad8SHonghui Zhang 
257e6dec923SYong Wu static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = {
258e6dec923SYong Wu 	.need_larbid = true,
2592e9b0908SYong Wu 	.config_port                = mtk_smi_larb_config_port_gen2_general,
2602e9b0908SYong Wu 	.larb_direct_to_common_mask = BIT(8) | BIT(9),      /* bdpsys */
261e6dec923SYong Wu };
262e6dec923SYong Wu 
2633c8f4ad8SHonghui Zhang static const struct of_device_id mtk_smi_larb_of_ids[] = {
2643c8f4ad8SHonghui Zhang 	{
2653c8f4ad8SHonghui Zhang 		.compatible = "mediatek,mt8173-smi-larb",
2663c8f4ad8SHonghui Zhang 		.data = &mtk_smi_larb_mt8173
2673c8f4ad8SHonghui Zhang 	},
2683c8f4ad8SHonghui Zhang 	{
2693c8f4ad8SHonghui Zhang 		.compatible = "mediatek,mt2701-smi-larb",
2703c8f4ad8SHonghui Zhang 		.data = &mtk_smi_larb_mt2701
2713c8f4ad8SHonghui Zhang 	},
272e6dec923SYong Wu 	{
273e6dec923SYong Wu 		.compatible = "mediatek,mt2712-smi-larb",
274e6dec923SYong Wu 		.data = &mtk_smi_larb_mt2712
275e6dec923SYong Wu 	},
2763c8f4ad8SHonghui Zhang 	{}
2773c8f4ad8SHonghui Zhang };
2783c8f4ad8SHonghui Zhang 
279cc8bbe1aSYong Wu static int mtk_smi_larb_probe(struct platform_device *pdev)
280cc8bbe1aSYong Wu {
281cc8bbe1aSYong Wu 	struct mtk_smi_larb *larb;
282cc8bbe1aSYong Wu 	struct resource *res;
283cc8bbe1aSYong Wu 	struct device *dev = &pdev->dev;
284cc8bbe1aSYong Wu 	struct device_node *smi_node;
285cc8bbe1aSYong Wu 	struct platform_device *smi_pdev;
286363932cdSHonghui Zhang 	int err;
287cc8bbe1aSYong Wu 
288cc8bbe1aSYong Wu 	larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
289cc8bbe1aSYong Wu 	if (!larb)
290cc8bbe1aSYong Wu 		return -ENOMEM;
291cc8bbe1aSYong Wu 
29275487860SHonghui Zhang 	larb->larb_gen = of_device_get_match_data(dev);
293cc8bbe1aSYong Wu 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
294cc8bbe1aSYong Wu 	larb->base = devm_ioremap_resource(dev, res);
295cc8bbe1aSYong Wu 	if (IS_ERR(larb->base))
296cc8bbe1aSYong Wu 		return PTR_ERR(larb->base);
297cc8bbe1aSYong Wu 
298cc8bbe1aSYong Wu 	larb->smi.clk_apb = devm_clk_get(dev, "apb");
299cc8bbe1aSYong Wu 	if (IS_ERR(larb->smi.clk_apb))
300cc8bbe1aSYong Wu 		return PTR_ERR(larb->smi.clk_apb);
301cc8bbe1aSYong Wu 
302cc8bbe1aSYong Wu 	larb->smi.clk_smi = devm_clk_get(dev, "smi");
303cc8bbe1aSYong Wu 	if (IS_ERR(larb->smi.clk_smi))
304cc8bbe1aSYong Wu 		return PTR_ERR(larb->smi.clk_smi);
305cc8bbe1aSYong Wu 	larb->smi.dev = dev;
306cc8bbe1aSYong Wu 
307363932cdSHonghui Zhang 	if (larb->larb_gen->need_larbid) {
308363932cdSHonghui Zhang 		err = of_property_read_u32(dev->of_node, "mediatek,larb-id",
309363932cdSHonghui Zhang 					   &larb->larbid);
310363932cdSHonghui Zhang 		if (err) {
311363932cdSHonghui Zhang 			dev_err(dev, "missing larbid property\n");
312363932cdSHonghui Zhang 			return err;
313363932cdSHonghui Zhang 		}
314363932cdSHonghui Zhang 	}
315363932cdSHonghui Zhang 
316cc8bbe1aSYong Wu 	smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
317cc8bbe1aSYong Wu 	if (!smi_node)
318cc8bbe1aSYong Wu 		return -EINVAL;
319cc8bbe1aSYong Wu 
320cc8bbe1aSYong Wu 	smi_pdev = of_find_device_by_node(smi_node);
321cc8bbe1aSYong Wu 	of_node_put(smi_node);
322cc8bbe1aSYong Wu 	if (smi_pdev) {
3234f608d38SYong Wu 		if (!platform_get_drvdata(smi_pdev))
3244f608d38SYong Wu 			return -EPROBE_DEFER;
325cc8bbe1aSYong Wu 		larb->smi_common_dev = &smi_pdev->dev;
326cc8bbe1aSYong Wu 	} else {
327cc8bbe1aSYong Wu 		dev_err(dev, "Failed to get the smi_common device\n");
328cc8bbe1aSYong Wu 		return -EINVAL;
329cc8bbe1aSYong Wu 	}
330cc8bbe1aSYong Wu 
331cc8bbe1aSYong Wu 	pm_runtime_enable(dev);
332cc8bbe1aSYong Wu 	platform_set_drvdata(pdev, larb);
333cc8bbe1aSYong Wu 	return component_add(dev, &mtk_smi_larb_component_ops);
334cc8bbe1aSYong Wu }
335cc8bbe1aSYong Wu 
336cc8bbe1aSYong Wu static int mtk_smi_larb_remove(struct platform_device *pdev)
337cc8bbe1aSYong Wu {
338cc8bbe1aSYong Wu 	pm_runtime_disable(&pdev->dev);
339cc8bbe1aSYong Wu 	component_del(&pdev->dev, &mtk_smi_larb_component_ops);
340cc8bbe1aSYong Wu 	return 0;
341cc8bbe1aSYong Wu }
342cc8bbe1aSYong Wu 
343cc8bbe1aSYong Wu static struct platform_driver mtk_smi_larb_driver = {
344cc8bbe1aSYong Wu 	.probe	= mtk_smi_larb_probe,
345cc8bbe1aSYong Wu 	.remove	= mtk_smi_larb_remove,
346cc8bbe1aSYong Wu 	.driver	= {
347cc8bbe1aSYong Wu 		.name = "mtk-smi-larb",
348cc8bbe1aSYong Wu 		.of_match_table = mtk_smi_larb_of_ids,
349cc8bbe1aSYong Wu 	}
350cc8bbe1aSYong Wu };
351cc8bbe1aSYong Wu 
35242d42c76SYong Wu static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
35342d42c76SYong Wu 	.gen = MTK_SMI_GEN1,
35442d42c76SYong Wu };
35542d42c76SYong Wu 
35642d42c76SYong Wu static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
35742d42c76SYong Wu 	.gen = MTK_SMI_GEN2,
35842d42c76SYong Wu };
35942d42c76SYong Wu 
3603c8f4ad8SHonghui Zhang static const struct of_device_id mtk_smi_common_of_ids[] = {
3613c8f4ad8SHonghui Zhang 	{
3623c8f4ad8SHonghui Zhang 		.compatible = "mediatek,mt8173-smi-common",
36342d42c76SYong Wu 		.data = &mtk_smi_common_gen2,
3643c8f4ad8SHonghui Zhang 	},
3653c8f4ad8SHonghui Zhang 	{
3663c8f4ad8SHonghui Zhang 		.compatible = "mediatek,mt2701-smi-common",
36742d42c76SYong Wu 		.data = &mtk_smi_common_gen1,
3683c8f4ad8SHonghui Zhang 	},
369e6dec923SYong Wu 	{
370e6dec923SYong Wu 		.compatible = "mediatek,mt2712-smi-common",
37142d42c76SYong Wu 		.data = &mtk_smi_common_gen2,
372e6dec923SYong Wu 	},
3733c8f4ad8SHonghui Zhang 	{}
3743c8f4ad8SHonghui Zhang };
3753c8f4ad8SHonghui Zhang 
376cc8bbe1aSYong Wu static int mtk_smi_common_probe(struct platform_device *pdev)
377cc8bbe1aSYong Wu {
378cc8bbe1aSYong Wu 	struct device *dev = &pdev->dev;
379cc8bbe1aSYong Wu 	struct mtk_smi *common;
3803c8f4ad8SHonghui Zhang 	struct resource *res;
38146cc815dSArvind Yadav 	int ret;
382cc8bbe1aSYong Wu 
383cc8bbe1aSYong Wu 	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
384cc8bbe1aSYong Wu 	if (!common)
385cc8bbe1aSYong Wu 		return -ENOMEM;
386cc8bbe1aSYong Wu 	common->dev = dev;
38742d42c76SYong Wu 	common->plat = of_device_get_match_data(dev);
388cc8bbe1aSYong Wu 
389cc8bbe1aSYong Wu 	common->clk_apb = devm_clk_get(dev, "apb");
390cc8bbe1aSYong Wu 	if (IS_ERR(common->clk_apb))
391cc8bbe1aSYong Wu 		return PTR_ERR(common->clk_apb);
392cc8bbe1aSYong Wu 
393cc8bbe1aSYong Wu 	common->clk_smi = devm_clk_get(dev, "smi");
394cc8bbe1aSYong Wu 	if (IS_ERR(common->clk_smi))
395cc8bbe1aSYong Wu 		return PTR_ERR(common->clk_smi);
396cc8bbe1aSYong Wu 
3973c8f4ad8SHonghui Zhang 	/*
3983c8f4ad8SHonghui Zhang 	 * for mtk smi gen 1, we need to get the ao(always on) base to config
3993c8f4ad8SHonghui Zhang 	 * m4u port, and we need to enable the aync clock for transform the smi
4003c8f4ad8SHonghui Zhang 	 * clock into emi clock domain, but for mtk smi gen2, there's no smi ao
4013c8f4ad8SHonghui Zhang 	 * base.
4023c8f4ad8SHonghui Zhang 	 */
40342d42c76SYong Wu 	if (common->plat->gen == MTK_SMI_GEN1) {
4043c8f4ad8SHonghui Zhang 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4053c8f4ad8SHonghui Zhang 		common->smi_ao_base = devm_ioremap_resource(dev, res);
4063c8f4ad8SHonghui Zhang 		if (IS_ERR(common->smi_ao_base))
4073c8f4ad8SHonghui Zhang 			return PTR_ERR(common->smi_ao_base);
4083c8f4ad8SHonghui Zhang 
4093c8f4ad8SHonghui Zhang 		common->clk_async = devm_clk_get(dev, "async");
4103c8f4ad8SHonghui Zhang 		if (IS_ERR(common->clk_async))
4113c8f4ad8SHonghui Zhang 			return PTR_ERR(common->clk_async);
4123c8f4ad8SHonghui Zhang 
41346cc815dSArvind Yadav 		ret = clk_prepare_enable(common->clk_async);
41446cc815dSArvind Yadav 		if (ret)
41546cc815dSArvind Yadav 			return ret;
4163c8f4ad8SHonghui Zhang 	}
417cc8bbe1aSYong Wu 	pm_runtime_enable(dev);
418cc8bbe1aSYong Wu 	platform_set_drvdata(pdev, common);
419cc8bbe1aSYong Wu 	return 0;
420cc8bbe1aSYong Wu }
421cc8bbe1aSYong Wu 
422cc8bbe1aSYong Wu static int mtk_smi_common_remove(struct platform_device *pdev)
423cc8bbe1aSYong Wu {
424cc8bbe1aSYong Wu 	pm_runtime_disable(&pdev->dev);
425cc8bbe1aSYong Wu 	return 0;
426cc8bbe1aSYong Wu }
427cc8bbe1aSYong Wu 
428cc8bbe1aSYong Wu static struct platform_driver mtk_smi_common_driver = {
429cc8bbe1aSYong Wu 	.probe	= mtk_smi_common_probe,
430cc8bbe1aSYong Wu 	.remove = mtk_smi_common_remove,
431cc8bbe1aSYong Wu 	.driver	= {
432cc8bbe1aSYong Wu 		.name = "mtk-smi-common",
433cc8bbe1aSYong Wu 		.of_match_table = mtk_smi_common_of_ids,
434cc8bbe1aSYong Wu 	}
435cc8bbe1aSYong Wu };
436cc8bbe1aSYong Wu 
437cc8bbe1aSYong Wu static int __init mtk_smi_init(void)
438cc8bbe1aSYong Wu {
439cc8bbe1aSYong Wu 	int ret;
440cc8bbe1aSYong Wu 
441cc8bbe1aSYong Wu 	ret = platform_driver_register(&mtk_smi_common_driver);
442cc8bbe1aSYong Wu 	if (ret != 0) {
443cc8bbe1aSYong Wu 		pr_err("Failed to register SMI driver\n");
444cc8bbe1aSYong Wu 		return ret;
445cc8bbe1aSYong Wu 	}
446cc8bbe1aSYong Wu 
447cc8bbe1aSYong Wu 	ret = platform_driver_register(&mtk_smi_larb_driver);
448cc8bbe1aSYong Wu 	if (ret != 0) {
449cc8bbe1aSYong Wu 		pr_err("Failed to register SMI-LARB driver\n");
450cc8bbe1aSYong Wu 		goto err_unreg_smi;
451cc8bbe1aSYong Wu 	}
452cc8bbe1aSYong Wu 	return ret;
453cc8bbe1aSYong Wu 
454cc8bbe1aSYong Wu err_unreg_smi:
455cc8bbe1aSYong Wu 	platform_driver_unregister(&mtk_smi_common_driver);
456cc8bbe1aSYong Wu 	return ret;
457cc8bbe1aSYong Wu }
4583c8f4ad8SHonghui Zhang 
4594f608d38SYong Wu module_init(mtk_smi_init);
460