tegra_nouveau.c revision 1.16
1/* $NetBSD: tegra_nouveau.c,v 1.16 2021/01/27 03:10:19 thorpej 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.16 2021/01/27 03:10:19 thorpej 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 device_compatible_entry compat_data[] = {
114	{ .compat = "nvidia,gk20a", .data = &gk20a_platform_data },
115	{ .compat = "nvidia,gm20b", .data = &gk20a_platform_data },
116	DEVICE_COMPAT_EOL
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_compatible_match(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 device_compatible_entry *data =
134	    of_compatible_lookup(faa->faa_phandle, compat_data);
135	const struct nvkm_device_tegra_func *tegra_func __diagused = data->data;
136	int error;
137
138	KASSERT(tegra_func != NULL);
139
140	if (!nouveau_driver_initialized) {
141		*nouveau_drm_driver_platform = *nouveau_drm_driver_stub;
142		nouveau_drm_driver_platform->set_busid =
143		    tegra_nouveau_set_busid;
144		nouveau_driver_initialized = true;
145	}
146
147	sc->sc_dev = self;
148	sc->sc_bst = faa->faa_bst;
149	sc->sc_dmat = faa->faa_dmat;
150	sc->sc_phandle = faa->faa_phandle;
151
152	sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu");
153	if (sc->sc_clk_gpu == NULL) {
154		aprint_error(": couldn't get clock gpu\n");
155		return;
156	}
157	sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr");
158	if (sc->sc_clk_pwr == NULL) {
159		aprint_error(": couldn't get clock pwr\n");
160		return;
161	}
162	sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu");
163	if (sc->sc_rst_gpu == NULL) {
164		aprint_error(": couldn't get reset gpu\n");
165		return;
166	}
167
168	aprint_naive("\n");
169	aprint_normal(": GPU\n");
170
171	prop_dictionary_get_cstring(prop, "debug", &nouveau_debug);
172	prop_dictionary_get_cstring(prop, "config", &nouveau_config);
173
174	fdtbus_reset_assert(sc->sc_rst_gpu);
175	error = clk_set_rate(sc->sc_clk_pwr, 204000000);
176	if (error) {
177		aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n",
178		    error);
179		return;
180	}
181	error = clk_enable(sc->sc_clk_pwr);
182	if (error) {
183		aprint_error_dev(self, "couldn't enable clock pwr: %d\n",
184		    error);
185		return;
186	}
187	error = clk_enable(sc->sc_clk_gpu);
188	if (error) {
189		aprint_error_dev(self, "couldn't enable clock gpu: %d\n",
190		    error);
191		return;
192	}
193	tegra_pmc_remove_clamping(PMC_PARTID_TD);
194	fdtbus_reset_deassert(sc->sc_rst_gpu);
195
196	error = -nvkm_device_ctor(&nvkm_device_tegra_func, NULL, self,
197	    NVKM_DEVICE_TEGRA, -1, device_xname(self),
198	    nouveau_config, nouveau_debug, true, true, ~0ULL, &sc->sc_nv_dev);
199	if (error) {
200		aprint_error_dev(self, "couldn't create nouveau device: %d\n",
201		    error);
202		return;
203	}
204
205	config_mountroot(self, tegra_nouveau_init);
206}
207
208static void
209tegra_nouveau_init(device_t self)
210{
211	struct tegra_nouveau_softc * const sc = device_private(self);
212	struct drm_driver * const driver = nouveau_drm_driver_platform;
213	struct drm_device *dev;
214	bus_addr_t addr[2], size[2];
215	int error;
216
217	if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 ||
218	    fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) {
219		aprint_error(": couldn't get registers\n");
220		return;
221	}
222
223	dev = drm_dev_alloc(driver, sc->sc_dev);
224	if (dev == NULL) {
225		aprint_error_dev(self, "couldn't allocate DRM device\n");
226		return;
227	}
228	dev->bst = sc->sc_bst;
229	dev->bus_dmat = sc->sc_dmat;
230	dev->dmat = dev->bus_dmat;
231	dev->dmat_subregion_p = false;
232
233	sc->sc_resources[0].addr = addr[0];
234	sc->sc_resources[0].size = size[0];
235	sc->sc_resources[1].addr = addr[1];
236	sc->sc_resources[1].size = size[1];
237
238	error = -drm_dev_register(dev, 0);
239	if (error) {
240		drm_dev_unref(dev);
241		aprint_error_dev(self, "couldn't register DRM device: %d\n",
242		    error);
243		return;
244	}
245
246	aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n",
247	    driver->name, driver->major, driver->minor, driver->patchlevel,
248	    driver->date, dev->primary->index);
249}
250
251static int
252tegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master)
253{
254	int id = 0;		/* XXX device_unit(self)? */
255
256	master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id);
257	if (master->unique == NULL)
258		return -ENOMEM;
259	master->unique_len = strlen(master->unique);
260
261	return 0;
262}
263
264static int
265tegra_nouveau_intr(void *cookie)
266{
267	struct tegra_nouveau_softc *sc = cookie;
268	struct nvkm_mc *mc = sc->sc_nv_dev.mc;
269	bool handled = false;
270
271	if (__predict_true(mc)) {
272		nvkm_mc_intr_unarm(mc);
273		nvkm_mc_intr(mc, &handled);
274		nvkm_mc_intr_rearm(mc);
275	}
276
277	return handled;
278}
279
280static int
281nvkm_device_tegra_init(struct nvkm_device *nvdev)
282{
283	struct tegra_nouveau_softc *sc =
284	    container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev);
285	device_t self = sc->sc_dev;
286	char intrstr[128];
287
288	if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) {
289		aprint_error_dev(self, "failed to decode interrupt\n");
290		return -EIO;
291	}
292
293	sc->sc_ih = fdtbus_intr_establish_xname(sc->sc_phandle, 0, IPL_VM,
294	    FDT_INTR_MPSAFE, tegra_nouveau_intr, sc, device_xname(self));
295	if (sc->sc_ih == NULL) {
296		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
297		    intrstr);
298		return -EIO;
299	}
300
301	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
302	return 0;
303}
304
305static void
306nvkm_device_tegra_fini(struct nvkm_device *nvdev, bool suspend)
307{
308	struct tegra_nouveau_softc *sc =
309	    container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev);
310
311	fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih);
312}
313
314static bus_space_tag_t
315nvkm_device_tegra_resource_tag(struct nvkm_device *dev, unsigned bar)
316{
317	struct tegra_nouveau_softc *sc =
318	    container_of(dev, struct tegra_nouveau_softc, sc_nv_dev);
319
320	KASSERT(bar < 2);
321	return sc->sc_bst;
322}
323
324static bus_addr_t
325nvkm_device_tegra_resource_addr(struct nvkm_device *dev, unsigned bar)
326{
327	struct tegra_nouveau_softc *sc =
328	    container_of(dev, struct tegra_nouveau_softc, sc_nv_dev);
329
330	KASSERT(bar < 2);
331	return sc->sc_resources[bar].addr;
332}
333
334static bus_size_t
335nvkm_device_tegra_resource_size(struct nvkm_device *dev, unsigned bar)
336{
337	struct tegra_nouveau_softc *sc =
338	    container_of(dev, struct tegra_nouveau_softc, sc_nv_dev);
339
340	KASSERT(bar < 2);
341	return sc->sc_resources[bar].size;
342}
343