xref: /netbsd-src/sys/external/bsd/drm2/via/via_pci.c (revision c185307488bbf6fc561ecae5b867f82bd8fc67eb)
1*c1853074Sriastradh /*	$NetBSD: via_pci.c,v 1.7 2021/12/19 12:30:23 riastradh Exp $	*/
2a72b8c43Sriastradh 
3a72b8c43Sriastradh /*-
4a72b8c43Sriastradh  * Copyright (c) 2015 The NetBSD Foundation, Inc.
5a72b8c43Sriastradh  * All rights reserved.
6a72b8c43Sriastradh  *
7a72b8c43Sriastradh  * This code is derived from software contributed to The NetBSD Foundation
8a72b8c43Sriastradh  * by Taylor R. Campbell.
9a72b8c43Sriastradh  *
10a72b8c43Sriastradh  * Redistribution and use in source and binary forms, with or without
11a72b8c43Sriastradh  * modification, are permitted provided that the following conditions
12a72b8c43Sriastradh  * are met:
13a72b8c43Sriastradh  * 1. Redistributions of source code must retain the above copyright
14a72b8c43Sriastradh  *    notice, this list of conditions and the following disclaimer.
15a72b8c43Sriastradh  * 2. Redistributions in binary form must reproduce the above copyright
16a72b8c43Sriastradh  *    notice, this list of conditions and the following disclaimer in the
17a72b8c43Sriastradh  *    documentation and/or other materials provided with the distribution.
18a72b8c43Sriastradh  *
19a72b8c43Sriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20a72b8c43Sriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21a72b8c43Sriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22a72b8c43Sriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23a72b8c43Sriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24a72b8c43Sriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25a72b8c43Sriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26a72b8c43Sriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27a72b8c43Sriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28a72b8c43Sriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29a72b8c43Sriastradh  * POSSIBILITY OF SUCH DAMAGE.
30a72b8c43Sriastradh  */
31a72b8c43Sriastradh 
32a72b8c43Sriastradh #include <sys/cdefs.h>
33*c1853074Sriastradh __KERNEL_RCSID(0, "$NetBSD: via_pci.c,v 1.7 2021/12/19 12:30:23 riastradh Exp $");
34a72b8c43Sriastradh 
35a72b8c43Sriastradh #include <sys/types.h>
36a72b8c43Sriastradh #include <sys/device.h>
37328fc440Sriastradh #include <sys/pmf.h>
38a72b8c43Sriastradh #include <sys/systm.h>
39a72b8c43Sriastradh 
40a72b8c43Sriastradh #include <linux/pci.h>
41a72b8c43Sriastradh 
42*c1853074Sriastradh #include <drm/drm_device.h>
43*c1853074Sriastradh #include <drm/drm_drv.h>
44*c1853074Sriastradh #include <drm/drm_pci.h>
45a72b8c43Sriastradh #include <drm/drm_pciids.h>
46a72b8c43Sriastradh #include <drm/via_drm.h>
47a72b8c43Sriastradh 
48a72b8c43Sriastradh #include "via_drv.h"
49a72b8c43Sriastradh 
50f21b21b0Sriastradh struct drm_device;
51f21b21b0Sriastradh 
52a72b8c43Sriastradh struct viadrm_softc {
53a72b8c43Sriastradh 	device_t		sc_dev;
54a72b8c43Sriastradh 	struct pci_dev		sc_pci_dev;
55a72b8c43Sriastradh 	struct drm_device	*sc_drm_dev;
56*c1853074Sriastradh 	bool			sc_pci_attached;
57*c1853074Sriastradh 	bool			sc_dev_registered;
58a72b8c43Sriastradh };
59a72b8c43Sriastradh 
60a72b8c43Sriastradh static int	viadrm_match(device_t, cfdata_t, void *);
61a72b8c43Sriastradh static void	viadrm_attach(device_t, device_t, void *);
62a72b8c43Sriastradh static int	viadrm_detach(device_t, int);
63a72b8c43Sriastradh 
64a72b8c43Sriastradh extern struct drm_driver *const via_drm_driver; /* XXX */
65a72b8c43Sriastradh 
66a72b8c43Sriastradh CFATTACH_DECL_NEW(viadrmums, sizeof(struct viadrm_softc),
67a72b8c43Sriastradh     viadrm_match, viadrm_attach, viadrm_detach, NULL);
68a72b8c43Sriastradh 
69a72b8c43Sriastradh static const struct pci_device_id viadrm_pci_ids[] = {
70a72b8c43Sriastradh 	viadrv_PCI_IDS
71a72b8c43Sriastradh };
72a72b8c43Sriastradh 
73a72b8c43Sriastradh static const unsigned long *
viadrm_lookup(const struct pci_attach_args * pa)74a72b8c43Sriastradh viadrm_lookup(const struct pci_attach_args *pa)
75a72b8c43Sriastradh {
76a72b8c43Sriastradh 	unsigned i;
77a72b8c43Sriastradh 
78a72b8c43Sriastradh 	for (i = 0; i < __arraycount(viadrm_pci_ids); i++) {
790a524044Sriastradh 		if (viadrm_pci_ids[i].vendor == 0 &&
800a524044Sriastradh 		    viadrm_pci_ids[i].device == 0)
810a524044Sriastradh 			break;
82a72b8c43Sriastradh 		KASSERT(viadrm_pci_ids[i].subvendor == PCI_ANY_ID);
83a72b8c43Sriastradh 		KASSERT(viadrm_pci_ids[i].subdevice == PCI_ANY_ID);
84a72b8c43Sriastradh 		KASSERT(viadrm_pci_ids[i].class == 0);
85a72b8c43Sriastradh 		KASSERT(viadrm_pci_ids[i].class_mask == 0);
86a72b8c43Sriastradh 		if (PCI_VENDOR(pa->pa_id) != viadrm_pci_ids[i].vendor)
87a72b8c43Sriastradh 			continue;
88a72b8c43Sriastradh 		if (PCI_PRODUCT(pa->pa_id) != viadrm_pci_ids[i].device)
89a72b8c43Sriastradh 			continue;
90a72b8c43Sriastradh 		return &viadrm_pci_ids[i].driver_data;
91a72b8c43Sriastradh 	}
92a72b8c43Sriastradh 
93a72b8c43Sriastradh 	return NULL;
94a72b8c43Sriastradh }
95a72b8c43Sriastradh 
96a72b8c43Sriastradh static int
viadrm_match(device_t parent,cfdata_t match,void * aux)97a72b8c43Sriastradh viadrm_match(device_t parent, cfdata_t match, void *aux)
98a72b8c43Sriastradh {
99a72b8c43Sriastradh 	extern int viadrm_guarantee_initialized(void);
100a72b8c43Sriastradh 	const struct pci_attach_args *const pa = aux;
101a72b8c43Sriastradh 	int error;
102a72b8c43Sriastradh 
103a72b8c43Sriastradh 	error = viadrm_guarantee_initialized();
104a72b8c43Sriastradh 	if (error) {
105a72b8c43Sriastradh 		aprint_error("viadrm: failed to initialize: %d\n", error);
106a72b8c43Sriastradh 		return 0;
107a72b8c43Sriastradh 	}
108a72b8c43Sriastradh 
109a72b8c43Sriastradh 	if (viadrm_lookup(pa) == NULL)
110a72b8c43Sriastradh 		return 0;
111a72b8c43Sriastradh 
112a72b8c43Sriastradh 	return 1;
113a72b8c43Sriastradh }
114a72b8c43Sriastradh 
115a72b8c43Sriastradh static void
viadrm_attach(device_t parent,device_t self,void * aux)116a72b8c43Sriastradh viadrm_attach(device_t parent, device_t self, void *aux)
117a72b8c43Sriastradh {
118a72b8c43Sriastradh 	struct viadrm_softc *const sc = device_private(self);
119a72b8c43Sriastradh 	const struct pci_attach_args *const pa = aux;
120a72b8c43Sriastradh 	const unsigned long *const cookiep = viadrm_lookup(pa);
121a72b8c43Sriastradh 	int error;
122a72b8c43Sriastradh 
123a72b8c43Sriastradh 	KASSERT(cookiep != NULL);
124a72b8c43Sriastradh 
1254cbe52e5Sjakllsch 	aprint_naive("\n");
1264cbe52e5Sjakllsch 	aprint_normal("\n");
1274cbe52e5Sjakllsch 
12891081e8eSriastradh 	/* Initialize the Linux PCI device descriptor.  */
12991081e8eSriastradh 	linux_pci_dev_init(&sc->sc_pci_dev, self, device_parent(self), pa, 0);
13091081e8eSriastradh 
131*c1853074Sriastradh 	sc->sc_drm_dev = drm_dev_alloc(via_drm_driver, self);
132*c1853074Sriastradh 	if (IS_ERR(sc->sc_drm_dev)) {
133*c1853074Sriastradh 		aprint_error_dev(self, "unable to create drm device: %ld\n",
134*c1853074Sriastradh 		    PTR_ERR(sc->sc_drm_dev));
135*c1853074Sriastradh 		sc->sc_drm_dev = NULL;
136*c1853074Sriastradh 		return;
137*c1853074Sriastradh 	}
138*c1853074Sriastradh 
139a72b8c43Sriastradh 	/* XXX errno Linux->NetBSD */
140*c1853074Sriastradh 	error = -drm_pci_attach(sc->sc_drm_dev, &sc->sc_pci_dev);
141a72b8c43Sriastradh 	if (error) {
142a72b8c43Sriastradh 		aprint_error_dev(self, "unable to attach drm: %d\n", error);
143a72b8c43Sriastradh 		return;
144a72b8c43Sriastradh 	}
145*c1853074Sriastradh 	sc->sc_pci_attached = true;
146*c1853074Sriastradh 
147*c1853074Sriastradh 	/* XXX errno Linux->NetBSD */
148*c1853074Sriastradh 	error = -drm_dev_register(sc->sc_drm_dev, *cookiep);
149*c1853074Sriastradh 	if (error) {
150*c1853074Sriastradh 		aprint_error_dev(self, "unable to register drm: %d\n", error);
151*c1853074Sriastradh 		return;
152*c1853074Sriastradh 	}
153*c1853074Sriastradh 	sc->sc_dev_registered = true;
154*c1853074Sriastradh 
155*c1853074Sriastradh 	if (!pmf_device_register(self, NULL, NULL))
156*c1853074Sriastradh 		aprint_error_dev(self, "couldn't establish power handler\n");
157a72b8c43Sriastradh }
158a72b8c43Sriastradh 
159a72b8c43Sriastradh static int
viadrm_detach(device_t self,int flags)160a72b8c43Sriastradh viadrm_detach(device_t self, int flags)
161a72b8c43Sriastradh {
162a72b8c43Sriastradh 	struct viadrm_softc *const sc = device_private(self);
163a72b8c43Sriastradh 	int error;
164a72b8c43Sriastradh 
165a72b8c43Sriastradh 	error = config_detach_children(self, flags);
166a72b8c43Sriastradh 	if (error)
167a72b8c43Sriastradh 		return error;
16891081e8eSriastradh 
169328fc440Sriastradh 	pmf_device_deregister(self);
170*c1853074Sriastradh 	if (sc->sc_dev_registered) {
171*c1853074Sriastradh 		drm_dev_unregister(sc->sc_drm_dev);
172*c1853074Sriastradh 		sc->sc_dev_registered = false;
173*c1853074Sriastradh 	}
174*c1853074Sriastradh 	if (sc->sc_pci_attached) {
175*c1853074Sriastradh 		drm_pci_detach(sc->sc_drm_dev);
176*c1853074Sriastradh 		sc->sc_pci_attached = false;
177*c1853074Sriastradh 	}
178*c1853074Sriastradh 	if (sc->sc_drm_dev) {
179*c1853074Sriastradh 		drm_dev_put(sc->sc_drm_dev);
180*c1853074Sriastradh 		sc->sc_drm_dev = NULL;
181*c1853074Sriastradh 	}
182*c1853074Sriastradh 	linux_pci_dev_destroy(&sc->sc_pci_dev);
183*c1853074Sriastradh 
18491081e8eSriastradh 	return 0;
185a72b8c43Sriastradh }
186