]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/memory/mtk-smi.c
memory: mtk-smi: add larbid handle routine
[mirror_ubuntu-bionic-kernel.git] / drivers / memory / mtk-smi.c
CommitLineData
cc8bbe1a
YW
1/*
2 * Copyright (c) 2015-2016 MediaTek Inc.
3 * Author: Yong Wu <yong.wu@mediatek.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <linux/clk.h>
15#include <linux/component.h>
16#include <linux/device.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/of_platform.h>
21#include <linux/platform_device.h>
22#include <linux/pm_runtime.h>
23#include <soc/mediatek/smi.h>
3c8f4ad8 24#include <dt-bindings/memory/mt2701-larb-port.h>
cc8bbe1a
YW
25
26#define SMI_LARB_MMU_EN 0xf00
3c8f4ad8
HZ
27#define REG_SMI_SECUR_CON_BASE 0x5c0
28
29/* every register control 8 port, register offset 0x4 */
30#define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2)
31#define REG_SMI_SECUR_CON_ADDR(id) \
32 (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id))
33
34/*
35 * every port have 4 bit to control, bit[port + 3] control virtual or physical,
36 * bit[port + 2 : port + 1] control the domain, bit[port] control the security
37 * or non-security.
38 */
39#define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2)))
40#define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3)
41/* mt2701 domain should be set to 3 */
42#define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1))
43
44struct mtk_smi_larb_gen {
363932cd 45 bool need_larbid;
3c8f4ad8
HZ
46 int port_in_larb[MTK_LARB_NR_MAX + 1];
47 void (*config_port)(struct device *);
48};
cc8bbe1a
YW
49
50struct mtk_smi {
3c8f4ad8
HZ
51 struct device *dev;
52 struct clk *clk_apb, *clk_smi;
53 struct clk *clk_async; /*only needed by mt2701*/
54 void __iomem *smi_ao_base;
cc8bbe1a
YW
55};
56
57struct mtk_smi_larb { /* larb: local arbiter */
3c8f4ad8
HZ
58 struct mtk_smi smi;
59 void __iomem *base;
60 struct device *smi_common_dev;
61 const struct mtk_smi_larb_gen *larb_gen;
62 int larbid;
63 u32 *mmu;
64};
65
66enum mtk_smi_gen {
67 MTK_SMI_GEN1,
68 MTK_SMI_GEN2
cc8bbe1a
YW
69};
70
71static int mtk_smi_enable(const struct mtk_smi *smi)
72{
73 int ret;
74
75 ret = pm_runtime_get_sync(smi->dev);
76 if (ret < 0)
77 return ret;
78
79 ret = clk_prepare_enable(smi->clk_apb);
80 if (ret)
81 goto err_put_pm;
82
83 ret = clk_prepare_enable(smi->clk_smi);
84 if (ret)
85 goto err_disable_apb;
86
87 return 0;
88
89err_disable_apb:
90 clk_disable_unprepare(smi->clk_apb);
91err_put_pm:
92 pm_runtime_put_sync(smi->dev);
93 return ret;
94}
95
96static void mtk_smi_disable(const struct mtk_smi *smi)
97{
98 clk_disable_unprepare(smi->clk_smi);
99 clk_disable_unprepare(smi->clk_apb);
100 pm_runtime_put_sync(smi->dev);
101}
102
103int mtk_smi_larb_get(struct device *larbdev)
104{
105 struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
3c8f4ad8 106 const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
cc8bbe1a
YW
107 struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
108 int ret;
109
110 /* Enable the smi-common's power and clocks */
111 ret = mtk_smi_enable(common);
112 if (ret)
113 return ret;
114
115 /* Enable the larb's power and clocks */
116 ret = mtk_smi_enable(&larb->smi);
117 if (ret) {
118 mtk_smi_disable(common);
119 return ret;
120 }
121
122 /* Configure the iommu info for this larb */
3c8f4ad8 123 larb_gen->config_port(larbdev);
cc8bbe1a
YW
124
125 return 0;
126}
cb1b5dff 127EXPORT_SYMBOL_GPL(mtk_smi_larb_get);
cc8bbe1a
YW
128
129void mtk_smi_larb_put(struct device *larbdev)
130{
131 struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
132 struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
133
134 /*
135 * Don't de-configure the iommu info for this larb since there may be
136 * several modules in this larb.
137 * The iommu info will be reset after power off.
138 */
139
140 mtk_smi_disable(&larb->smi);
141 mtk_smi_disable(common);
142}
cb1b5dff 143EXPORT_SYMBOL_GPL(mtk_smi_larb_put);
cc8bbe1a
YW
144
145static int
146mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
147{
148 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
149 struct mtk_smi_iommu *smi_iommu = data;
150 unsigned int i;
151
152 for (i = 0; i < smi_iommu->larb_nr; i++) {
153 if (dev == smi_iommu->larb_imu[i].dev) {
154 /* The 'mmu' may be updated in iommu-attach/detach. */
155 larb->mmu = &smi_iommu->larb_imu[i].mmu;
156 return 0;
157 }
158 }
159 return -ENODEV;
160}
161
3c8f4ad8
HZ
162static void mtk_smi_larb_config_port(struct device *dev)
163{
164 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
165
166 writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
167}
168
169
170static void mtk_smi_larb_config_port_gen1(struct device *dev)
171{
172 struct mtk_smi_larb *larb = dev_get_drvdata(dev);
173 const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
174 struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
175 int i, m4u_port_id, larb_port_num;
176 u32 sec_con_val, reg_val;
177
178 m4u_port_id = larb_gen->port_in_larb[larb->larbid];
179 larb_port_num = larb_gen->port_in_larb[larb->larbid + 1]
180 - larb_gen->port_in_larb[larb->larbid];
181
182 for (i = 0; i < larb_port_num; i++, m4u_port_id++) {
183 if (*larb->mmu & BIT(i)) {
184 /* bit[port + 3] controls the virtual or physical */
185 sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id);
186 } else {
187 /* do not need to enable m4u for this port */
188 continue;
189 }
190 reg_val = readl(common->smi_ao_base
191 + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
192 reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id);
193 reg_val |= sec_con_val;
194 reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id);
195 writel(reg_val,
196 common->smi_ao_base
197 + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
198 }
199}
200
cc8bbe1a
YW
201static void
202mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
203{
204 /* Do nothing as the iommu is always enabled. */
205}
206
207static const struct component_ops mtk_smi_larb_component_ops = {
208 .bind = mtk_smi_larb_bind,
209 .unbind = mtk_smi_larb_unbind,
210};
211
3c8f4ad8
HZ
212static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
213 /* mt8173 do not need the port in larb */
214 .config_port = mtk_smi_larb_config_port,
215};
216
217static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
363932cd 218 .need_larbid = true,
3c8f4ad8
HZ
219 .port_in_larb = {
220 LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
221 LARB2_PORT_OFFSET, LARB3_PORT_OFFSET
222 },
223 .config_port = mtk_smi_larb_config_port_gen1,
224};
225
226static const struct of_device_id mtk_smi_larb_of_ids[] = {
227 {
228 .compatible = "mediatek,mt8173-smi-larb",
229 .data = &mtk_smi_larb_mt8173
230 },
231 {
232 .compatible = "mediatek,mt2701-smi-larb",
233 .data = &mtk_smi_larb_mt2701
234 },
235 {}
236};
237
cc8bbe1a
YW
238static int mtk_smi_larb_probe(struct platform_device *pdev)
239{
240 struct mtk_smi_larb *larb;
241 struct resource *res;
242 struct device *dev = &pdev->dev;
243 struct device_node *smi_node;
244 struct platform_device *smi_pdev;
363932cd 245 int err;
cc8bbe1a
YW
246
247 if (!dev->pm_domain)
248 return -EPROBE_DEFER;
249
250 larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
251 if (!larb)
252 return -ENOMEM;
253
75487860 254 larb->larb_gen = of_device_get_match_data(dev);
cc8bbe1a
YW
255 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
256 larb->base = devm_ioremap_resource(dev, res);
257 if (IS_ERR(larb->base))
258 return PTR_ERR(larb->base);
259
260 larb->smi.clk_apb = devm_clk_get(dev, "apb");
261 if (IS_ERR(larb->smi.clk_apb))
262 return PTR_ERR(larb->smi.clk_apb);
263
264 larb->smi.clk_smi = devm_clk_get(dev, "smi");
265 if (IS_ERR(larb->smi.clk_smi))
266 return PTR_ERR(larb->smi.clk_smi);
267 larb->smi.dev = dev;
268
363932cd
HZ
269 if (larb->larb_gen->need_larbid) {
270 err = of_property_read_u32(dev->of_node, "mediatek,larb-id",
271 &larb->larbid);
272 if (err) {
273 dev_err(dev, "missing larbid property\n");
274 return err;
275 }
276 }
277
cc8bbe1a
YW
278 smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
279 if (!smi_node)
280 return -EINVAL;
281
282 smi_pdev = of_find_device_by_node(smi_node);
283 of_node_put(smi_node);
284 if (smi_pdev) {
285 larb->smi_common_dev = &smi_pdev->dev;
286 } else {
287 dev_err(dev, "Failed to get the smi_common device\n");
288 return -EINVAL;
289 }
290
291 pm_runtime_enable(dev);
292 platform_set_drvdata(pdev, larb);
293 return component_add(dev, &mtk_smi_larb_component_ops);
294}
295
296static int mtk_smi_larb_remove(struct platform_device *pdev)
297{
298 pm_runtime_disable(&pdev->dev);
299 component_del(&pdev->dev, &mtk_smi_larb_component_ops);
300 return 0;
301}
302
cc8bbe1a
YW
303static struct platform_driver mtk_smi_larb_driver = {
304 .probe = mtk_smi_larb_probe,
3c8f4ad8 305 .remove = mtk_smi_larb_remove,
cc8bbe1a
YW
306 .driver = {
307 .name = "mtk-smi-larb",
308 .of_match_table = mtk_smi_larb_of_ids,
309 }
310};
311
3c8f4ad8
HZ
312static const struct of_device_id mtk_smi_common_of_ids[] = {
313 {
314 .compatible = "mediatek,mt8173-smi-common",
315 .data = (void *)MTK_SMI_GEN2
316 },
317 {
318 .compatible = "mediatek,mt2701-smi-common",
319 .data = (void *)MTK_SMI_GEN1
320 },
321 {}
322};
323
cc8bbe1a
YW
324static int mtk_smi_common_probe(struct platform_device *pdev)
325{
326 struct device *dev = &pdev->dev;
327 struct mtk_smi *common;
3c8f4ad8 328 struct resource *res;
3c8f4ad8 329 enum mtk_smi_gen smi_gen;
cc8bbe1a
YW
330
331 if (!dev->pm_domain)
332 return -EPROBE_DEFER;
333
334 common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
335 if (!common)
336 return -ENOMEM;
337 common->dev = dev;
338
339 common->clk_apb = devm_clk_get(dev, "apb");
340 if (IS_ERR(common->clk_apb))
341 return PTR_ERR(common->clk_apb);
342
343 common->clk_smi = devm_clk_get(dev, "smi");
344 if (IS_ERR(common->clk_smi))
345 return PTR_ERR(common->clk_smi);
346
3c8f4ad8
HZ
347 /*
348 * for mtk smi gen 1, we need to get the ao(always on) base to config
349 * m4u port, and we need to enable the aync clock for transform the smi
350 * clock into emi clock domain, but for mtk smi gen2, there's no smi ao
351 * base.
352 */
75487860 353 smi_gen = (enum mtk_smi_gen)of_device_get_match_data(dev);
3c8f4ad8
HZ
354 if (smi_gen == MTK_SMI_GEN1) {
355 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
356 common->smi_ao_base = devm_ioremap_resource(dev, res);
357 if (IS_ERR(common->smi_ao_base))
358 return PTR_ERR(common->smi_ao_base);
359
360 common->clk_async = devm_clk_get(dev, "async");
361 if (IS_ERR(common->clk_async))
362 return PTR_ERR(common->clk_async);
363
364 clk_prepare_enable(common->clk_async);
365 }
cc8bbe1a
YW
366 pm_runtime_enable(dev);
367 platform_set_drvdata(pdev, common);
368 return 0;
369}
370
371static int mtk_smi_common_remove(struct platform_device *pdev)
372{
373 pm_runtime_disable(&pdev->dev);
374 return 0;
375}
376
cc8bbe1a
YW
377static struct platform_driver mtk_smi_common_driver = {
378 .probe = mtk_smi_common_probe,
379 .remove = mtk_smi_common_remove,
380 .driver = {
381 .name = "mtk-smi-common",
382 .of_match_table = mtk_smi_common_of_ids,
383 }
384};
385
386static int __init mtk_smi_init(void)
387{
388 int ret;
389
390 ret = platform_driver_register(&mtk_smi_common_driver);
391 if (ret != 0) {
392 pr_err("Failed to register SMI driver\n");
393 return ret;
394 }
395
396 ret = platform_driver_register(&mtk_smi_larb_driver);
397 if (ret != 0) {
398 pr_err("Failed to register SMI-LARB driver\n");
399 goto err_unreg_smi;
400 }
401 return ret;
402
403err_unreg_smi:
404 platform_driver_unregister(&mtk_smi_common_driver);
405 return ret;
406}
3c8f4ad8 407
cc8bbe1a 408subsys_initcall(mtk_smi_init);