File Index
Files and directories
Sign in
FILE

tegra.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c C
  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#include <core/tegra.h>
 23#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
 24#include "priv.h"
 25
 26#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
 27#include <asm/dma-iommu.h>
 28#endif
 29
 30static int
 31nvkm_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 int
 82nvkm_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 void
101nvkm_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#endif
116
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_paging_domain_alloc(dev);
124		if (IS_ERR(tdev->iommu.domain))
125			goto error;
126
127		/*
128		 * A IOMMU is only usable if it supports page sizes smaller
129		 * or equal to the system's PAGE_SIZE, with a preference if
130		 * 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#endif
168}
169
170static void
171nvkm_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#endif
180}
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, enum nvkm_bar_id bar)
190{
191	struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
192	int idx;
193
194	switch (bar) {
195	case NVKM_BAR0_PRI: idx = 0; break;
196	case NVKM_BAR1_FB : idx = 1; break;
197	default:
198		WARN_ON(1);
199		return NULL;
200	}
201
202	return platform_get_resource(tdev->pdev, IORESOURCE_MEM, idx);
203}
204
205static resource_size_t
206nvkm_device_tegra_resource_addr(struct nvkm_device *device, enum nvkm_bar_id bar)
207{
208	struct resource *res = nvkm_device_tegra_resource(device, bar);
209	return res ? res->start : 0;
210}
211
212static resource_size_t
213nvkm_device_tegra_resource_size(struct nvkm_device *device, enum nvkm_bar_id bar)
214{
215	struct resource *res = nvkm_device_tegra_resource(device, bar);
216	return res ? resource_size(res) : 0;
217}
218
219static int
220nvkm_device_tegra_irq(struct nvkm_device *device)
221{
222	struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
223
224	return platform_get_irq_byname(tdev->pdev, "stall");
225}
226
227static void *
228nvkm_device_tegra_dtor(struct nvkm_device *device)
229{
230	struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
231	nvkm_device_tegra_power_down(tdev);
232	nvkm_device_tegra_remove_iommu(tdev);
233	return tdev;
234}
235
236static const struct nvkm_device_func
237nvkm_device_tegra_func = {
238	.tegra = nvkm_device_tegra,
239	.dtor = nvkm_device_tegra_dtor,
240	.irq = nvkm_device_tegra_irq,
241	.resource_addr = nvkm_device_tegra_resource_addr,
242	.resource_size = nvkm_device_tegra_resource_size,
243	.cpu_coherent = false,
244};
245
246int
247nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
248		      struct platform_device *pdev,
249		      const char *cfg, const char *dbg,
250		      struct nvkm_device **pdevice)
251{
252	struct nvkm_device_tegra *tdev;
253	unsigned long rate;
254	int ret;
255
256	if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))
257		return -ENOMEM;
258
259	tdev->func = func;
260	tdev->pdev = pdev;
261
262	tdev->regs = devm_platform_ioremap_resource(pdev, 0);
263	if (IS_ERR(tdev->regs))
264		return PTR_ERR(tdev->regs);
265
266	if (func->require_vdd) {
267		tdev->vdd = devm_regulator_get(&pdev->dev, "vdd");
268		if (IS_ERR(tdev->vdd)) {
269			ret = PTR_ERR(tdev->vdd);
270			goto free;
271		}
272	}
273
274	tdev->rst = devm_reset_control_get(&pdev->dev, "gpu");
275	if (IS_ERR(tdev->rst)) {
276		ret = PTR_ERR(tdev->rst);
277		goto free;
278	}
279
280	tdev->clk = devm_clk_get(&pdev->dev, "gpu");
281	if (IS_ERR(tdev->clk)) {
282		ret = PTR_ERR(tdev->clk);
283		goto free;
284	}
285
286	rate = clk_get_rate(tdev->clk);
287	if (rate == 0) {
288		ret = clk_set_rate(tdev->clk, ULONG_MAX);
289		if (ret < 0)
290			goto free;
291
292		rate = clk_get_rate(tdev->clk);
293
294		dev_dbg(&pdev->dev, "GPU clock set to %lu\n", rate);
295	}
296
297	if (func->require_ref_clk)
298		tdev->clk_ref = devm_clk_get(&pdev->dev, "ref");
299	if (IS_ERR(tdev->clk_ref)) {
300		ret = PTR_ERR(tdev->clk_ref);
301		goto free;
302	}
303
304	tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr");
305	if (IS_ERR(tdev->clk_pwr)) {
306		ret = PTR_ERR(tdev->clk_pwr);
307		goto free;
308	}
309
310	/**
311	 * The IOMMU bit defines the upper limit of the GPU-addressable space.
312	 */
313	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(tdev->func->iommu_bit));
314	if (ret)
315		goto free;
316
317	nvkm_device_tegra_probe_iommu(tdev);
318
319	ret = nvkm_device_tegra_power_up(tdev);
320	if (ret)
321		goto remove;
322
323	tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value;
324	tdev->gpu_speedo_id = tegra_sku_info.gpu_speedo_id;
325	ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev,
326			       NVKM_DEVICE_TEGRA, pdev->id, NULL,
327			       cfg, dbg, &tdev->device);
328	if (ret)
329		goto powerdown;
330
331	*pdevice = &tdev->device;
332
333	return 0;
334
335powerdown:
336	nvkm_device_tegra_power_down(tdev);
337remove:
338	nvkm_device_tegra_remove_iommu(tdev);
339free:
340	kfree(tdev);
341	return ret;
342}
343#else
344int
345nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
346		      struct platform_device *pdev,
347		      const char *cfg, const char *dbg,
348		      struct nvkm_device **pdevice)
349{
350	return -ENOSYS;
351}
352#endif
~/ Read-only file preview.