1cc8bbe1aSYong Wu /* 2cc8bbe1aSYong Wu * Copyright (c) 2015-2016 MediaTek Inc. 3cc8bbe1aSYong Wu * Author: Yong Wu <yong.wu@mediatek.com> 4cc8bbe1aSYong Wu * 5cc8bbe1aSYong Wu * This program is free software; you can redistribute it and/or modify 6cc8bbe1aSYong Wu * it under the terms of the GNU General Public License version 2 as 7cc8bbe1aSYong Wu * published by the Free Software Foundation. 8cc8bbe1aSYong Wu * 9cc8bbe1aSYong Wu * This program is distributed in the hope that it will be useful, 10cc8bbe1aSYong Wu * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cc8bbe1aSYong Wu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12cc8bbe1aSYong Wu * GNU General Public License for more details. 13cc8bbe1aSYong Wu */ 14cc8bbe1aSYong Wu #include <linux/clk.h> 15cc8bbe1aSYong Wu #include <linux/component.h> 16cc8bbe1aSYong Wu #include <linux/device.h> 17cc8bbe1aSYong Wu #include <linux/err.h> 18cc8bbe1aSYong Wu #include <linux/io.h> 194f608d38SYong Wu #include <linux/module.h> 20cc8bbe1aSYong Wu #include <linux/of.h> 21cc8bbe1aSYong Wu #include <linux/of_platform.h> 22cc8bbe1aSYong Wu #include <linux/platform_device.h> 23cc8bbe1aSYong Wu #include <linux/pm_runtime.h> 24cc8bbe1aSYong Wu #include <soc/mediatek/smi.h> 253c8f4ad8SHonghui Zhang #include <dt-bindings/memory/mt2701-larb-port.h> 26cc8bbe1aSYong Wu 27e6dec923SYong Wu /* mt8173 */ 28cc8bbe1aSYong Wu #define SMI_LARB_MMU_EN 0xf00 29e6dec923SYong Wu 30e6dec923SYong Wu /* mt2701 */ 313c8f4ad8SHonghui Zhang #define REG_SMI_SECUR_CON_BASE 0x5c0 323c8f4ad8SHonghui Zhang 333c8f4ad8SHonghui Zhang /* every register control 8 port, register offset 0x4 */ 343c8f4ad8SHonghui Zhang #define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2) 353c8f4ad8SHonghui Zhang #define REG_SMI_SECUR_CON_ADDR(id) \ 363c8f4ad8SHonghui Zhang (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id)) 373c8f4ad8SHonghui Zhang 383c8f4ad8SHonghui Zhang /* 393c8f4ad8SHonghui Zhang * every port have 4 bit to control, bit[port + 3] control virtual or physical, 403c8f4ad8SHonghui Zhang * bit[port + 2 : port + 1] control the domain, bit[port] control the security 413c8f4ad8SHonghui Zhang * or non-security. 423c8f4ad8SHonghui Zhang */ 433c8f4ad8SHonghui Zhang #define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2))) 443c8f4ad8SHonghui Zhang #define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3) 453c8f4ad8SHonghui Zhang /* mt2701 domain should be set to 3 */ 463c8f4ad8SHonghui Zhang #define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1)) 473c8f4ad8SHonghui Zhang 48e6dec923SYong Wu /* mt2712 */ 49e6dec923SYong Wu #define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4)) 50e6dec923SYong Wu #define F_MMU_EN BIT(0) 51e6dec923SYong Wu 523c8f4ad8SHonghui Zhang struct mtk_smi_larb_gen { 53363932cdSHonghui Zhang bool need_larbid; 543c8f4ad8SHonghui Zhang int port_in_larb[MTK_LARB_NR_MAX + 1]; 553c8f4ad8SHonghui Zhang void (*config_port)(struct device *); 563c8f4ad8SHonghui Zhang }; 57cc8bbe1aSYong Wu 58cc8bbe1aSYong Wu struct mtk_smi { 59cc8bbe1aSYong Wu struct device *dev; 60cc8bbe1aSYong Wu struct clk *clk_apb, *clk_smi; 613c8f4ad8SHonghui Zhang struct clk *clk_async; /*only needed by mt2701*/ 623c8f4ad8SHonghui Zhang void __iomem *smi_ao_base; 63cc8bbe1aSYong Wu }; 64cc8bbe1aSYong Wu 65cc8bbe1aSYong Wu struct mtk_smi_larb { /* larb: local arbiter */ 66cc8bbe1aSYong Wu struct mtk_smi smi; 67cc8bbe1aSYong Wu void __iomem *base; 68cc8bbe1aSYong Wu struct device *smi_common_dev; 693c8f4ad8SHonghui Zhang const struct mtk_smi_larb_gen *larb_gen; 703c8f4ad8SHonghui Zhang int larbid; 71cc8bbe1aSYong Wu u32 *mmu; 72cc8bbe1aSYong Wu }; 73cc8bbe1aSYong Wu 743c8f4ad8SHonghui Zhang enum mtk_smi_gen { 753c8f4ad8SHonghui Zhang MTK_SMI_GEN1, 763c8f4ad8SHonghui Zhang MTK_SMI_GEN2 773c8f4ad8SHonghui Zhang }; 783c8f4ad8SHonghui Zhang 79cc8bbe1aSYong Wu static int mtk_smi_enable(const struct mtk_smi *smi) 80cc8bbe1aSYong Wu { 81cc8bbe1aSYong Wu int ret; 82cc8bbe1aSYong Wu 83cc8bbe1aSYong Wu ret = pm_runtime_get_sync(smi->dev); 84cc8bbe1aSYong Wu if (ret < 0) 85cc8bbe1aSYong Wu return ret; 86cc8bbe1aSYong Wu 87cc8bbe1aSYong Wu ret = clk_prepare_enable(smi->clk_apb); 88cc8bbe1aSYong Wu if (ret) 89cc8bbe1aSYong Wu goto err_put_pm; 90cc8bbe1aSYong Wu 91cc8bbe1aSYong Wu ret = clk_prepare_enable(smi->clk_smi); 92cc8bbe1aSYong Wu if (ret) 93cc8bbe1aSYong Wu goto err_disable_apb; 94cc8bbe1aSYong Wu 95cc8bbe1aSYong Wu return 0; 96cc8bbe1aSYong Wu 97cc8bbe1aSYong Wu err_disable_apb: 98cc8bbe1aSYong Wu clk_disable_unprepare(smi->clk_apb); 99cc8bbe1aSYong Wu err_put_pm: 100cc8bbe1aSYong Wu pm_runtime_put_sync(smi->dev); 101cc8bbe1aSYong Wu return ret; 102cc8bbe1aSYong Wu } 103cc8bbe1aSYong Wu 104cc8bbe1aSYong Wu static void mtk_smi_disable(const struct mtk_smi *smi) 105cc8bbe1aSYong Wu { 106cc8bbe1aSYong Wu clk_disable_unprepare(smi->clk_smi); 107cc8bbe1aSYong Wu clk_disable_unprepare(smi->clk_apb); 108cc8bbe1aSYong Wu pm_runtime_put_sync(smi->dev); 109cc8bbe1aSYong Wu } 110cc8bbe1aSYong Wu 111cc8bbe1aSYong Wu int mtk_smi_larb_get(struct device *larbdev) 112cc8bbe1aSYong Wu { 113cc8bbe1aSYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); 1143c8f4ad8SHonghui Zhang const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; 115cc8bbe1aSYong Wu struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 116cc8bbe1aSYong Wu int ret; 117cc8bbe1aSYong Wu 118cc8bbe1aSYong Wu /* Enable the smi-common's power and clocks */ 119cc8bbe1aSYong Wu ret = mtk_smi_enable(common); 120cc8bbe1aSYong Wu if (ret) 121cc8bbe1aSYong Wu return ret; 122cc8bbe1aSYong Wu 123cc8bbe1aSYong Wu /* Enable the larb's power and clocks */ 124cc8bbe1aSYong Wu ret = mtk_smi_enable(&larb->smi); 125cc8bbe1aSYong Wu if (ret) { 126cc8bbe1aSYong Wu mtk_smi_disable(common); 127cc8bbe1aSYong Wu return ret; 128cc8bbe1aSYong Wu } 129cc8bbe1aSYong Wu 130cc8bbe1aSYong Wu /* Configure the iommu info for this larb */ 1313c8f4ad8SHonghui Zhang larb_gen->config_port(larbdev); 132cc8bbe1aSYong Wu 133cc8bbe1aSYong Wu return 0; 134cc8bbe1aSYong Wu } 135cb1b5dffSPhilipp Zabel EXPORT_SYMBOL_GPL(mtk_smi_larb_get); 136cc8bbe1aSYong Wu 137cc8bbe1aSYong Wu void mtk_smi_larb_put(struct device *larbdev) 138cc8bbe1aSYong Wu { 139cc8bbe1aSYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); 140cc8bbe1aSYong Wu struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 141cc8bbe1aSYong Wu 142cc8bbe1aSYong Wu /* 143cc8bbe1aSYong Wu * Don't de-configure the iommu info for this larb since there may be 144cc8bbe1aSYong Wu * several modules in this larb. 145cc8bbe1aSYong Wu * The iommu info will be reset after power off. 146cc8bbe1aSYong Wu */ 147cc8bbe1aSYong Wu 148cc8bbe1aSYong Wu mtk_smi_disable(&larb->smi); 149cc8bbe1aSYong Wu mtk_smi_disable(common); 150cc8bbe1aSYong Wu } 151cb1b5dffSPhilipp Zabel EXPORT_SYMBOL_GPL(mtk_smi_larb_put); 152cc8bbe1aSYong Wu 153cc8bbe1aSYong Wu static int 154cc8bbe1aSYong Wu mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) 155cc8bbe1aSYong Wu { 156cc8bbe1aSYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(dev); 157cc8bbe1aSYong Wu struct mtk_smi_iommu *smi_iommu = data; 158cc8bbe1aSYong Wu unsigned int i; 159cc8bbe1aSYong Wu 160e6dec923SYong Wu if (larb->larb_gen->need_larbid) { 161e6dec923SYong Wu larb->mmu = &smi_iommu->larb_imu[larb->larbid].mmu; 162e6dec923SYong Wu return 0; 163e6dec923SYong Wu } 164e6dec923SYong Wu 165e6dec923SYong Wu /* 166e6dec923SYong Wu * If there is no larbid property, Loop to find the corresponding 167e6dec923SYong Wu * iommu information. 168e6dec923SYong Wu */ 169cc8bbe1aSYong Wu for (i = 0; i < smi_iommu->larb_nr; i++) { 170cc8bbe1aSYong Wu if (dev == smi_iommu->larb_imu[i].dev) { 171cc8bbe1aSYong Wu /* The 'mmu' may be updated in iommu-attach/detach. */ 172cc8bbe1aSYong Wu larb->mmu = &smi_iommu->larb_imu[i].mmu; 173cc8bbe1aSYong Wu return 0; 174cc8bbe1aSYong Wu } 175cc8bbe1aSYong Wu } 176cc8bbe1aSYong Wu return -ENODEV; 177cc8bbe1aSYong Wu } 178cc8bbe1aSYong Wu 179e6dec923SYong Wu static void mtk_smi_larb_config_port_mt2712(struct device *dev) 180e6dec923SYong Wu { 181e6dec923SYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(dev); 182e6dec923SYong Wu u32 reg; 183e6dec923SYong Wu int i; 184e6dec923SYong Wu 185e6dec923SYong Wu /* 186e6dec923SYong Wu * larb 8/9 is the bdpsys larb, the iommu_en is enabled defaultly. 187e6dec923SYong Wu * Don't need to set it again. 188e6dec923SYong Wu */ 189e6dec923SYong Wu if (larb->larbid == 8 || larb->larbid == 9) 190e6dec923SYong Wu return; 191e6dec923SYong Wu 192e6dec923SYong Wu for_each_set_bit(i, (unsigned long *)larb->mmu, 32) { 193e6dec923SYong Wu reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i)); 194e6dec923SYong Wu reg |= F_MMU_EN; 195e6dec923SYong Wu writel(reg, larb->base + SMI_LARB_NONSEC_CON(i)); 196e6dec923SYong Wu } 197e6dec923SYong Wu } 198e6dec923SYong Wu 199e6dec923SYong Wu static void mtk_smi_larb_config_port_mt8173(struct device *dev) 2003c8f4ad8SHonghui Zhang { 2013c8f4ad8SHonghui Zhang struct mtk_smi_larb *larb = dev_get_drvdata(dev); 2023c8f4ad8SHonghui Zhang 2033c8f4ad8SHonghui Zhang writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); 2043c8f4ad8SHonghui Zhang } 2053c8f4ad8SHonghui Zhang 2063c8f4ad8SHonghui Zhang static void mtk_smi_larb_config_port_gen1(struct device *dev) 2073c8f4ad8SHonghui Zhang { 2083c8f4ad8SHonghui Zhang struct mtk_smi_larb *larb = dev_get_drvdata(dev); 2093c8f4ad8SHonghui Zhang const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; 2103c8f4ad8SHonghui Zhang struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 2113c8f4ad8SHonghui Zhang int i, m4u_port_id, larb_port_num; 2123c8f4ad8SHonghui Zhang u32 sec_con_val, reg_val; 2133c8f4ad8SHonghui Zhang 2143c8f4ad8SHonghui Zhang m4u_port_id = larb_gen->port_in_larb[larb->larbid]; 2153c8f4ad8SHonghui Zhang larb_port_num = larb_gen->port_in_larb[larb->larbid + 1] 2163c8f4ad8SHonghui Zhang - larb_gen->port_in_larb[larb->larbid]; 2173c8f4ad8SHonghui Zhang 2183c8f4ad8SHonghui Zhang for (i = 0; i < larb_port_num; i++, m4u_port_id++) { 2193c8f4ad8SHonghui Zhang if (*larb->mmu & BIT(i)) { 2203c8f4ad8SHonghui Zhang /* bit[port + 3] controls the virtual or physical */ 2213c8f4ad8SHonghui Zhang sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id); 2223c8f4ad8SHonghui Zhang } else { 2233c8f4ad8SHonghui Zhang /* do not need to enable m4u for this port */ 2243c8f4ad8SHonghui Zhang continue; 2253c8f4ad8SHonghui Zhang } 2263c8f4ad8SHonghui Zhang reg_val = readl(common->smi_ao_base 2273c8f4ad8SHonghui Zhang + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); 2283c8f4ad8SHonghui Zhang reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id); 2293c8f4ad8SHonghui Zhang reg_val |= sec_con_val; 2303c8f4ad8SHonghui Zhang reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id); 2313c8f4ad8SHonghui Zhang writel(reg_val, 2323c8f4ad8SHonghui Zhang common->smi_ao_base 2333c8f4ad8SHonghui Zhang + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); 2343c8f4ad8SHonghui Zhang } 2353c8f4ad8SHonghui Zhang } 2363c8f4ad8SHonghui Zhang 237cc8bbe1aSYong Wu static void 238cc8bbe1aSYong Wu mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) 239cc8bbe1aSYong Wu { 240cc8bbe1aSYong Wu /* Do nothing as the iommu is always enabled. */ 241cc8bbe1aSYong Wu } 242cc8bbe1aSYong Wu 243cc8bbe1aSYong Wu static const struct component_ops mtk_smi_larb_component_ops = { 244cc8bbe1aSYong Wu .bind = mtk_smi_larb_bind, 245cc8bbe1aSYong Wu .unbind = mtk_smi_larb_unbind, 246cc8bbe1aSYong Wu }; 247cc8bbe1aSYong Wu 2483c8f4ad8SHonghui Zhang static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = { 2493c8f4ad8SHonghui Zhang /* mt8173 do not need the port in larb */ 250e6dec923SYong Wu .config_port = mtk_smi_larb_config_port_mt8173, 2513c8f4ad8SHonghui Zhang }; 2523c8f4ad8SHonghui Zhang 2533c8f4ad8SHonghui Zhang static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = { 254363932cdSHonghui Zhang .need_larbid = true, 2553c8f4ad8SHonghui Zhang .port_in_larb = { 2563c8f4ad8SHonghui Zhang LARB0_PORT_OFFSET, LARB1_PORT_OFFSET, 2573c8f4ad8SHonghui Zhang LARB2_PORT_OFFSET, LARB3_PORT_OFFSET 2583c8f4ad8SHonghui Zhang }, 2593c8f4ad8SHonghui Zhang .config_port = mtk_smi_larb_config_port_gen1, 2603c8f4ad8SHonghui Zhang }; 2613c8f4ad8SHonghui Zhang 262e6dec923SYong Wu static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = { 263e6dec923SYong Wu .need_larbid = true, 264e6dec923SYong Wu .config_port = mtk_smi_larb_config_port_mt2712, 265e6dec923SYong Wu }; 266e6dec923SYong Wu 2673c8f4ad8SHonghui Zhang static const struct of_device_id mtk_smi_larb_of_ids[] = { 2683c8f4ad8SHonghui Zhang { 2693c8f4ad8SHonghui Zhang .compatible = "mediatek,mt8173-smi-larb", 2703c8f4ad8SHonghui Zhang .data = &mtk_smi_larb_mt8173 2713c8f4ad8SHonghui Zhang }, 2723c8f4ad8SHonghui Zhang { 2733c8f4ad8SHonghui Zhang .compatible = "mediatek,mt2701-smi-larb", 2743c8f4ad8SHonghui Zhang .data = &mtk_smi_larb_mt2701 2753c8f4ad8SHonghui Zhang }, 276e6dec923SYong Wu { 277e6dec923SYong Wu .compatible = "mediatek,mt2712-smi-larb", 278e6dec923SYong Wu .data = &mtk_smi_larb_mt2712 279e6dec923SYong Wu }, 2803c8f4ad8SHonghui Zhang {} 2813c8f4ad8SHonghui Zhang }; 2823c8f4ad8SHonghui Zhang 283cc8bbe1aSYong Wu static int mtk_smi_larb_probe(struct platform_device *pdev) 284cc8bbe1aSYong Wu { 285cc8bbe1aSYong Wu struct mtk_smi_larb *larb; 286cc8bbe1aSYong Wu struct resource *res; 287cc8bbe1aSYong Wu struct device *dev = &pdev->dev; 288cc8bbe1aSYong Wu struct device_node *smi_node; 289cc8bbe1aSYong Wu struct platform_device *smi_pdev; 290363932cdSHonghui Zhang int err; 291cc8bbe1aSYong Wu 292cc8bbe1aSYong Wu larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); 293cc8bbe1aSYong Wu if (!larb) 294cc8bbe1aSYong Wu return -ENOMEM; 295cc8bbe1aSYong Wu 29675487860SHonghui Zhang larb->larb_gen = of_device_get_match_data(dev); 297cc8bbe1aSYong Wu res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 298cc8bbe1aSYong Wu larb->base = devm_ioremap_resource(dev, res); 299cc8bbe1aSYong Wu if (IS_ERR(larb->base)) 300cc8bbe1aSYong Wu return PTR_ERR(larb->base); 301cc8bbe1aSYong Wu 302cc8bbe1aSYong Wu larb->smi.clk_apb = devm_clk_get(dev, "apb"); 303cc8bbe1aSYong Wu if (IS_ERR(larb->smi.clk_apb)) 304cc8bbe1aSYong Wu return PTR_ERR(larb->smi.clk_apb); 305cc8bbe1aSYong Wu 306cc8bbe1aSYong Wu larb->smi.clk_smi = devm_clk_get(dev, "smi"); 307cc8bbe1aSYong Wu if (IS_ERR(larb->smi.clk_smi)) 308cc8bbe1aSYong Wu return PTR_ERR(larb->smi.clk_smi); 309cc8bbe1aSYong Wu larb->smi.dev = dev; 310cc8bbe1aSYong Wu 311363932cdSHonghui Zhang if (larb->larb_gen->need_larbid) { 312363932cdSHonghui Zhang err = of_property_read_u32(dev->of_node, "mediatek,larb-id", 313363932cdSHonghui Zhang &larb->larbid); 314363932cdSHonghui Zhang if (err) { 315363932cdSHonghui Zhang dev_err(dev, "missing larbid property\n"); 316363932cdSHonghui Zhang return err; 317363932cdSHonghui Zhang } 318363932cdSHonghui Zhang } 319363932cdSHonghui Zhang 320cc8bbe1aSYong Wu smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0); 321cc8bbe1aSYong Wu if (!smi_node) 322cc8bbe1aSYong Wu return -EINVAL; 323cc8bbe1aSYong Wu 324cc8bbe1aSYong Wu smi_pdev = of_find_device_by_node(smi_node); 325cc8bbe1aSYong Wu of_node_put(smi_node); 326cc8bbe1aSYong Wu if (smi_pdev) { 3274f608d38SYong Wu if (!platform_get_drvdata(smi_pdev)) 3284f608d38SYong Wu return -EPROBE_DEFER; 329cc8bbe1aSYong Wu larb->smi_common_dev = &smi_pdev->dev; 330cc8bbe1aSYong Wu } else { 331cc8bbe1aSYong Wu dev_err(dev, "Failed to get the smi_common device\n"); 332cc8bbe1aSYong Wu return -EINVAL; 333cc8bbe1aSYong Wu } 334cc8bbe1aSYong Wu 335cc8bbe1aSYong Wu pm_runtime_enable(dev); 336cc8bbe1aSYong Wu platform_set_drvdata(pdev, larb); 337cc8bbe1aSYong Wu return component_add(dev, &mtk_smi_larb_component_ops); 338cc8bbe1aSYong Wu } 339cc8bbe1aSYong Wu 340cc8bbe1aSYong Wu static int mtk_smi_larb_remove(struct platform_device *pdev) 341cc8bbe1aSYong Wu { 342cc8bbe1aSYong Wu pm_runtime_disable(&pdev->dev); 343cc8bbe1aSYong Wu component_del(&pdev->dev, &mtk_smi_larb_component_ops); 344cc8bbe1aSYong Wu return 0; 345cc8bbe1aSYong Wu } 346cc8bbe1aSYong Wu 347cc8bbe1aSYong Wu static struct platform_driver mtk_smi_larb_driver = { 348cc8bbe1aSYong Wu .probe = mtk_smi_larb_probe, 349cc8bbe1aSYong Wu .remove = mtk_smi_larb_remove, 350cc8bbe1aSYong Wu .driver = { 351cc8bbe1aSYong Wu .name = "mtk-smi-larb", 352cc8bbe1aSYong Wu .of_match_table = mtk_smi_larb_of_ids, 353cc8bbe1aSYong Wu } 354cc8bbe1aSYong Wu }; 355cc8bbe1aSYong Wu 3563c8f4ad8SHonghui Zhang static const struct of_device_id mtk_smi_common_of_ids[] = { 3573c8f4ad8SHonghui Zhang { 3583c8f4ad8SHonghui Zhang .compatible = "mediatek,mt8173-smi-common", 3593c8f4ad8SHonghui Zhang .data = (void *)MTK_SMI_GEN2 3603c8f4ad8SHonghui Zhang }, 3613c8f4ad8SHonghui Zhang { 3623c8f4ad8SHonghui Zhang .compatible = "mediatek,mt2701-smi-common", 3633c8f4ad8SHonghui Zhang .data = (void *)MTK_SMI_GEN1 3643c8f4ad8SHonghui Zhang }, 365e6dec923SYong Wu { 366e6dec923SYong Wu .compatible = "mediatek,mt2712-smi-common", 367e6dec923SYong Wu .data = (void *)MTK_SMI_GEN2 368e6dec923SYong Wu }, 3693c8f4ad8SHonghui Zhang {} 3703c8f4ad8SHonghui Zhang }; 3713c8f4ad8SHonghui Zhang 372cc8bbe1aSYong Wu static int mtk_smi_common_probe(struct platform_device *pdev) 373cc8bbe1aSYong Wu { 374cc8bbe1aSYong Wu struct device *dev = &pdev->dev; 375cc8bbe1aSYong Wu struct mtk_smi *common; 3763c8f4ad8SHonghui Zhang struct resource *res; 3773c8f4ad8SHonghui Zhang enum mtk_smi_gen smi_gen; 37846cc815dSArvind Yadav int ret; 379cc8bbe1aSYong Wu 380cc8bbe1aSYong Wu common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); 381cc8bbe1aSYong Wu if (!common) 382cc8bbe1aSYong Wu return -ENOMEM; 383cc8bbe1aSYong Wu common->dev = dev; 384cc8bbe1aSYong Wu 385cc8bbe1aSYong Wu common->clk_apb = devm_clk_get(dev, "apb"); 386cc8bbe1aSYong Wu if (IS_ERR(common->clk_apb)) 387cc8bbe1aSYong Wu return PTR_ERR(common->clk_apb); 388cc8bbe1aSYong Wu 389cc8bbe1aSYong Wu common->clk_smi = devm_clk_get(dev, "smi"); 390cc8bbe1aSYong Wu if (IS_ERR(common->clk_smi)) 391cc8bbe1aSYong Wu return PTR_ERR(common->clk_smi); 392cc8bbe1aSYong Wu 3933c8f4ad8SHonghui Zhang /* 3943c8f4ad8SHonghui Zhang * for mtk smi gen 1, we need to get the ao(always on) base to config 3953c8f4ad8SHonghui Zhang * m4u port, and we need to enable the aync clock for transform the smi 3963c8f4ad8SHonghui Zhang * clock into emi clock domain, but for mtk smi gen2, there's no smi ao 3973c8f4ad8SHonghui Zhang * base. 3983c8f4ad8SHonghui Zhang */ 39975487860SHonghui Zhang smi_gen = (enum mtk_smi_gen)of_device_get_match_data(dev); 4003c8f4ad8SHonghui Zhang if (smi_gen == MTK_SMI_GEN1) { 4013c8f4ad8SHonghui Zhang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4023c8f4ad8SHonghui Zhang common->smi_ao_base = devm_ioremap_resource(dev, res); 4033c8f4ad8SHonghui Zhang if (IS_ERR(common->smi_ao_base)) 4043c8f4ad8SHonghui Zhang return PTR_ERR(common->smi_ao_base); 4053c8f4ad8SHonghui Zhang 4063c8f4ad8SHonghui Zhang common->clk_async = devm_clk_get(dev, "async"); 4073c8f4ad8SHonghui Zhang if (IS_ERR(common->clk_async)) 4083c8f4ad8SHonghui Zhang return PTR_ERR(common->clk_async); 4093c8f4ad8SHonghui Zhang 41046cc815dSArvind Yadav ret = clk_prepare_enable(common->clk_async); 41146cc815dSArvind Yadav if (ret) 41246cc815dSArvind Yadav return ret; 4133c8f4ad8SHonghui Zhang } 414cc8bbe1aSYong Wu pm_runtime_enable(dev); 415cc8bbe1aSYong Wu platform_set_drvdata(pdev, common); 416cc8bbe1aSYong Wu return 0; 417cc8bbe1aSYong Wu } 418cc8bbe1aSYong Wu 419cc8bbe1aSYong Wu static int mtk_smi_common_remove(struct platform_device *pdev) 420cc8bbe1aSYong Wu { 421cc8bbe1aSYong Wu pm_runtime_disable(&pdev->dev); 422cc8bbe1aSYong Wu return 0; 423cc8bbe1aSYong Wu } 424cc8bbe1aSYong Wu 425cc8bbe1aSYong Wu static struct platform_driver mtk_smi_common_driver = { 426cc8bbe1aSYong Wu .probe = mtk_smi_common_probe, 427cc8bbe1aSYong Wu .remove = mtk_smi_common_remove, 428cc8bbe1aSYong Wu .driver = { 429cc8bbe1aSYong Wu .name = "mtk-smi-common", 430cc8bbe1aSYong Wu .of_match_table = mtk_smi_common_of_ids, 431cc8bbe1aSYong Wu } 432cc8bbe1aSYong Wu }; 433cc8bbe1aSYong Wu 434cc8bbe1aSYong Wu static int __init mtk_smi_init(void) 435cc8bbe1aSYong Wu { 436cc8bbe1aSYong Wu int ret; 437cc8bbe1aSYong Wu 438cc8bbe1aSYong Wu ret = platform_driver_register(&mtk_smi_common_driver); 439cc8bbe1aSYong Wu if (ret != 0) { 440cc8bbe1aSYong Wu pr_err("Failed to register SMI driver\n"); 441cc8bbe1aSYong Wu return ret; 442cc8bbe1aSYong Wu } 443cc8bbe1aSYong Wu 444cc8bbe1aSYong Wu ret = platform_driver_register(&mtk_smi_larb_driver); 445cc8bbe1aSYong Wu if (ret != 0) { 446cc8bbe1aSYong Wu pr_err("Failed to register SMI-LARB driver\n"); 447cc8bbe1aSYong Wu goto err_unreg_smi; 448cc8bbe1aSYong Wu } 449cc8bbe1aSYong Wu return ret; 450cc8bbe1aSYong Wu 451cc8bbe1aSYong Wu err_unreg_smi: 452cc8bbe1aSYong Wu platform_driver_unregister(&mtk_smi_common_driver); 453cc8bbe1aSYong Wu return ret; 454cc8bbe1aSYong Wu } 4553c8f4ad8SHonghui Zhang 4564f608d38SYong Wu module_init(mtk_smi_init); 457