xref: /netbsd-src/sys/external/bsd/drm2/i915drm/intelfb.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1 /*	$NetBSD: intelfb.c,v 1.17 2019/08/15 00:27:47 rin Exp $	*/
2 
3 /*-
4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Taylor R. Campbell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: intelfb.c,v 1.17 2019/08/15 00:27:47 rin Exp $");
34 
35 #include <sys/types.h>
36 #include <sys/bus.h>
37 #include <sys/device.h>
38 
39 #include <drm/drmP.h>
40 #include <drm/drmfb.h>
41 #include <drm/drmfb_pci.h>
42 
43 #include "i915_drv.h"
44 #include "i915_pci.h"
45 #include "intel_drv.h"
46 #include "intelfb.h"
47 
48 static int	intelfb_match(device_t, cfdata_t, void *);
49 static void	intelfb_attach(device_t, device_t, void *);
50 static int	intelfb_detach(device_t, int);
51 
52 static void	intelfb_attach_task(struct i915drmkms_task *);
53 
54 static bool	intelfb_shutdown(device_t, int);
55 
56 static paddr_t	intelfb_drmfb_mmapfb(struct drmfb_softc *, off_t, int);
57 
58 struct intelfb_softc {
59 	struct drmfb_softc		sc_drmfb; /* XXX Must be first.  */
60 	device_t			sc_dev;
61 	struct intelfb_attach_args	sc_ifa;
62 	bus_space_handle_t		sc_fb_bsh;
63 	struct i915drmkms_task		sc_attach_task;
64 	bool				sc_mapped:1;
65 	bool				sc_scheduled:1;
66 	bool				sc_attached:1;
67 };
68 
69 static const struct drmfb_params intelfb_drmfb_params = {
70 	.dp_mmapfb = intelfb_drmfb_mmapfb,
71 	.dp_mmap = drmfb_pci_mmap,
72 	.dp_ioctl = drmfb_pci_ioctl,
73 	.dp_is_vga_console = drmfb_pci_is_vga_console,
74 	.dp_disable_vga = i915_disable_vga,
75 };
76 
77 CFATTACH_DECL_NEW(intelfb, sizeof(struct intelfb_softc),
78     intelfb_match, intelfb_attach, intelfb_detach, NULL);
79 
80 static int
81 intelfb_match(device_t parent, cfdata_t match, void *aux)
82 {
83 
84 	return 1;
85 }
86 
87 static void
88 intelfb_attach(device_t parent, device_t self, void *aux)
89 {
90 	struct intelfb_softc *const sc = device_private(self);
91 	const struct intelfb_attach_args *const ifa = aux;
92 	int error;
93 
94 	sc->sc_dev = self;
95 	sc->sc_ifa = *ifa;
96 	sc->sc_mapped = false;
97 	sc->sc_scheduled = false;
98 	sc->sc_attached = false;
99 
100 	aprint_naive("\n");
101 	aprint_normal("\n");
102 
103 	/* XXX Defer this too?  */
104 	error = bus_space_map(ifa->ifa_fb_bst, ifa->ifa_fb_addr,
105 	    ifa->ifa_fb_size,
106 	    BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE,
107 	    &sc->sc_fb_bsh);
108 	if (error) {
109 		aprint_error_dev(self, "unable to map framebuffer: %d\n",
110 		    error);
111 		goto fail0;
112 	}
113 	sc->sc_mapped = true;
114 
115 	i915drmkms_task_init(&sc->sc_attach_task, &intelfb_attach_task);
116 	error = i915drmkms_task_schedule(parent, &sc->sc_attach_task);
117 	if (error) {
118 		aprint_error_dev(self, "failed to schedule mode set: %d\n",
119 		    error);
120 		goto fail1;
121 	}
122 	self->dv_flags |= DVF_ATTACH_INPROGRESS;
123 	sc->sc_scheduled = true;
124 
125 	/* Success!  */
126 	return;
127 
128 fail1:	bus_space_unmap(ifa->ifa_fb_bst, sc->sc_fb_bsh, ifa->ifa_fb_size);
129 	sc->sc_mapped = false;
130 fail0:	return;
131 }
132 
133 static int
134 intelfb_detach(device_t self, int flags)
135 {
136 	struct intelfb_softc *const sc = device_private(self);
137 	int error;
138 
139 	if (sc->sc_scheduled)
140 		return EBUSY;
141 
142 	if (sc->sc_attached) {
143 		pmf_device_deregister(self);
144 		error = drmfb_detach(&sc->sc_drmfb, flags);
145 		if (error) {
146 			/* XXX Ugh.  */
147 			(void)pmf_device_register1(self, NULL, NULL,
148 			    &intelfb_shutdown);
149 			return error;
150 		}
151 		sc->sc_attached = false;
152 	}
153 
154 	if (sc->sc_mapped) {
155 		bus_space_unmap(sc->sc_ifa.ifa_fb_bst, sc->sc_fb_bsh,
156 		    sc->sc_ifa.ifa_fb_size);
157 		sc->sc_mapped = false;
158 	}
159 
160 	return 0;
161 }
162 
163 static void
164 intelfb_attach_task(struct i915drmkms_task *task)
165 {
166 	struct intelfb_softc *const sc = container_of(task,
167 	    struct intelfb_softc, sc_attach_task);
168 	const struct intelfb_attach_args *const ifa = &sc->sc_ifa;
169 	const struct drmfb_attach_args da = {
170 		.da_dev = sc->sc_dev,
171 		.da_fb_helper = ifa->ifa_fb_helper,
172 		.da_fb_sizes = &ifa->ifa_fb_sizes,
173 		.da_fb_vaddr = bus_space_vaddr(ifa->ifa_fb_bst, sc->sc_fb_bsh),
174 		.da_fb_linebytes = ifa->ifa_fb_helper->fb->pitches[0],
175 		.da_params = &intelfb_drmfb_params,
176 	};
177 	int error;
178 
179 	error = drmfb_attach(&sc->sc_drmfb, &da);
180 	if (error) {
181 		aprint_error_dev(sc->sc_dev, "failed to attach drmfb: %d\n",
182 		    error);
183 		goto out;
184 	}
185 
186 	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, &intelfb_shutdown))
187 		aprint_error_dev(sc->sc_dev,
188 		    "failed to register shutdown handler\n");
189 
190 	sc->sc_attached = true;
191 out:
192 	sc->sc_dev->dv_flags &= ~DVF_ATTACH_INPROGRESS;
193 }
194 
195 static bool
196 intelfb_shutdown(device_t self, int flags)
197 {
198 	struct intelfb_softc *const sc = device_private(self);
199 
200 	return drmfb_shutdown(&sc->sc_drmfb, flags);
201 }
202 
203 static paddr_t
204 intelfb_drmfb_mmapfb(struct drmfb_softc *drmfb, off_t offset, int prot)
205 {
206 	struct intelfb_softc *const sc = container_of(drmfb,
207 	    struct intelfb_softc, sc_drmfb);
208 	struct drm_fb_helper *const helper = sc->sc_ifa.ifa_fb_helper;
209 	struct intel_fbdev *const fbdev = container_of(helper,
210 	    struct intel_fbdev, helper);
211 	struct drm_device *const dev = helper->dev;
212 	struct drm_i915_private *const dev_priv = dev->dev_private;
213 
214 	KASSERT(0 <= offset);
215 	KASSERT(offset < fbdev->fb->obj->base.size);
216 
217 	return bus_space_mmap(dev->bst, dev_priv->gtt.mappable_base,
218 	    i915_gem_obj_ggtt_offset(fbdev->fb->obj) + offset,
219 	    prot, BUS_SPACE_MAP_PREFETCHABLE);
220 }
221