brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · d1c294f Raw
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