1 /* 2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <linux/clk.h> 24 #include <linux/io.h> 25 #include <linux/module.h> 26 #include <linux/platform_device.h> 27 #include <linux/of.h> 28 #include <linux/reset.h> 29 #include <linux/regulator/consumer.h> 30 #include <linux/iommu.h> 31 #include <soc/tegra/fuse.h> 32 #include <soc/tegra/pmc.h> 33 34 #include "nouveau_drm.h" 35 #include "nouveau_platform.h" 36 37 static int nouveau_platform_power_up(struct nouveau_platform_gpu *gpu) 38 { 39 int err; 40 41 err = regulator_enable(gpu->vdd); 42 if (err) 43 goto err_power; 44 45 err = clk_prepare_enable(gpu->clk); 46 if (err) 47 goto err_clk; 48 err = clk_prepare_enable(gpu->clk_pwr); 49 if (err) 50 goto err_clk_pwr; 51 clk_set_rate(gpu->clk_pwr, 204000000); 52 udelay(10); 53 54 reset_control_assert(gpu->rst); 55 udelay(10); 56 57 err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); 58 if (err) 59 goto err_clamp; 60 udelay(10); 61 62 reset_control_deassert(gpu->rst); 63 udelay(10); 64 65 return 0; 66 67 err_clamp: 68 clk_disable_unprepare(gpu->clk_pwr); 69 err_clk_pwr: 70 clk_disable_unprepare(gpu->clk); 71 err_clk: 72 regulator_disable(gpu->vdd); 73 err_power: 74 return err; 75 } 76 77 static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu) 78 { 79 int err; 80 81 reset_control_assert(gpu->rst); 82 udelay(10); 83 84 clk_disable_unprepare(gpu->clk_pwr); 85 clk_disable_unprepare(gpu->clk); 86 udelay(10); 87 88 err = regulator_disable(gpu->vdd); 89 if (err) 90 return err; 91 92 return 0; 93 } 94 95 static void nouveau_platform_probe_iommu(struct device *dev, 96 struct nouveau_platform_gpu *gpu) 97 { 98 int err; 99 unsigned long pgsize_bitmap; 100 101 mutex_init(&gpu->iommu.mutex); 102 103 if (iommu_present(&platform_bus_type)) { 104 gpu->iommu.domain = iommu_domain_alloc(&platform_bus_type); 105 if (IS_ERR(gpu->iommu.domain)) 106 goto error; 107 108 /* 109 * A IOMMU is only usable if it supports page sizes smaller 110 * or equal to the system's PAGE_SIZE, with a preference if 111 * both are equal. 112 */ 113 pgsize_bitmap = gpu->iommu.domain->ops->pgsize_bitmap; 114 if (pgsize_bitmap & PAGE_SIZE) { 115 gpu->iommu.pgshift = PAGE_SHIFT; 116 } else { 117 gpu->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK); 118 if (gpu->iommu.pgshift == 0) { 119 dev_warn(dev, "unsupported IOMMU page size\n"); 120 goto free_domain; 121 } 122 gpu->iommu.pgshift -= 1; 123 } 124 125 err = iommu_attach_device(gpu->iommu.domain, dev); 126 if (err) 127 goto free_domain; 128 129 err = nvkm_mm_init(&gpu->iommu._mm, 0, 130 (1ULL << 40) >> gpu->iommu.pgshift, 1); 131 if (err) 132 goto detach_device; 133 134 gpu->iommu.mm = &gpu->iommu._mm; 135 } 136 137 return; 138 139 detach_device: 140 iommu_detach_device(gpu->iommu.domain, dev); 141 142 free_domain: 143 iommu_domain_free(gpu->iommu.domain); 144 145 error: 146 gpu->iommu.domain = NULL; 147 gpu->iommu.pgshift = 0; 148 dev_err(dev, "cannot initialize IOMMU MM\n"); 149 } 150 151 static void nouveau_platform_remove_iommu(struct device *dev, 152 struct nouveau_platform_gpu *gpu) 153 { 154 if (gpu->iommu.domain) { 155 nvkm_mm_fini(&gpu->iommu._mm); 156 iommu_detach_device(gpu->iommu.domain, dev); 157 iommu_domain_free(gpu->iommu.domain); 158 } 159 } 160 161 static int nouveau_platform_probe(struct platform_device *pdev) 162 { 163 struct nouveau_platform_gpu *gpu; 164 struct nouveau_platform_device *device; 165 struct drm_device *drm; 166 int err; 167 168 gpu = devm_kzalloc(&pdev->dev, sizeof(*gpu), GFP_KERNEL); 169 if (!gpu) 170 return -ENOMEM; 171 172 gpu->vdd = devm_regulator_get(&pdev->dev, "vdd"); 173 if (IS_ERR(gpu->vdd)) 174 return PTR_ERR(gpu->vdd); 175 176 gpu->rst = devm_reset_control_get(&pdev->dev, "gpu"); 177 if (IS_ERR(gpu->rst)) 178 return PTR_ERR(gpu->rst); 179 180 gpu->clk = devm_clk_get(&pdev->dev, "gpu"); 181 if (IS_ERR(gpu->clk)) 182 return PTR_ERR(gpu->clk); 183 184 gpu->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); 185 if (IS_ERR(gpu->clk_pwr)) 186 return PTR_ERR(gpu->clk_pwr); 187 188 nouveau_platform_probe_iommu(&pdev->dev, gpu); 189 190 err = nouveau_platform_power_up(gpu); 191 if (err) 192 return err; 193 194 drm = nouveau_platform_device_create(pdev, &device); 195 if (IS_ERR(drm)) { 196 err = PTR_ERR(drm); 197 goto power_down; 198 } 199 200 device->gpu = gpu; 201 device->gpu_speedo = tegra_sku_info.gpu_speedo_value; 202 203 err = drm_dev_register(drm, 0); 204 if (err < 0) 205 goto err_unref; 206 207 return 0; 208 209 err_unref: 210 drm_dev_unref(drm); 211 212 power_down: 213 nouveau_platform_power_down(gpu); 214 nouveau_platform_remove_iommu(&pdev->dev, gpu); 215 216 return err; 217 } 218 219 static int nouveau_platform_remove(struct platform_device *pdev) 220 { 221 struct drm_device *drm_dev = platform_get_drvdata(pdev); 222 struct nouveau_drm *drm = nouveau_drm(drm_dev); 223 struct nvkm_device *device = nvxx_device(&drm->device); 224 struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu; 225 int err; 226 227 nouveau_drm_device_remove(drm_dev); 228 229 err = nouveau_platform_power_down(gpu); 230 231 nouveau_platform_remove_iommu(&pdev->dev, gpu); 232 233 return err; 234 } 235 236 #if IS_ENABLED(CONFIG_OF) 237 static const struct of_device_id nouveau_platform_match[] = { 238 { .compatible = "nvidia,gk20a" }, 239 { } 240 }; 241 242 MODULE_DEVICE_TABLE(of, nouveau_platform_match); 243 #endif 244 245 struct platform_driver nouveau_platform_driver = { 246 .driver = { 247 .name = "nouveau", 248 .of_match_table = of_match_ptr(nouveau_platform_match), 249 }, 250 .probe = nouveau_platform_probe, 251 .remove = nouveau_platform_remove, 252 }; 253