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 443c8f4ad8SHonghui Zhang struct mtk_smi_larb_gen { 45363932cdSHonghui Zhang bool need_larbid; 463c8f4ad8SHonghui Zhang int port_in_larb[MTK_LARB_NR_MAX + 1]; 473c8f4ad8SHonghui Zhang void (*config_port)(struct device *); 483c8f4ad8SHonghui Zhang }; 49cc8bbe1aSYong Wu 50cc8bbe1aSYong Wu struct mtk_smi { 51cc8bbe1aSYong Wu struct device *dev; 52cc8bbe1aSYong Wu struct clk *clk_apb, *clk_smi; 533c8f4ad8SHonghui Zhang struct clk *clk_async; /*only needed by mt2701*/ 543c8f4ad8SHonghui Zhang void __iomem *smi_ao_base; 55cc8bbe1aSYong Wu }; 56cc8bbe1aSYong Wu 57cc8bbe1aSYong Wu struct mtk_smi_larb { /* larb: local arbiter */ 58cc8bbe1aSYong Wu struct mtk_smi smi; 59cc8bbe1aSYong Wu void __iomem *base; 60cc8bbe1aSYong Wu struct device *smi_common_dev; 613c8f4ad8SHonghui Zhang const struct mtk_smi_larb_gen *larb_gen; 623c8f4ad8SHonghui Zhang int larbid; 63cc8bbe1aSYong Wu u32 *mmu; 64cc8bbe1aSYong Wu }; 65cc8bbe1aSYong Wu 663c8f4ad8SHonghui Zhang enum mtk_smi_gen { 673c8f4ad8SHonghui Zhang MTK_SMI_GEN1, 683c8f4ad8SHonghui Zhang MTK_SMI_GEN2 693c8f4ad8SHonghui Zhang }; 703c8f4ad8SHonghui Zhang 71cc8bbe1aSYong Wu static int mtk_smi_enable(const struct mtk_smi *smi) 72cc8bbe1aSYong Wu { 73cc8bbe1aSYong Wu int ret; 74cc8bbe1aSYong Wu 75cc8bbe1aSYong Wu ret = pm_runtime_get_sync(smi->dev); 76cc8bbe1aSYong Wu if (ret < 0) 77cc8bbe1aSYong Wu return ret; 78cc8bbe1aSYong Wu 79cc8bbe1aSYong Wu ret = clk_prepare_enable(smi->clk_apb); 80cc8bbe1aSYong Wu if (ret) 81cc8bbe1aSYong Wu goto err_put_pm; 82cc8bbe1aSYong Wu 83cc8bbe1aSYong Wu ret = clk_prepare_enable(smi->clk_smi); 84cc8bbe1aSYong Wu if (ret) 85cc8bbe1aSYong Wu goto err_disable_apb; 86cc8bbe1aSYong Wu 87cc8bbe1aSYong Wu return 0; 88cc8bbe1aSYong Wu 89cc8bbe1aSYong Wu err_disable_apb: 90cc8bbe1aSYong Wu clk_disable_unprepare(smi->clk_apb); 91cc8bbe1aSYong Wu err_put_pm: 92cc8bbe1aSYong Wu pm_runtime_put_sync(smi->dev); 93cc8bbe1aSYong Wu return ret; 94cc8bbe1aSYong Wu } 95cc8bbe1aSYong Wu 96cc8bbe1aSYong Wu static void mtk_smi_disable(const struct mtk_smi *smi) 97cc8bbe1aSYong Wu { 98cc8bbe1aSYong Wu clk_disable_unprepare(smi->clk_smi); 99cc8bbe1aSYong Wu clk_disable_unprepare(smi->clk_apb); 100cc8bbe1aSYong Wu pm_runtime_put_sync(smi->dev); 101cc8bbe1aSYong Wu } 102cc8bbe1aSYong Wu 103cc8bbe1aSYong Wu int mtk_smi_larb_get(struct device *larbdev) 104cc8bbe1aSYong Wu { 105cc8bbe1aSYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); 1063c8f4ad8SHonghui Zhang const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; 107cc8bbe1aSYong Wu struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 108cc8bbe1aSYong Wu int ret; 109cc8bbe1aSYong Wu 110cc8bbe1aSYong Wu /* Enable the smi-common's power and clocks */ 111cc8bbe1aSYong Wu ret = mtk_smi_enable(common); 112cc8bbe1aSYong Wu if (ret) 113cc8bbe1aSYong Wu return ret; 114cc8bbe1aSYong Wu 115cc8bbe1aSYong Wu /* Enable the larb's power and clocks */ 116cc8bbe1aSYong Wu ret = mtk_smi_enable(&larb->smi); 117cc8bbe1aSYong Wu if (ret) { 118cc8bbe1aSYong Wu mtk_smi_disable(common); 119cc8bbe1aSYong Wu return ret; 120cc8bbe1aSYong Wu } 121cc8bbe1aSYong Wu 122cc8bbe1aSYong Wu /* Configure the iommu info for this larb */ 1233c8f4ad8SHonghui Zhang larb_gen->config_port(larbdev); 124cc8bbe1aSYong Wu 125cc8bbe1aSYong Wu return 0; 126cc8bbe1aSYong Wu } 127cb1b5dffSPhilipp Zabel EXPORT_SYMBOL_GPL(mtk_smi_larb_get); 128cc8bbe1aSYong Wu 129cc8bbe1aSYong Wu void mtk_smi_larb_put(struct device *larbdev) 130cc8bbe1aSYong Wu { 131cc8bbe1aSYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); 132cc8bbe1aSYong Wu struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 133cc8bbe1aSYong Wu 134cc8bbe1aSYong Wu /* 135cc8bbe1aSYong Wu * Don't de-configure the iommu info for this larb since there may be 136cc8bbe1aSYong Wu * several modules in this larb. 137cc8bbe1aSYong Wu * The iommu info will be reset after power off. 138cc8bbe1aSYong Wu */ 139cc8bbe1aSYong Wu 140cc8bbe1aSYong Wu mtk_smi_disable(&larb->smi); 141cc8bbe1aSYong Wu mtk_smi_disable(common); 142cc8bbe1aSYong Wu } 143cb1b5dffSPhilipp Zabel EXPORT_SYMBOL_GPL(mtk_smi_larb_put); 144cc8bbe1aSYong Wu 145cc8bbe1aSYong Wu static int 146cc8bbe1aSYong Wu mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) 147cc8bbe1aSYong Wu { 148cc8bbe1aSYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(dev); 149cc8bbe1aSYong Wu struct mtk_smi_iommu *smi_iommu = data; 150cc8bbe1aSYong Wu unsigned int i; 151cc8bbe1aSYong Wu 152e6dec923SYong Wu if (larb->larb_gen->need_larbid) { 153e6dec923SYong Wu larb->mmu = &smi_iommu->larb_imu[larb->larbid].mmu; 154e6dec923SYong Wu return 0; 155e6dec923SYong Wu } 156e6dec923SYong Wu 157e6dec923SYong Wu /* 158e6dec923SYong Wu * If there is no larbid property, Loop to find the corresponding 159e6dec923SYong Wu * iommu information. 160e6dec923SYong Wu */ 161cc8bbe1aSYong Wu for (i = 0; i < smi_iommu->larb_nr; i++) { 162cc8bbe1aSYong Wu if (dev == smi_iommu->larb_imu[i].dev) { 163cc8bbe1aSYong Wu /* The 'mmu' may be updated in iommu-attach/detach. */ 164cc8bbe1aSYong Wu larb->mmu = &smi_iommu->larb_imu[i].mmu; 165cc8bbe1aSYong Wu return 0; 166cc8bbe1aSYong Wu } 167cc8bbe1aSYong Wu } 168cc8bbe1aSYong Wu return -ENODEV; 169cc8bbe1aSYong Wu } 170cc8bbe1aSYong Wu 171e6dec923SYong Wu static void mtk_smi_larb_config_port_mt2712(struct device *dev) 172e6dec923SYong Wu { 173e6dec923SYong Wu struct mtk_smi_larb *larb = dev_get_drvdata(dev); 174e6dec923SYong Wu u32 reg; 175e6dec923SYong Wu int i; 176e6dec923SYong Wu 177e6dec923SYong Wu /* 178e6dec923SYong Wu * larb 8/9 is the bdpsys larb, the iommu_en is enabled defaultly. 179e6dec923SYong Wu * Don't need to set it again. 180e6dec923SYong Wu */ 181e6dec923SYong Wu if (larb->larbid == 8 || larb->larbid == 9) 182e6dec923SYong Wu return; 183e6dec923SYong Wu 184e6dec923SYong Wu for_each_set_bit(i, (unsigned long *)larb->mmu, 32) { 185e6dec923SYong Wu reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i)); 186e6dec923SYong Wu reg |= F_MMU_EN; 187e6dec923SYong Wu writel(reg, larb->base + SMI_LARB_NONSEC_CON(i)); 188e6dec923SYong Wu } 189e6dec923SYong Wu } 190e6dec923SYong Wu 191e6dec923SYong Wu static void mtk_smi_larb_config_port_mt8173(struct device *dev) 1923c8f4ad8SHonghui Zhang { 1933c8f4ad8SHonghui Zhang struct mtk_smi_larb *larb = dev_get_drvdata(dev); 1943c8f4ad8SHonghui Zhang 1953c8f4ad8SHonghui Zhang writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); 1963c8f4ad8SHonghui Zhang } 1973c8f4ad8SHonghui Zhang 1983c8f4ad8SHonghui Zhang static void mtk_smi_larb_config_port_gen1(struct device *dev) 1993c8f4ad8SHonghui Zhang { 2003c8f4ad8SHonghui Zhang struct mtk_smi_larb *larb = dev_get_drvdata(dev); 2013c8f4ad8SHonghui Zhang const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; 2023c8f4ad8SHonghui Zhang struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 2033c8f4ad8SHonghui Zhang int i, m4u_port_id, larb_port_num; 2043c8f4ad8SHonghui Zhang u32 sec_con_val, reg_val; 2053c8f4ad8SHonghui Zhang 2063c8f4ad8SHonghui Zhang m4u_port_id = larb_gen->port_in_larb[larb->larbid]; 2073c8f4ad8SHonghui Zhang larb_port_num = larb_gen->port_in_larb[larb->larbid + 1] 2083c8f4ad8SHonghui Zhang - larb_gen->port_in_larb[larb->larbid]; 2093c8f4ad8SHonghui Zhang 2103c8f4ad8SHonghui Zhang for (i = 0; i < larb_port_num; i++, m4u_port_id++) { 2113c8f4ad8SHonghui Zhang if (*larb->mmu & BIT(i)) { 2123c8f4ad8SHonghui Zhang /* bit[port + 3] controls the virtual or physical */ 2133c8f4ad8SHonghui Zhang sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id); 2143c8f4ad8SHonghui Zhang } else { 2153c8f4ad8SHonghui Zhang /* do not need to enable m4u for this port */ 2163c8f4ad8SHonghui Zhang continue; 2173c8f4ad8SHonghui Zhang } 2183c8f4ad8SHonghui Zhang reg_val = readl(common->smi_ao_base 2193c8f4ad8SHonghui Zhang + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); 2203c8f4ad8SHonghui Zhang reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id); 2213c8f4ad8SHonghui Zhang reg_val |= sec_con_val; 2223c8f4ad8SHonghui Zhang reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id); 2233c8f4ad8SHonghui Zhang writel(reg_val, 2243c8f4ad8SHonghui Zhang common->smi_ao_base 2253c8f4ad8SHonghui Zhang + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); 2263c8f4ad8SHonghui Zhang } 2273c8f4ad8SHonghui Zhang } 2283c8f4ad8SHonghui Zhang 229cc8bbe1aSYong Wu static void 230cc8bbe1aSYong Wu mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) 231cc8bbe1aSYong Wu { 232cc8bbe1aSYong Wu /* Do nothing as the iommu is always enabled. */ 233cc8bbe1aSYong Wu } 234cc8bbe1aSYong Wu 235cc8bbe1aSYong Wu static const struct component_ops mtk_smi_larb_component_ops = { 236cc8bbe1aSYong Wu .bind = mtk_smi_larb_bind, 237cc8bbe1aSYong Wu .unbind = mtk_smi_larb_unbind, 238cc8bbe1aSYong Wu }; 239cc8bbe1aSYong Wu 2403c8f4ad8SHonghui Zhang static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = { 2413c8f4ad8SHonghui Zhang /* mt8173 do not need the port in larb */ 242e6dec923SYong Wu .config_port = mtk_smi_larb_config_port_mt8173, 2433c8f4ad8SHonghui Zhang }; 2443c8f4ad8SHonghui Zhang 2453c8f4ad8SHonghui Zhang static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = { 246363932cdSHonghui Zhang .need_larbid = true, 2473c8f4ad8SHonghui Zhang .port_in_larb = { 2483c8f4ad8SHonghui Zhang LARB0_PORT_OFFSET, LARB1_PORT_OFFSET, 2493c8f4ad8SHonghui Zhang LARB2_PORT_OFFSET, LARB3_PORT_OFFSET 2503c8f4ad8SHonghui Zhang }, 2513c8f4ad8SHonghui Zhang .config_port = mtk_smi_larb_config_port_gen1, 2523c8f4ad8SHonghui Zhang }; 2533c8f4ad8SHonghui Zhang 254e6dec923SYong Wu static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = { 255e6dec923SYong Wu .need_larbid = true, 256e6dec923SYong Wu .config_port = mtk_smi_larb_config_port_mt2712, 257e6dec923SYong Wu }; 258e6dec923SYong Wu 2593c8f4ad8SHonghui Zhang static const struct of_device_id mtk_smi_larb_of_ids[] = { 2603c8f4ad8SHonghui Zhang { 2613c8f4ad8SHonghui Zhang .compatible = "mediatek,mt8173-smi-larb", 2623c8f4ad8SHonghui Zhang .data = &mtk_smi_larb_mt8173 2633c8f4ad8SHonghui Zhang }, 2643c8f4ad8SHonghui Zhang { 2653c8f4ad8SHonghui Zhang .compatible = "mediatek,mt2701-smi-larb", 2663c8f4ad8SHonghui Zhang .data = &mtk_smi_larb_mt2701 2673c8f4ad8SHonghui Zhang }, 268e6dec923SYong Wu { 269e6dec923SYong Wu .compatible = "mediatek,mt2712-smi-larb", 270e6dec923SYong Wu .data = &mtk_smi_larb_mt2712 271e6dec923SYong Wu }, 2723c8f4ad8SHonghui Zhang {} 2733c8f4ad8SHonghui Zhang }; 2743c8f4ad8SHonghui Zhang 275cc8bbe1aSYong Wu static int mtk_smi_larb_probe(struct platform_device *pdev) 276cc8bbe1aSYong Wu { 277cc8bbe1aSYong Wu struct mtk_smi_larb *larb; 278cc8bbe1aSYong Wu struct resource *res; 279cc8bbe1aSYong Wu struct device *dev = &pdev->dev; 280cc8bbe1aSYong Wu struct device_node *smi_node; 281cc8bbe1aSYong Wu struct platform_device *smi_pdev; 282363932cdSHonghui Zhang int err; 283cc8bbe1aSYong Wu 284cc8bbe1aSYong Wu larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); 285cc8bbe1aSYong Wu if (!larb) 286cc8bbe1aSYong Wu return -ENOMEM; 287cc8bbe1aSYong Wu 28875487860SHonghui Zhang larb->larb_gen = of_device_get_match_data(dev); 289cc8bbe1aSYong Wu res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 290cc8bbe1aSYong Wu larb->base = devm_ioremap_resource(dev, res); 291cc8bbe1aSYong Wu if (IS_ERR(larb->base)) 292cc8bbe1aSYong Wu return PTR_ERR(larb->base); 293cc8bbe1aSYong Wu 294cc8bbe1aSYong Wu larb->smi.clk_apb = devm_clk_get(dev, "apb"); 295cc8bbe1aSYong Wu if (IS_ERR(larb->smi.clk_apb)) 296cc8bbe1aSYong Wu return PTR_ERR(larb->smi.clk_apb); 297cc8bbe1aSYong Wu 298cc8bbe1aSYong Wu larb->smi.clk_smi = devm_clk_get(dev, "smi"); 299cc8bbe1aSYong Wu if (IS_ERR(larb->smi.clk_smi)) 300cc8bbe1aSYong Wu return PTR_ERR(larb->smi.clk_smi); 301cc8bbe1aSYong Wu larb->smi.dev = dev; 302cc8bbe1aSYong Wu 303363932cdSHonghui Zhang if (larb->larb_gen->need_larbid) { 304363932cdSHonghui Zhang err = of_property_read_u32(dev->of_node, "mediatek,larb-id", 305363932cdSHonghui Zhang &larb->larbid); 306363932cdSHonghui Zhang if (err) { 307363932cdSHonghui Zhang dev_err(dev, "missing larbid property\n"); 308363932cdSHonghui Zhang return err; 309363932cdSHonghui Zhang } 310363932cdSHonghui Zhang } 311363932cdSHonghui Zhang 312cc8bbe1aSYong Wu smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0); 313cc8bbe1aSYong Wu if (!smi_node) 314cc8bbe1aSYong Wu return -EINVAL; 315cc8bbe1aSYong Wu 316cc8bbe1aSYong Wu smi_pdev = of_find_device_by_node(smi_node); 317cc8bbe1aSYong Wu of_node_put(smi_node); 318cc8bbe1aSYong Wu if (smi_pdev) { 3194f608d38SYong Wu if (!platform_get_drvdata(smi_pdev)) 3204f608d38SYong Wu return -EPROBE_DEFER; 321cc8bbe1aSYong Wu larb->smi_common_dev = &smi_pdev->dev; 322cc8bbe1aSYong Wu } else { 323cc8bbe1aSYong Wu dev_err(dev, "Failed to get the smi_common device\n"); 324cc8bbe1aSYong Wu return -EINVAL; 325cc8bbe1aSYong Wu } 326cc8bbe1aSYong Wu 327cc8bbe1aSYong Wu pm_runtime_enable(dev); 328cc8bbe1aSYong Wu platform_set_drvdata(pdev, larb); 329cc8bbe1aSYong Wu return component_add(dev, &mtk_smi_larb_component_ops); 330cc8bbe1aSYong Wu } 331cc8bbe1aSYong Wu 332cc8bbe1aSYong Wu static int mtk_smi_larb_remove(struct platform_device *pdev) 333cc8bbe1aSYong Wu { 334cc8bbe1aSYong Wu pm_runtime_disable(&pdev->dev); 335cc8bbe1aSYong Wu component_del(&pdev->dev, &mtk_smi_larb_component_ops); 336cc8bbe1aSYong Wu return 0; 337cc8bbe1aSYong Wu } 338cc8bbe1aSYong Wu 339cc8bbe1aSYong Wu static struct platform_driver mtk_smi_larb_driver = { 340cc8bbe1aSYong Wu .probe = mtk_smi_larb_probe, 341cc8bbe1aSYong Wu .remove = mtk_smi_larb_remove, 342cc8bbe1aSYong Wu .driver = { 343cc8bbe1aSYong Wu .name = "mtk-smi-larb", 344cc8bbe1aSYong Wu .of_match_table = mtk_smi_larb_of_ids, 345cc8bbe1aSYong Wu } 346cc8bbe1aSYong Wu }; 347cc8bbe1aSYong Wu 3483c8f4ad8SHonghui Zhang static const struct of_device_id mtk_smi_common_of_ids[] = { 3493c8f4ad8SHonghui Zhang { 3503c8f4ad8SHonghui Zhang .compatible = "mediatek,mt8173-smi-common", 3513c8f4ad8SHonghui Zhang .data = (void *)MTK_SMI_GEN2 3523c8f4ad8SHonghui Zhang }, 3533c8f4ad8SHonghui Zhang { 3543c8f4ad8SHonghui Zhang .compatible = "mediatek,mt2701-smi-common", 3553c8f4ad8SHonghui Zhang .data = (void *)MTK_SMI_GEN1 3563c8f4ad8SHonghui Zhang }, 357e6dec923SYong Wu { 358e6dec923SYong Wu .compatible = "mediatek,mt2712-smi-common", 359e6dec923SYong Wu .data = (void *)MTK_SMI_GEN2 360e6dec923SYong Wu }, 3613c8f4ad8SHonghui Zhang {} 3623c8f4ad8SHonghui Zhang }; 3633c8f4ad8SHonghui Zhang 364cc8bbe1aSYong Wu static int mtk_smi_common_probe(struct platform_device *pdev) 365cc8bbe1aSYong Wu { 366cc8bbe1aSYong Wu struct device *dev = &pdev->dev; 367cc8bbe1aSYong Wu struct mtk_smi *common; 3683c8f4ad8SHonghui Zhang struct resource *res; 3693c8f4ad8SHonghui Zhang enum mtk_smi_gen smi_gen; 37046cc815dSArvind Yadav int ret; 371cc8bbe1aSYong Wu 372cc8bbe1aSYong Wu common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); 373cc8bbe1aSYong Wu if (!common) 374cc8bbe1aSYong Wu return -ENOMEM; 375cc8bbe1aSYong Wu common->dev = dev; 376cc8bbe1aSYong Wu 377cc8bbe1aSYong Wu common->clk_apb = devm_clk_get(dev, "apb"); 378cc8bbe1aSYong Wu if (IS_ERR(common->clk_apb)) 379cc8bbe1aSYong Wu return PTR_ERR(common->clk_apb); 380cc8bbe1aSYong Wu 381cc8bbe1aSYong Wu common->clk_smi = devm_clk_get(dev, "smi"); 382cc8bbe1aSYong Wu if (IS_ERR(common->clk_smi)) 383cc8bbe1aSYong Wu return PTR_ERR(common->clk_smi); 384cc8bbe1aSYong Wu 3853c8f4ad8SHonghui Zhang /* 3863c8f4ad8SHonghui Zhang * for mtk smi gen 1, we need to get the ao(always on) base to config 3873c8f4ad8SHonghui Zhang * m4u port, and we need to enable the aync clock for transform the smi 3883c8f4ad8SHonghui Zhang * clock into emi clock domain, but for mtk smi gen2, there's no smi ao 3893c8f4ad8SHonghui Zhang * base. 3903c8f4ad8SHonghui Zhang */ 39175487860SHonghui Zhang smi_gen = (enum mtk_smi_gen)of_device_get_match_data(dev); 3923c8f4ad8SHonghui Zhang if (smi_gen == MTK_SMI_GEN1) { 3933c8f4ad8SHonghui Zhang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3943c8f4ad8SHonghui Zhang common->smi_ao_base = devm_ioremap_resource(dev, res); 3953c8f4ad8SHonghui Zhang if (IS_ERR(common->smi_ao_base)) 3963c8f4ad8SHonghui Zhang return PTR_ERR(common->smi_ao_base); 3973c8f4ad8SHonghui Zhang 3983c8f4ad8SHonghui Zhang common->clk_async = devm_clk_get(dev, "async"); 3993c8f4ad8SHonghui Zhang if (IS_ERR(common->clk_async)) 4003c8f4ad8SHonghui Zhang return PTR_ERR(common->clk_async); 4013c8f4ad8SHonghui Zhang 40246cc815dSArvind Yadav ret = clk_prepare_enable(common->clk_async); 40346cc815dSArvind Yadav if (ret) 40446cc815dSArvind Yadav return ret; 4053c8f4ad8SHonghui Zhang } 406cc8bbe1aSYong Wu pm_runtime_enable(dev); 407cc8bbe1aSYong Wu platform_set_drvdata(pdev, common); 408cc8bbe1aSYong Wu return 0; 409cc8bbe1aSYong Wu } 410cc8bbe1aSYong Wu 411cc8bbe1aSYong Wu static int mtk_smi_common_remove(struct platform_device *pdev) 412cc8bbe1aSYong Wu { 413cc8bbe1aSYong Wu pm_runtime_disable(&pdev->dev); 414cc8bbe1aSYong Wu return 0; 415cc8bbe1aSYong Wu } 416cc8bbe1aSYong Wu 417cc8bbe1aSYong Wu static struct platform_driver mtk_smi_common_driver = { 418cc8bbe1aSYong Wu .probe = mtk_smi_common_probe, 419cc8bbe1aSYong Wu .remove = mtk_smi_common_remove, 420cc8bbe1aSYong Wu .driver = { 421cc8bbe1aSYong Wu .name = "mtk-smi-common", 422cc8bbe1aSYong Wu .of_match_table = mtk_smi_common_of_ids, 423cc8bbe1aSYong Wu } 424cc8bbe1aSYong Wu }; 425cc8bbe1aSYong Wu 426cc8bbe1aSYong Wu static int __init mtk_smi_init(void) 427cc8bbe1aSYong Wu { 428cc8bbe1aSYong Wu int ret; 429cc8bbe1aSYong Wu 430cc8bbe1aSYong Wu ret = platform_driver_register(&mtk_smi_common_driver); 431cc8bbe1aSYong Wu if (ret != 0) { 432cc8bbe1aSYong Wu pr_err("Failed to register SMI driver\n"); 433cc8bbe1aSYong Wu return ret; 434cc8bbe1aSYong Wu } 435cc8bbe1aSYong Wu 436cc8bbe1aSYong Wu ret = platform_driver_register(&mtk_smi_larb_driver); 437cc8bbe1aSYong Wu if (ret != 0) { 438cc8bbe1aSYong Wu pr_err("Failed to register SMI-LARB driver\n"); 439cc8bbe1aSYong Wu goto err_unreg_smi; 440cc8bbe1aSYong Wu } 441cc8bbe1aSYong Wu return ret; 442cc8bbe1aSYong Wu 443cc8bbe1aSYong Wu err_unreg_smi: 444cc8bbe1aSYong Wu platform_driver_unregister(&mtk_smi_common_driver); 445cc8bbe1aSYong Wu return ret; 446cc8bbe1aSYong Wu } 4473c8f4ad8SHonghui Zhang 4484f608d38SYong Wu module_init(mtk_smi_init); 449