xref: /netbsd/sys/external/bsd/drm2/vmwgfx/vmwgfxfb.c (revision ee0dbf1d)
1*ee0dbf1dSriastradh /*	$NetBSD: vmwgfxfb.c,v 1.4 2022/09/25 08:21:02 riastradh Exp $	*/
2e3e4e02dSriastradh 
3e3e4e02dSriastradh /*-
4e3e4e02dSriastradh  * Copyright (c) 2022 The NetBSD Foundation, Inc.
5e3e4e02dSriastradh  * All rights reserved.
6e3e4e02dSriastradh  *
7e3e4e02dSriastradh  * Redistribution and use in source and binary forms, with or without
8e3e4e02dSriastradh  * modification, are permitted provided that the following conditions
9e3e4e02dSriastradh  * are met:
10e3e4e02dSriastradh  * 1. Redistributions of source code must retain the above copyright
11e3e4e02dSriastradh  *    notice, this list of conditions and the following disclaimer.
12e3e4e02dSriastradh  * 2. Redistributions in binary form must reproduce the above copyright
13e3e4e02dSriastradh  *    notice, this list of conditions and the following disclaimer in the
14e3e4e02dSriastradh  *    documentation and/or other materials provided with the distribution.
15e3e4e02dSriastradh  *
16e3e4e02dSriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17e3e4e02dSriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18e3e4e02dSriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19e3e4e02dSriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20e3e4e02dSriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21e3e4e02dSriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22e3e4e02dSriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23e3e4e02dSriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24e3e4e02dSriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25e3e4e02dSriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26e3e4e02dSriastradh  * POSSIBILITY OF SUCH DAMAGE.
27e3e4e02dSriastradh  */
28e3e4e02dSriastradh 
29e3e4e02dSriastradh 
30e3e4e02dSriastradh #include <sys/cdefs.h>
31*ee0dbf1dSriastradh __KERNEL_RCSID(0, "$NetBSD: vmwgfxfb.c,v 1.4 2022/09/25 08:21:02 riastradh Exp $");
32e3e4e02dSriastradh 
33e3e4e02dSriastradh #include <sys/types.h>
34e3e4e02dSriastradh #include <sys/device.h>
35e3e4e02dSriastradh 
36e3e4e02dSriastradh #include <drm/drm_fb_helper.h>
37e3e4e02dSriastradh #include <drm/drmfb.h>
38e3e4e02dSriastradh #include <drm/drmfb_pci.h>
39e3e4e02dSriastradh 
40e3e4e02dSriastradh #include "vmwgfx_drv.h"
41e3e4e02dSriastradh #include "vmwgfx_task.h"
42e3e4e02dSriastradh #include "vmwgfxfb.h"
43e3e4e02dSriastradh 
44e3e4e02dSriastradh struct vmwgfxfb_softc {
45e3e4e02dSriastradh 	struct drmfb_softc		sc_drmfb; /* XXX Must be first.  */
46e3e4e02dSriastradh 	device_t			sc_dev;
47e3e4e02dSriastradh 	struct vmwgfxfb_attach_args	sc_vfa;
48e3e4e02dSriastradh 	struct vmwgfx_task		sc_attach_task;
49e3e4e02dSriastradh 	bool				sc_attached:1;
50e3e4e02dSriastradh };
51e3e4e02dSriastradh 
52e3e4e02dSriastradh static int	vmwgfxfb_match(device_t, cfdata_t, void *);
53e3e4e02dSriastradh static void	vmwgfxfb_attach(device_t, device_t, void *);
54e3e4e02dSriastradh static int	vmwgfxfb_detach(device_t, int);
55e3e4e02dSriastradh 
56e3e4e02dSriastradh static void	vmwgfxfb_attach_task(struct vmwgfx_task *);
57e3e4e02dSriastradh 
58e3e4e02dSriastradh static paddr_t	vmwgfxfb_drmfb_mmapfb(struct drmfb_softc *, off_t, int);
59e3e4e02dSriastradh static bool	vmwgfxfb_shutdown(device_t, int);
60e3e4e02dSriastradh 
61e3e4e02dSriastradh CFATTACH_DECL_NEW(vmwgfxfb, sizeof(struct vmwgfxfb_softc),
62e3e4e02dSriastradh     vmwgfxfb_match, vmwgfxfb_attach, vmwgfxfb_detach, NULL);
63e3e4e02dSriastradh 
64e3e4e02dSriastradh static const struct drmfb_params vmwgfxfb_drmfb_params = {
65e3e4e02dSriastradh 	.dp_mmapfb = vmwgfxfb_drmfb_mmapfb,
66e3e4e02dSriastradh 	.dp_mmap = drmfb_pci_mmap,
67e3e4e02dSriastradh 	.dp_ioctl = drmfb_pci_ioctl,
68e3e4e02dSriastradh 	.dp_is_vga_console = drmfb_pci_is_vga_console,
69e3e4e02dSriastradh };
70e3e4e02dSriastradh 
71e3e4e02dSriastradh static int
vmwgfxfb_match(device_t parent,cfdata_t match,void * aux)72e3e4e02dSriastradh vmwgfxfb_match(device_t parent, cfdata_t match, void *aux)
73e3e4e02dSriastradh {
74e3e4e02dSriastradh 
75e3e4e02dSriastradh 	return 1;
76e3e4e02dSriastradh }
77e3e4e02dSriastradh 
78e3e4e02dSriastradh static void
vmwgfxfb_attach(device_t parent,device_t self,void * aux)79e3e4e02dSriastradh vmwgfxfb_attach(device_t parent, device_t self, void *aux)
80e3e4e02dSriastradh {
81e3e4e02dSriastradh 	struct vmwgfxfb_softc *const sc = device_private(self);
82e3e4e02dSriastradh 	const struct vmwgfxfb_attach_args *const vfa = aux;
83e3e4e02dSriastradh 
84e3e4e02dSriastradh 	sc->sc_dev = self;
85e3e4e02dSriastradh 	sc->sc_vfa = *vfa;
86e3e4e02dSriastradh 	sc->sc_attached = false;
87e3e4e02dSriastradh 
88e3e4e02dSriastradh 	aprint_naive("\n");
89e3e4e02dSriastradh 	aprint_normal("\n");
90e3e4e02dSriastradh 
91e3e4e02dSriastradh 	vmwgfx_task_init(&sc->sc_attach_task, &vmwgfxfb_attach_task);
92cbb10065Sriastradh 	vmwgfx_task_schedule(parent, &sc->sc_attach_task);
93a2de06e8Sriastradh 	config_pending_incr(self);
94e3e4e02dSriastradh }
95e3e4e02dSriastradh 
96e3e4e02dSriastradh static int
vmwgfxfb_detach(device_t self,int flags)97e3e4e02dSriastradh vmwgfxfb_detach(device_t self, int flags)
98e3e4e02dSriastradh {
99e3e4e02dSriastradh 	struct vmwgfxfb_softc *const sc = device_private(self);
100e3e4e02dSriastradh 	int error;
101e3e4e02dSriastradh 
102e3e4e02dSriastradh 	if (sc->sc_attached) {
103e3e4e02dSriastradh 		pmf_device_deregister(self);
104e3e4e02dSriastradh 		error = drmfb_detach(&sc->sc_drmfb, flags);
105e3e4e02dSriastradh 		if (error) {
106e3e4e02dSriastradh 			/* XXX Ugh.  */
107e3e4e02dSriastradh 			(void)pmf_device_register1(self, NULL, NULL,
108e3e4e02dSriastradh 			    &vmwgfxfb_shutdown);
109e3e4e02dSriastradh 			return error;
110e3e4e02dSriastradh 		}
111e3e4e02dSriastradh 		sc->sc_attached = false;
112e3e4e02dSriastradh 	}
113e3e4e02dSriastradh 
114e3e4e02dSriastradh 	return 0;
115e3e4e02dSriastradh }
116e3e4e02dSriastradh 
117e3e4e02dSriastradh static void
vmwgfxfb_attach_task(struct vmwgfx_task * task)118e3e4e02dSriastradh vmwgfxfb_attach_task(struct vmwgfx_task *task)
119e3e4e02dSriastradh {
120e3e4e02dSriastradh 	struct vmwgfxfb_softc *const sc = container_of(task,
121e3e4e02dSriastradh 	    struct vmwgfxfb_softc, sc_attach_task);
122e3e4e02dSriastradh 	const struct vmwgfxfb_attach_args *const vfa = &sc->sc_vfa;
123e3e4e02dSriastradh 	const struct drmfb_attach_args da = {
124e3e4e02dSriastradh 		.da_dev = sc->sc_dev,
125e3e4e02dSriastradh 		.da_fb_helper = vfa->vfa_fb_helper,
126e3e4e02dSriastradh 		.da_fb_sizes = &vfa->vfa_fb_sizes,
127e3e4e02dSriastradh 		.da_fb_vaddr = __UNVOLATILE(vfa->vfa_fb_ptr),
128e3e4e02dSriastradh 		.da_fb_linebytes = vfa->vfa_fb_linebytes,
129e3e4e02dSriastradh 		.da_params = &vmwgfxfb_drmfb_params,
130e3e4e02dSriastradh 	};
131e3e4e02dSriastradh 	int error;
132e3e4e02dSriastradh 
133e3e4e02dSriastradh 	error = drmfb_attach(&sc->sc_drmfb, &da);
134e3e4e02dSriastradh 	if (error) {
135e3e4e02dSriastradh 		aprint_error_dev(sc->sc_dev, "failed to attach drmfb: %d\n",
136e3e4e02dSriastradh 		    error);
137a2de06e8Sriastradh 		goto out;
138e3e4e02dSriastradh 	}
139e3e4e02dSriastradh 	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, &vmwgfxfb_shutdown))
140e3e4e02dSriastradh 		aprint_error_dev(sc->sc_dev,
141e3e4e02dSriastradh 		    "failed to register shutdown handler\n");
142e3e4e02dSriastradh 
143e3e4e02dSriastradh 	sc->sc_attached = true;
144a2de06e8Sriastradh out:
145a2de06e8Sriastradh 	config_pending_decr(sc->sc_dev);
146e3e4e02dSriastradh }
147e3e4e02dSriastradh 
148e3e4e02dSriastradh static bool
vmwgfxfb_shutdown(device_t self,int flags)149e3e4e02dSriastradh vmwgfxfb_shutdown(device_t self, int flags)
150e3e4e02dSriastradh {
151e3e4e02dSriastradh 	struct vmwgfxfb_softc *const sc = device_private(self);
152e3e4e02dSriastradh 
153e3e4e02dSriastradh 	return drmfb_shutdown(&sc->sc_drmfb, flags);
154e3e4e02dSriastradh }
155e3e4e02dSriastradh 
156e3e4e02dSriastradh static paddr_t
vmwgfxfb_drmfb_mmapfb(struct drmfb_softc * drmfb,off_t offset,int prot)157e3e4e02dSriastradh vmwgfxfb_drmfb_mmapfb(struct drmfb_softc *drmfb, off_t offset, int prot)
158e3e4e02dSriastradh {
159e3e4e02dSriastradh 	struct vmwgfxfb_softc *const sc = container_of(drmfb,
160e3e4e02dSriastradh 	    struct vmwgfxfb_softc, sc_drmfb);
161e3e4e02dSriastradh 	struct drm_fb_helper *const helper = sc->sc_vfa.vfa_fb_helper;
162e3e4e02dSriastradh 	struct drm_framebuffer *const fb = helper->fb;
163e3e4e02dSriastradh 	struct vmw_buffer_object *const vbo = /*XXX MAGIC HERE*/;
164e3e4e02dSriastradh 	int flags = 0;
165e3e4e02dSriastradh 
166e3e4e02dSriastradh 	if (offset < 0)
167e3e4e02dSriastradh 		return -1;
168e3e4e02dSriastradh 
169e3e4e02dSriastradh 	const unsigned num_pages __diagused = vbo->base.num_pages;
170e3e4e02dSriastradh 
171e3e4e02dSriastradh 	KASSERT(offset < (num_pages << PAGE_SHIFT));
172e3e4e02dSriastradh 	KASSERT(vbo->base.mem.bus.is_iomem);
173e3e4e02dSriastradh 
174e3e4e02dSriastradh 	if (ISSET(vbo->base.mem.placement, TTM_PL_FLAG_WC))
175e3e4e02dSriastradh 		flags |= BUS_SPACE_MAP_PREFETCHABLE;
176e3e4e02dSriastradh 
177e3e4e02dSriastradh 	return bus_space_mmap(vbo->base.bdev->memt,
178e3e4e02dSriastradh 	    vbo->base.mem.bus.base, vbo->base.mem.bus.offset + offset,
179e3e4e02dSriastradh 	    prot, flags);
180e3e4e02dSriastradh }
181