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