339 lines · c
1/*2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20 * DEALINGS IN THE SOFTWARE.21 */22#include <core/tegra.h>23#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER24#include "priv.h"25 26#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)27#include <asm/dma-iommu.h>28#endif29 30static int31nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev)32{33 int ret;34 35 if (tdev->vdd) {36 ret = regulator_enable(tdev->vdd);37 if (ret)38 goto err_power;39 }40 41 ret = clk_prepare_enable(tdev->clk);42 if (ret)43 goto err_clk;44 ret = clk_prepare_enable(tdev->clk_ref);45 if (ret)46 goto err_clk_ref;47 ret = clk_prepare_enable(tdev->clk_pwr);48 if (ret)49 goto err_clk_pwr;50 clk_set_rate(tdev->clk_pwr, 204000000);51 udelay(10);52 53 if (!tdev->pdev->dev.pm_domain) {54 reset_control_assert(tdev->rst);55 udelay(10);56 57 ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D);58 if (ret)59 goto err_clamp;60 udelay(10);61 62 reset_control_deassert(tdev->rst);63 udelay(10);64 }65 66 return 0;67 68err_clamp:69 clk_disable_unprepare(tdev->clk_pwr);70err_clk_pwr:71 clk_disable_unprepare(tdev->clk_ref);72err_clk_ref:73 clk_disable_unprepare(tdev->clk);74err_clk:75 if (tdev->vdd)76 regulator_disable(tdev->vdd);77err_power:78 return ret;79}80 81static int82nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev)83{84 int ret;85 86 clk_disable_unprepare(tdev->clk_pwr);87 clk_disable_unprepare(tdev->clk_ref);88 clk_disable_unprepare(tdev->clk);89 udelay(10);90 91 if (tdev->vdd) {92 ret = regulator_disable(tdev->vdd);93 if (ret)94 return ret;95 }96 97 return 0;98}99 100static void101nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev)102{103#if IS_ENABLED(CONFIG_IOMMU_API)104 struct device *dev = &tdev->pdev->dev;105 unsigned long pgsize_bitmap;106 int ret;107 108#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)109 if (dev->archdata.mapping) {110 struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);111 112 arm_iommu_detach_device(dev);113 arm_iommu_release_mapping(mapping);114 }115#endif116 117 if (!tdev->func->iommu_bit)118 return;119 120 mutex_init(&tdev->iommu.mutex);121 122 if (device_iommu_mapped(dev)) {123 tdev->iommu.domain = iommu_domain_alloc(&platform_bus_type);124 if (!tdev->iommu.domain)125 goto error;126 127 /*128 * A IOMMU is only usable if it supports page sizes smaller129 * or equal to the system's PAGE_SIZE, with a preference if130 * both are equal.131 */132 pgsize_bitmap = tdev->iommu.domain->pgsize_bitmap;133 if (pgsize_bitmap & PAGE_SIZE) {134 tdev->iommu.pgshift = PAGE_SHIFT;135 } else {136 tdev->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK);137 if (tdev->iommu.pgshift == 0) {138 dev_warn(dev, "unsupported IOMMU page size\n");139 goto free_domain;140 }141 tdev->iommu.pgshift -= 1;142 }143 144 ret = iommu_attach_device(tdev->iommu.domain, dev);145 if (ret)146 goto free_domain;147 148 ret = nvkm_mm_init(&tdev->iommu.mm, 0, 0,149 (1ULL << tdev->func->iommu_bit) >>150 tdev->iommu.pgshift, 1);151 if (ret)152 goto detach_device;153 }154 155 return;156 157detach_device:158 iommu_detach_device(tdev->iommu.domain, dev);159 160free_domain:161 iommu_domain_free(tdev->iommu.domain);162 163error:164 tdev->iommu.domain = NULL;165 tdev->iommu.pgshift = 0;166 dev_err(dev, "cannot initialize IOMMU MM\n");167#endif168}169 170static void171nvkm_device_tegra_remove_iommu(struct nvkm_device_tegra *tdev)172{173#if IS_ENABLED(CONFIG_IOMMU_API)174 if (tdev->iommu.domain) {175 nvkm_mm_fini(&tdev->iommu.mm);176 iommu_detach_device(tdev->iommu.domain, tdev->device.dev);177 iommu_domain_free(tdev->iommu.domain);178 }179#endif180}181 182static struct nvkm_device_tegra *183nvkm_device_tegra(struct nvkm_device *device)184{185 return container_of(device, struct nvkm_device_tegra, device);186}187 188static struct resource *189nvkm_device_tegra_resource(struct nvkm_device *device, unsigned bar)190{191 struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);192 return platform_get_resource(tdev->pdev, IORESOURCE_MEM, bar);193}194 195static resource_size_t196nvkm_device_tegra_resource_addr(struct nvkm_device *device, unsigned bar)197{198 struct resource *res = nvkm_device_tegra_resource(device, bar);199 return res ? res->start : 0;200}201 202static resource_size_t203nvkm_device_tegra_resource_size(struct nvkm_device *device, unsigned bar)204{205 struct resource *res = nvkm_device_tegra_resource(device, bar);206 return res ? resource_size(res) : 0;207}208 209static int210nvkm_device_tegra_irq(struct nvkm_device *device)211{212 struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);213 214 return platform_get_irq_byname(tdev->pdev, "stall");215}216 217static void *218nvkm_device_tegra_dtor(struct nvkm_device *device)219{220 struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);221 nvkm_device_tegra_power_down(tdev);222 nvkm_device_tegra_remove_iommu(tdev);223 return tdev;224}225 226static const struct nvkm_device_func227nvkm_device_tegra_func = {228 .tegra = nvkm_device_tegra,229 .dtor = nvkm_device_tegra_dtor,230 .irq = nvkm_device_tegra_irq,231 .resource_addr = nvkm_device_tegra_resource_addr,232 .resource_size = nvkm_device_tegra_resource_size,233 .cpu_coherent = false,234};235 236int237nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,238 struct platform_device *pdev,239 const char *cfg, const char *dbg,240 struct nvkm_device **pdevice)241{242 struct nvkm_device_tegra *tdev;243 unsigned long rate;244 int ret;245 246 if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))247 return -ENOMEM;248 249 tdev->func = func;250 tdev->pdev = pdev;251 252 if (func->require_vdd) {253 tdev->vdd = devm_regulator_get(&pdev->dev, "vdd");254 if (IS_ERR(tdev->vdd)) {255 ret = PTR_ERR(tdev->vdd);256 goto free;257 }258 }259 260 tdev->rst = devm_reset_control_get(&pdev->dev, "gpu");261 if (IS_ERR(tdev->rst)) {262 ret = PTR_ERR(tdev->rst);263 goto free;264 }265 266 tdev->clk = devm_clk_get(&pdev->dev, "gpu");267 if (IS_ERR(tdev->clk)) {268 ret = PTR_ERR(tdev->clk);269 goto free;270 }271 272 rate = clk_get_rate(tdev->clk);273 if (rate == 0) {274 ret = clk_set_rate(tdev->clk, ULONG_MAX);275 if (ret < 0)276 goto free;277 278 rate = clk_get_rate(tdev->clk);279 280 dev_dbg(&pdev->dev, "GPU clock set to %lu\n", rate);281 }282 283 if (func->require_ref_clk)284 tdev->clk_ref = devm_clk_get(&pdev->dev, "ref");285 if (IS_ERR(tdev->clk_ref)) {286 ret = PTR_ERR(tdev->clk_ref);287 goto free;288 }289 290 tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr");291 if (IS_ERR(tdev->clk_pwr)) {292 ret = PTR_ERR(tdev->clk_pwr);293 goto free;294 }295 296 /**297 * The IOMMU bit defines the upper limit of the GPU-addressable space.298 */299 ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(tdev->func->iommu_bit));300 if (ret)301 goto free;302 303 nvkm_device_tegra_probe_iommu(tdev);304 305 ret = nvkm_device_tegra_power_up(tdev);306 if (ret)307 goto remove;308 309 tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value;310 tdev->gpu_speedo_id = tegra_sku_info.gpu_speedo_id;311 ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev,312 NVKM_DEVICE_TEGRA, pdev->id, NULL,313 cfg, dbg, &tdev->device);314 if (ret)315 goto powerdown;316 317 *pdevice = &tdev->device;318 319 return 0;320 321powerdown:322 nvkm_device_tegra_power_down(tdev);323remove:324 nvkm_device_tegra_remove_iommu(tdev);325free:326 kfree(tdev);327 return ret;328}329#else330int331nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,332 struct platform_device *pdev,333 const char *cfg, const char *dbg,334 struct nvkm_device **pdevice)335{336 return -ENOSYS;337}338#endif339