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> 24 25 #define SMI_LARB_MMU_EN 0xf00 26 27 struct mtk_smi { 28 struct device *dev; 29 struct clk *clk_apb, *clk_smi; 30 }; 31 32 struct mtk_smi_larb { /* larb: local arbiter */ 33 struct mtk_smi smi; 34 void __iomem *base; 35 struct device *smi_common_dev; 36 u32 *mmu; 37 }; 38 39 static int mtk_smi_enable(const struct mtk_smi *smi) 40 { 41 int ret; 42 43 ret = pm_runtime_get_sync(smi->dev); 44 if (ret < 0) 45 return ret; 46 47 ret = clk_prepare_enable(smi->clk_apb); 48 if (ret) 49 goto err_put_pm; 50 51 ret = clk_prepare_enable(smi->clk_smi); 52 if (ret) 53 goto err_disable_apb; 54 55 return 0; 56 57 err_disable_apb: 58 clk_disable_unprepare(smi->clk_apb); 59 err_put_pm: 60 pm_runtime_put_sync(smi->dev); 61 return ret; 62 } 63 64 static void mtk_smi_disable(const struct mtk_smi *smi) 65 { 66 clk_disable_unprepare(smi->clk_smi); 67 clk_disable_unprepare(smi->clk_apb); 68 pm_runtime_put_sync(smi->dev); 69 } 70 71 int mtk_smi_larb_get(struct device *larbdev) 72 { 73 struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); 74 struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 75 int ret; 76 77 /* Enable the smi-common's power and clocks */ 78 ret = mtk_smi_enable(common); 79 if (ret) 80 return ret; 81 82 /* Enable the larb's power and clocks */ 83 ret = mtk_smi_enable(&larb->smi); 84 if (ret) { 85 mtk_smi_disable(common); 86 return ret; 87 } 88 89 /* Configure the iommu info for this larb */ 90 writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); 91 92 return 0; 93 } 94 95 void mtk_smi_larb_put(struct device *larbdev) 96 { 97 struct mtk_smi_larb *larb = dev_get_drvdata(larbdev); 98 struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 99 100 /* 101 * Don't de-configure the iommu info for this larb since there may be 102 * several modules in this larb. 103 * The iommu info will be reset after power off. 104 */ 105 106 mtk_smi_disable(&larb->smi); 107 mtk_smi_disable(common); 108 } 109 110 static int 111 mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) 112 { 113 struct mtk_smi_larb *larb = dev_get_drvdata(dev); 114 struct mtk_smi_iommu *smi_iommu = data; 115 unsigned int i; 116 117 for (i = 0; i < smi_iommu->larb_nr; i++) { 118 if (dev == smi_iommu->larb_imu[i].dev) { 119 /* The 'mmu' may be updated in iommu-attach/detach. */ 120 larb->mmu = &smi_iommu->larb_imu[i].mmu; 121 return 0; 122 } 123 } 124 return -ENODEV; 125 } 126 127 static void 128 mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) 129 { 130 /* Do nothing as the iommu is always enabled. */ 131 } 132 133 static const struct component_ops mtk_smi_larb_component_ops = { 134 .bind = mtk_smi_larb_bind, 135 .unbind = mtk_smi_larb_unbind, 136 }; 137 138 static int mtk_smi_larb_probe(struct platform_device *pdev) 139 { 140 struct mtk_smi_larb *larb; 141 struct resource *res; 142 struct device *dev = &pdev->dev; 143 struct device_node *smi_node; 144 struct platform_device *smi_pdev; 145 146 if (!dev->pm_domain) 147 return -EPROBE_DEFER; 148 149 larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); 150 if (!larb) 151 return -ENOMEM; 152 153 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 154 larb->base = devm_ioremap_resource(dev, res); 155 if (IS_ERR(larb->base)) 156 return PTR_ERR(larb->base); 157 158 larb->smi.clk_apb = devm_clk_get(dev, "apb"); 159 if (IS_ERR(larb->smi.clk_apb)) 160 return PTR_ERR(larb->smi.clk_apb); 161 162 larb->smi.clk_smi = devm_clk_get(dev, "smi"); 163 if (IS_ERR(larb->smi.clk_smi)) 164 return PTR_ERR(larb->smi.clk_smi); 165 larb->smi.dev = dev; 166 167 smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0); 168 if (!smi_node) 169 return -EINVAL; 170 171 smi_pdev = of_find_device_by_node(smi_node); 172 of_node_put(smi_node); 173 if (smi_pdev) { 174 larb->smi_common_dev = &smi_pdev->dev; 175 } else { 176 dev_err(dev, "Failed to get the smi_common device\n"); 177 return -EINVAL; 178 } 179 180 pm_runtime_enable(dev); 181 platform_set_drvdata(pdev, larb); 182 return component_add(dev, &mtk_smi_larb_component_ops); 183 } 184 185 static int mtk_smi_larb_remove(struct platform_device *pdev) 186 { 187 pm_runtime_disable(&pdev->dev); 188 component_del(&pdev->dev, &mtk_smi_larb_component_ops); 189 return 0; 190 } 191 192 static const struct of_device_id mtk_smi_larb_of_ids[] = { 193 { .compatible = "mediatek,mt8173-smi-larb",}, 194 {} 195 }; 196 197 static struct platform_driver mtk_smi_larb_driver = { 198 .probe = mtk_smi_larb_probe, 199 .remove = mtk_smi_larb_remove, 200 .driver = { 201 .name = "mtk-smi-larb", 202 .of_match_table = mtk_smi_larb_of_ids, 203 } 204 }; 205 206 static int mtk_smi_common_probe(struct platform_device *pdev) 207 { 208 struct device *dev = &pdev->dev; 209 struct mtk_smi *common; 210 211 if (!dev->pm_domain) 212 return -EPROBE_DEFER; 213 214 common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); 215 if (!common) 216 return -ENOMEM; 217 common->dev = dev; 218 219 common->clk_apb = devm_clk_get(dev, "apb"); 220 if (IS_ERR(common->clk_apb)) 221 return PTR_ERR(common->clk_apb); 222 223 common->clk_smi = devm_clk_get(dev, "smi"); 224 if (IS_ERR(common->clk_smi)) 225 return PTR_ERR(common->clk_smi); 226 227 pm_runtime_enable(dev); 228 platform_set_drvdata(pdev, common); 229 return 0; 230 } 231 232 static int mtk_smi_common_remove(struct platform_device *pdev) 233 { 234 pm_runtime_disable(&pdev->dev); 235 return 0; 236 } 237 238 static const struct of_device_id mtk_smi_common_of_ids[] = { 239 { .compatible = "mediatek,mt8173-smi-common", }, 240 {} 241 }; 242 243 static struct platform_driver mtk_smi_common_driver = { 244 .probe = mtk_smi_common_probe, 245 .remove = mtk_smi_common_remove, 246 .driver = { 247 .name = "mtk-smi-common", 248 .of_match_table = mtk_smi_common_of_ids, 249 } 250 }; 251 252 static int __init mtk_smi_init(void) 253 { 254 int ret; 255 256 ret = platform_driver_register(&mtk_smi_common_driver); 257 if (ret != 0) { 258 pr_err("Failed to register SMI driver\n"); 259 return ret; 260 } 261 262 ret = platform_driver_register(&mtk_smi_larb_driver); 263 if (ret != 0) { 264 pr_err("Failed to register SMI-LARB driver\n"); 265 goto err_unreg_smi; 266 } 267 return ret; 268 269 err_unreg_smi: 270 platform_driver_unregister(&mtk_smi_common_driver); 271 return ret; 272 } 273 subsys_initcall(mtk_smi_init); 274