tegra_nouveau.c revision 1.13
1/* $NetBSD: tegra_nouveau.c,v 1.13 2021/01/15 23:11:59 jmcneill Exp $ */
2
3/*-
4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.13 2021/01/15 23:11:59 jmcneill Exp $");
31
32#include <sys/param.h>
33#include <sys/bus.h>
34#include <sys/device.h>
35#include <sys/intr.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39
40#include <arm/nvidia/tegra_reg.h>
41#include <arm/nvidia/tegra_pmcreg.h>
42#include <arm/nvidia/tegra_var.h>
43#include <arm/nvidia/tegra_intr.h>
44
45#include <dev/fdt/fdtvar.h>
46
47#include <drm/drmP.h>
48#include <core/tegra.h>
49#include <nvkm/engine/device/priv.h>
50#include <nvkm/subdev/mc/priv.h>
51
52extern char *nouveau_config;
53extern char *nouveau_debug;
54extern struct drm_driver *const nouveau_drm_driver_stub;     /* XXX */
55extern struct drm_driver *const nouveau_drm_driver_platform; /* XXX */
56static bool nouveau_driver_initialized = false;		     /* XXX */
57
58static int	tegra_nouveau_match(device_t, cfdata_t, void *);
59static void	tegra_nouveau_attach(device_t, device_t, void *);
60
61struct tegra_nouveau_softc {
62	device_t		sc_dev;
63	bus_space_tag_t		sc_bst;
64	struct {
65		bus_addr_t		addr;
66		bus_size_t		size;
67	}			sc_resources[2];
68	bus_dma_tag_t		sc_dmat;
69	int			sc_phandle;
70	void			*sc_ih;
71	struct clk		*sc_clk_gpu;
72	struct clk		*sc_clk_pwr;
73	struct fdtbus_reset	*sc_rst_gpu;
74	struct drm_device	*sc_drm_dev;
75	struct nvkm_device	sc_nv_dev;
76};
77
78static void	tegra_nouveau_init(device_t);
79
80static int	tegra_nouveau_set_busid(struct drm_device *,
81					struct drm_master *);
82
83static int	tegra_nouveau_intr(void *);
84
85static int	nvkm_device_tegra_init(struct nvkm_device *);
86static void	nvkm_device_tegra_fini(struct nvkm_device *, bool);
87
88static bus_space_tag_t
89		nvkm_device_tegra_resource_tag(struct nvkm_device *, unsigned);
90static bus_addr_t
91		nvkm_device_tegra_resource_addr(struct nvkm_device *, unsigned);
92static bus_size_t
93		nvkm_device_tegra_resource_size(struct nvkm_device *, unsigned);
94
95CFATTACH_DECL_NEW(tegra_nouveau, sizeof(struct tegra_nouveau_softc),
96	tegra_nouveau_match, tegra_nouveau_attach, NULL, NULL);
97
98static const struct nvkm_device_func nvkm_device_tegra_func = {
99	.tegra = NULL,		/* XXX */
100	.dtor = NULL,
101	.init = nvkm_device_tegra_init,
102	.fini = nvkm_device_tegra_fini,
103	.resource_tag = nvkm_device_tegra_resource_tag,
104	.resource_addr = nvkm_device_tegra_resource_addr,
105	.resource_size = nvkm_device_tegra_resource_size,
106	.cpu_coherent = false,
107};
108
109static const struct nvkm_device_tegra_func gk20a_platform_data = {
110	.iommu_bit = 34,
111};
112
113static const struct of_compat_data compat_data[] = {
114	{ "nvidia,gk20a", (uintptr_t)&gk20a_platform_data },
115	{ "nvidia,gm20b", (uintptr_t)&gk20a_platform_data },
116	{ NULL, 0 },
117};
118
119static int
120tegra_nouveau_match(device_t parent, cfdata_t cf, void *aux)
121{
122	struct fdt_attach_args * const faa = aux;
123
124	return of_match_compat_data(faa->faa_phandle, compat_data);
125}
126
127static void
128tegra_nouveau_attach(device_t parent, device_t self, void *aux)
129{
130	struct tegra_nouveau_softc * const sc = device_private(self);
131	struct fdt_attach_args * const faa = aux;
132	prop_dictionary_t prop = device_properties(self);
133	const struct of_compat_data *data =
134	    of_search_compatible(faa->faa_phandle, compat_data);
135	const struct nvkm_device_tegra_func *tegra_func __diagused =
136	    (const void *)data->data;
137	int error;
138
139	KASSERT(tegra_func != NULL);
140
141	if (!nouveau_driver_initialized) {
142		*nouveau_drm_driver_platform = *nouveau_drm_driver_stub;
143		nouveau_drm_driver_platform->set_busid =
144		    tegra_nouveau_set_busid;
145		nouveau_driver_initialized = true;
146	}
147
148	sc->sc_dev = self;
149	sc->sc_bst = faa->faa_bst;
150	sc->sc_dmat = faa->faa_dmat;
151	sc->sc_phandle = faa->faa_phandle;
152
153	sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu");
154	if (sc->sc_clk_gpu == NULL) {
155		aprint_error(": couldn't get clock gpu\n");
156		return;
157	}
158	sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr");
159	if (sc->sc_clk_pwr == NULL) {
160		aprint_error(": couldn't get clock pwr\n");
161		return;
162	}
163	sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu");
164	if (sc->sc_rst_gpu == NULL) {
165		aprint_error(": couldn't get reset gpu\n");
166		return;
167	}
168
169	aprint_naive("\n");
170	aprint_normal(": GPU\n");
171
172	prop_dictionary_get_cstring(prop, "debug", &nouveau_debug);
173	prop_dictionary_get_cstring(prop, "config", &nouveau_config);
174
175	fdtbus_reset_assert(sc->sc_rst_gpu);
176	error = clk_set_rate(sc->sc_clk_pwr, 204000000);
177	if (error) {
178		aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n",
179		    error);
180		return;
181	}
182	error = clk_enable(sc->sc_clk_pwr);
183	if (error) {
184		aprint_error_dev(self, "couldn't enable clock pwr: %d\n",
185		    error);
186		return;
187	}
188	error = clk_enable(sc->sc_clk_gpu);
189	if (error) {
190		aprint_error_dev(self, "couldn't enable clock gpu: %d\n",
191		    error);
192		return;
193	}
194	tegra_pmc_remove_clamping(PMC_PARTID_TD);
195	fdtbus_reset_deassert(sc->sc_rst_gpu);
196
197	error = -nvkm_device_ctor(&nvkm_device_tegra_func, NULL, self,
198	    NVKM_DEVICE_TEGRA, -1, device_xname(self),
199	    nouveau_config, nouveau_debug, true, true, ~0ULL, &sc->sc_nv_dev);
200	if (error) {
201		aprint_error_dev(self, "couldn't create nouveau device: %d\n",
202		    error);
203		return;
204	}
205
206	config_mountroot(self, tegra_nouveau_init);
207}
208
209static void
210tegra_nouveau_init(device_t self)
211{
212	struct tegra_nouveau_softc * const sc = device_private(self);
213	struct drm_driver * const driver = nouveau_drm_driver_platform;
214	struct drm_device *dev;
215	bus_addr_t addr[2], size[2];
216	int error;
217
218	if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 ||
219	    fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) {
220		aprint_error(": couldn't get registers\n");
221		return;
222	}
223
224	dev = drm_dev_alloc(driver, sc->sc_dev);
225	if (dev == NULL) {
226		aprint_error_dev(self, "couldn't allocate DRM device\n");
227		return;
228	}
229	dev->bst = sc->sc_bst;
230	dev->bus_dmat = sc->sc_dmat;
231	dev->dmat = dev->bus_dmat;
232	dev->dmat_subregion_p = false;
233
234	sc->sc_resources[0].addr = addr[0];
235	sc->sc_resources[0].size = size[0];
236	sc->sc_resources[1].addr = addr[1];
237	sc->sc_resources[1].size = size[1];
238
239	error = -drm_dev_register(dev, 0);
240	if (error) {
241		drm_dev_unref(dev);
242		aprint_error_dev(self, "couldn't register DRM device: %d\n",
243		    error);
244		return;
245	}
246
247	aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n",
248	    driver->name, driver->major, driver->minor, driver->patchlevel,
249	    driver->date, dev->primary->index);
250}
251
252static int
253tegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master)
254{
255	int id = 0;		/* XXX device_unit(self)? */
256
257	master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id);
258	if (master->unique == NULL)
259		return -ENOMEM;
260	master->unique_len = strlen(master->unique);
261
262	return 0;
263}
264
265static int
266tegra_nouveau_intr(void *cookie)
267{
268	struct tegra_nouveau_softc *sc = cookie;
269	struct nvkm_mc *mc = sc->sc_nv_dev.mc;
270	bool handled = false;
271
272	if (__predict_true(mc)) {
273		nvkm_mc_intr_unarm(mc);
274		nvkm_mc_intr(mc, &handled);
275		nvkm_mc_intr_rearm(mc);
276	}
277
278	return handled;
279}
280
281static int
282nvkm_device_tegra_init(struct nvkm_device *nvdev)
283{
284	struct tegra_nouveau_softc *sc =
285	    container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev);
286	device_t self = sc->sc_dev;
287	char intrstr[128];
288
289	if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) {
290		aprint_error_dev(self, "failed to decode interrupt\n");
291		return -EIO;
292	}
293
294	sc->sc_ih = fdtbus_intr_establish_xname(sc->sc_phandle, 0, IPL_VM,
295	    FDT_INTR_MPSAFE, tegra_nouveau_intr, sc, device_xname(self));
296	if (sc->sc_ih == NULL) {
297		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
298		    intrstr);
299		return -EIO;
300	}
301
302	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
303	return 0;
304}
305
306static void
307nvkm_device_tegra_fini(struct nvkm_device *nvdev, bool suspend)
308{
309	struct tegra_nouveau_softc *sc =
310	    container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev);
311
312	fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih);
313}
314
315static bus_space_tag_t
316nvkm_device_tegra_resource_tag(struct nvkm_device *dev, unsigned bar)
317{
318	struct tegra_nouveau_softc *sc =
319	    container_of(dev, struct tegra_nouveau_softc, sc_nv_dev);
320
321	KASSERT(bar < 2);
322	return sc->sc_bst;
323}
324
325static bus_addr_t
326nvkm_device_tegra_resource_addr(struct nvkm_device *dev, unsigned bar)
327{
328	struct tegra_nouveau_softc *sc =
329	    container_of(dev, struct tegra_nouveau_softc, sc_nv_dev);
330
331	KASSERT(bar < 2);
332	return sc->sc_resources[bar].addr;
333}
334
335static bus_size_t
336nvkm_device_tegra_resource_size(struct nvkm_device *dev, unsigned bar)
337{
338	struct tegra_nouveau_softc *sc =
339	    container_of(dev, struct tegra_nouveau_softc, sc_nv_dev);
340
341	KASSERT(bar < 2);
342	return sc->sc_resources[bar].size;
343}
344