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