sunxi_debe.c revision 1.2.2.1 1 1.2.2.1 pgoyette /* $NetBSD: sunxi_debe.c,v 1.2.2.1 2018/04/07 04:12:12 pgoyette Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.2.2.1 pgoyette * Copyright (c) 2018 Manuel Bouyer <bouyer (at) antioche.eu.org>
5 1.2.2.1 pgoyette * All rights reserved.
6 1.2.2.1 pgoyette *
7 1.2.2.1 pgoyette * Copyright (c) 2014 Jared D. McNeill <jmcneill (at) invisible.ca>
8 1.1 jmcneill * All rights reserved.
9 1.1 jmcneill *
10 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
11 1.1 jmcneill * modification, are permitted provided that the following conditions
12 1.1 jmcneill * are met:
13 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
14 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
15 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the
17 1.1 jmcneill * documentation and/or other materials provided with the distribution.
18 1.1 jmcneill *
19 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 jmcneill * SUCH DAMAGE.
30 1.1 jmcneill */
31 1.1 jmcneill
32 1.2.2.1 pgoyette #include "genfb.h"
33 1.2.2.1 pgoyette
34 1.2.2.1 pgoyette #ifndef SUNXI_DEBE_VIDEOMEM
35 1.2.2.1 pgoyette #define SUNXI_DEBE_VIDEOMEM (16 * 1024 * 1024)
36 1.2.2.1 pgoyette #endif
37 1.2.2.1 pgoyette
38 1.2.2.1 pgoyette #define SUNXI_DEBE_CURMAX 64
39 1.2.2.1 pgoyette
40 1.1 jmcneill #include <sys/cdefs.h>
41 1.2.2.1 pgoyette __KERNEL_RCSID(0, "$NetBSD: sunxi_debe.c,v 1.2.2.1 2018/04/07 04:12:12 pgoyette Exp $");
42 1.1 jmcneill
43 1.1 jmcneill #include <sys/param.h>
44 1.1 jmcneill #include <sys/bus.h>
45 1.1 jmcneill #include <sys/device.h>
46 1.2.2.1 pgoyette #include <sys/intr.h>
47 1.1 jmcneill #include <sys/systm.h>
48 1.2.2.1 pgoyette #include <sys/kernel.h>
49 1.2.2.1 pgoyette #include <sys/mutex.h>
50 1.2.2.1 pgoyette #include <sys/condvar.h>
51 1.1 jmcneill
52 1.1 jmcneill #include <dev/fdt/fdtvar.h>
53 1.2.2.1 pgoyette #include <dev/fdt/fdt_port.h>
54 1.1 jmcneill
55 1.2.2.1 pgoyette #include <dev/videomode/videomode.h>
56 1.2.2.1 pgoyette #include <dev/wscons/wsconsio.h>
57 1.1 jmcneill #include <dev/wsfb/genfbvar.h>
58 1.1 jmcneill
59 1.2.2.1 pgoyette #include <arm/sunxi/sunxi_debereg.h>
60 1.2.2.1 pgoyette #include <arm/sunxi/sunxi_display.h>
61 1.1 jmcneill
62 1.2.2.1 pgoyette enum sunxi_debe_type {
63 1.2.2.1 pgoyette DEBE_A10 = 1,
64 1.1 jmcneill };
65 1.1 jmcneill
66 1.1 jmcneill struct sunxi_debe_softc {
67 1.2.2.1 pgoyette device_t sc_dev;
68 1.2.2.1 pgoyette device_t sc_fbdev;
69 1.2.2.1 pgoyette enum sunxi_debe_type sc_type;
70 1.1 jmcneill bus_space_tag_t sc_bst;
71 1.1 jmcneill bus_space_handle_t sc_bsh;
72 1.2.2.1 pgoyette bus_dma_tag_t sc_dmat;
73 1.1 jmcneill
74 1.2.2.1 pgoyette struct clk *sc_clk_ahb;
75 1.2.2.1 pgoyette struct clk *sc_clk_mod;
76 1.2.2.1 pgoyette struct clk *sc_clk_ram;
77 1.2.2.1 pgoyette
78 1.2.2.1 pgoyette bus_dma_segment_t sc_dmasegs[1];
79 1.2.2.1 pgoyette bus_size_t sc_dmasize;
80 1.2.2.1 pgoyette bus_dmamap_t sc_dmamap;
81 1.2.2.1 pgoyette void *sc_dmap;
82 1.2.2.1 pgoyette
83 1.2.2.1 pgoyette bool sc_cursor_enable;
84 1.2.2.1 pgoyette int sc_cursor_x, sc_cursor_y;
85 1.2.2.1 pgoyette int sc_hot_x, sc_hot_y;
86 1.2.2.1 pgoyette uint8_t sc_cursor_bitmap[8 * SUNXI_DEBE_CURMAX];
87 1.2.2.1 pgoyette uint8_t sc_cursor_mask[8 * SUNXI_DEBE_CURMAX];
88 1.2.2.1 pgoyette
89 1.2.2.1 pgoyette int sc_phandle;
90 1.2.2.1 pgoyette struct fdt_device_ports sc_ports;
91 1.2.2.1 pgoyette struct fdt_endpoint *sc_out_ep;
92 1.2.2.1 pgoyette int sc_unit; /* debe0 or debe1 */
93 1.1 jmcneill };
94 1.1 jmcneill
95 1.2.2.1 pgoyette #define DEBE_READ(sc, reg) \
96 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
97 1.2.2.1 pgoyette #define DEBE_WRITE(sc, reg, val) \
98 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
99 1.1 jmcneill
100 1.2.2.1 pgoyette static const struct of_compat_data compat_data[] = {
101 1.2.2.1 pgoyette {"allwinner,sun4i-a10-display-backend", DEBE_A10},
102 1.2.2.1 pgoyette {"allwinner,sun7i-a20-display-backend", DEBE_A10},
103 1.2.2.1 pgoyette {NULL}
104 1.2.2.1 pgoyette };
105 1.2.2.1 pgoyette
106 1.2.2.1 pgoyette struct sunxifb_attach_args {
107 1.2.2.1 pgoyette void *afb_fb;
108 1.2.2.1 pgoyette uint32_t afb_width;
109 1.2.2.1 pgoyette uint32_t afb_height;
110 1.2.2.1 pgoyette bus_dma_tag_t afb_dmat;
111 1.2.2.1 pgoyette bus_dma_segment_t *afb_dmasegs;
112 1.2.2.1 pgoyette int afb_ndmasegs;
113 1.2.2.1 pgoyette };
114 1.2.2.1 pgoyette
115 1.2.2.1 pgoyette static void sunxi_debe_ep_connect(device_t, struct fdt_endpoint *, bool);
116 1.2.2.1 pgoyette static int sunxi_debe_ep_enable(device_t, struct fdt_endpoint *, bool);
117 1.2.2.1 pgoyette static int sunxi_debe_match(device_t, cfdata_t, void *);
118 1.2.2.1 pgoyette static void sunxi_debe_attach(device_t, device_t, void *);
119 1.2.2.1 pgoyette
120 1.2.2.1 pgoyette static int sunxi_debe_alloc_videomem(struct sunxi_debe_softc *);
121 1.2.2.1 pgoyette static void sunxi_debe_setup_fbdev(struct sunxi_debe_softc *,
122 1.2.2.1 pgoyette const struct videomode *);
123 1.2.2.1 pgoyette
124 1.2.2.1 pgoyette static int sunxi_debe_set_curpos(struct sunxi_debe_softc *, int, int);
125 1.2.2.1 pgoyette static int sunxi_debe_set_cursor(struct sunxi_debe_softc *,
126 1.2.2.1 pgoyette struct wsdisplay_cursor *);
127 1.2.2.1 pgoyette static int sunxi_debe_ioctl(device_t, u_long, void *);
128 1.2.2.1 pgoyette static void sunxi_befb_set_videomode(device_t, u_int, u_int);
129 1.2.2.1 pgoyette void sunxi_debe_dump_regs(int);
130 1.2.2.1 pgoyette
131 1.2.2.1 pgoyette CFATTACH_DECL_NEW(sunxi_debe, sizeof(struct sunxi_debe_softc),
132 1.2.2.1 pgoyette sunxi_debe_match, sunxi_debe_attach, NULL, NULL);
133 1.2.2.1 pgoyette
134 1.2.2.1 pgoyette static int
135 1.2.2.1 pgoyette sunxi_debe_match(device_t parent, cfdata_t cf, void *aux)
136 1.1 jmcneill {
137 1.2.2.1 pgoyette struct fdt_attach_args * const faa = aux;
138 1.2.2.1 pgoyette
139 1.2.2.1 pgoyette return of_match_compat_data(faa->faa_phandle, compat_data);
140 1.1 jmcneill }
141 1.1 jmcneill
142 1.2.2.1 pgoyette static void
143 1.2.2.1 pgoyette sunxi_debe_attach(device_t parent, device_t self, void *aux)
144 1.1 jmcneill {
145 1.2.2.1 pgoyette struct sunxi_debe_softc *sc = device_private(self);
146 1.2.2.1 pgoyette struct fdt_attach_args * const faa = aux;
147 1.2.2.1 pgoyette const int phandle = faa->faa_phandle;
148 1.2.2.1 pgoyette bus_addr_t addr;
149 1.2.2.1 pgoyette bus_size_t size;
150 1.2.2.1 pgoyette struct fdtbus_reset *rst;
151 1.1 jmcneill int error;
152 1.1 jmcneill
153 1.2.2.1 pgoyette sc->sc_dev = self;
154 1.2.2.1 pgoyette sc->sc_phandle = phandle;
155 1.2.2.1 pgoyette sc->sc_bst = faa->faa_bst;
156 1.2.2.1 pgoyette sc->sc_dmat = faa->faa_dmat;
157 1.2.2.1 pgoyette if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
158 1.2.2.1 pgoyette aprint_error(": couldn't get registers\n");
159 1.2.2.1 pgoyette }
160 1.2.2.1 pgoyette if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
161 1.2.2.1 pgoyette aprint_error(": couldn't map registers\n");
162 1.2.2.1 pgoyette return;
163 1.2.2.1 pgoyette }
164 1.2.2.1 pgoyette
165 1.2.2.1 pgoyette sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
166 1.2.2.1 pgoyette sc->sc_clk_mod = fdtbus_clock_get(phandle, "mod");
167 1.2.2.1 pgoyette sc->sc_clk_ram = fdtbus_clock_get(phandle, "ram");
168 1.2.2.1 pgoyette
169 1.2.2.1 pgoyette rst = fdtbus_reset_get_index(phandle, 0);
170 1.2.2.1 pgoyette if (rst == NULL) {
171 1.2.2.1 pgoyette aprint_error(": couldn't get reset\n");
172 1.2.2.1 pgoyette return;
173 1.2.2.1 pgoyette }
174 1.2.2.1 pgoyette if (fdtbus_reset_assert(rst) != 0) {
175 1.2.2.1 pgoyette aprint_error(": couldn't assert reset\n");
176 1.2.2.1 pgoyette return;
177 1.2.2.1 pgoyette }
178 1.2.2.1 pgoyette delay(1);
179 1.2.2.1 pgoyette if (fdtbus_reset_deassert(rst) != 0) {
180 1.2.2.1 pgoyette aprint_error(": couldn't de-assert reset\n");
181 1.2.2.1 pgoyette return;
182 1.2.2.1 pgoyette }
183 1.2.2.1 pgoyette
184 1.2.2.1 pgoyette if (sc->sc_clk_ahb == NULL || sc->sc_clk_mod == NULL
185 1.2.2.1 pgoyette || sc->sc_clk_ram == NULL) {
186 1.2.2.1 pgoyette aprint_error(": couldn't get clocks\n");
187 1.2.2.1 pgoyette aprint_debug_dev(self, "clk ahb %s mod %s ram %s\n",
188 1.2.2.1 pgoyette sc->sc_clk_ahb == NULL ? "missing" : "present",
189 1.2.2.1 pgoyette sc->sc_clk_mod == NULL ? "missing" : "present",
190 1.2.2.1 pgoyette sc->sc_clk_ram == NULL ? "missing" : "present");
191 1.2.2.1 pgoyette return;
192 1.2.2.1 pgoyette }
193 1.2.2.1 pgoyette
194 1.2.2.1 pgoyette error = clk_set_rate(sc->sc_clk_mod, 300000000);
195 1.2.2.1 pgoyette if (error) {
196 1.2.2.1 pgoyette aprint_error("couln't set mod clock rate (%d)\n", error);
197 1.2.2.1 pgoyette return;
198 1.2.2.1 pgoyette }
199 1.2.2.1 pgoyette
200 1.2.2.1 pgoyette if (clk_enable(sc->sc_clk_ahb) != 0 ||
201 1.2.2.1 pgoyette clk_enable(sc->sc_clk_mod) != 0) {
202 1.2.2.1 pgoyette aprint_error(": couldn't enable clocks\n");
203 1.2.2.1 pgoyette return;
204 1.2.2.1 pgoyette }
205 1.2.2.1 pgoyette if (clk_disable(sc->sc_clk_ram) != 0) {
206 1.2.2.1 pgoyette aprint_error(": couldn't disable ram clock\n");
207 1.2.2.1 pgoyette }
208 1.2.2.1 pgoyette
209 1.2.2.1 pgoyette sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data;
210 1.2.2.1 pgoyette
211 1.2.2.1 pgoyette aprint_naive("\n");
212 1.2.2.1 pgoyette aprint_normal(": Display Engine Backend (%s)\n",
213 1.2.2.1 pgoyette fdtbus_get_string(phandle, "name"));
214 1.2.2.1 pgoyette
215 1.2.2.1 pgoyette
216 1.2.2.1 pgoyette for (unsigned int reg = 0x800; reg < 0x1000; reg += 4) {
217 1.2.2.1 pgoyette DEBE_WRITE(sc, reg, 0);
218 1.2.2.1 pgoyette }
219 1.2.2.1 pgoyette
220 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, SUNXI_DEBE_MODCTL_EN);
221 1.2.2.1 pgoyette
222 1.2.2.1 pgoyette sc->sc_dmasize = SUNXI_DEBE_VIDEOMEM;
223 1.2.2.1 pgoyette
224 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_HWC_PALETTE_TABLE, 0);
225 1.2.2.1 pgoyette
226 1.2.2.1 pgoyette error = sunxi_debe_alloc_videomem(sc);
227 1.2.2.1 pgoyette if (error) {
228 1.2.2.1 pgoyette aprint_error_dev(sc->sc_dev,
229 1.2.2.1 pgoyette "couldn't allocate video memory, error = %d\n", error);
230 1.2.2.1 pgoyette return;
231 1.2.2.1 pgoyette }
232 1.2.2.1 pgoyette
233 1.2.2.1 pgoyette sc->sc_unit = -1;
234 1.2.2.1 pgoyette sc->sc_ports.dp_ep_connect = sunxi_debe_ep_connect;
235 1.2.2.1 pgoyette sc->sc_ports.dp_ep_enable = sunxi_debe_ep_enable;
236 1.2.2.1 pgoyette fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER);
237 1.2.2.1 pgoyette
238 1.2.2.1 pgoyette if (clk_disable(sc->sc_clk_ahb) != 0 ||
239 1.2.2.1 pgoyette clk_disable(sc->sc_clk_mod) != 0) {
240 1.2.2.1 pgoyette aprint_error(": couldn't disable clocks\n");
241 1.2.2.1 pgoyette return;
242 1.2.2.1 pgoyette }
243 1.2.2.1 pgoyette }
244 1.2.2.1 pgoyette
245 1.2.2.1 pgoyette
246 1.2.2.1 pgoyette
247 1.2.2.1 pgoyette static void
248 1.2.2.1 pgoyette sunxi_debe_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect)
249 1.2.2.1 pgoyette {
250 1.2.2.1 pgoyette struct sunxi_debe_softc *sc = device_private(self);
251 1.2.2.1 pgoyette struct fdt_endpoint *rep = fdt_endpoint_remote(ep);
252 1.2.2.1 pgoyette int rep_idx = fdt_endpoint_index(rep);
253 1.2.2.1 pgoyette
254 1.2.2.1 pgoyette KASSERT(device_is_a(self, "sunxidebe"));
255 1.2.2.1 pgoyette if (!connect) {
256 1.2.2.1 pgoyette aprint_error_dev(self, "endpoint disconnect not supported\n");
257 1.2.2.1 pgoyette return;
258 1.2.2.1 pgoyette }
259 1.2.2.1 pgoyette
260 1.2.2.1 pgoyette if (fdt_endpoint_port_index(ep) == 1) {
261 1.2.2.1 pgoyette bool do_print = (sc->sc_unit == -1);
262 1.2.2.1 pgoyette /*
263 1.2.2.1 pgoyette * one of our output endpoints has been connected.
264 1.2.2.1 pgoyette * the remote id is our unit number
265 1.2.2.1 pgoyette */
266 1.2.2.1 pgoyette if (sc->sc_unit != -1 && rep_idx != -1 &&
267 1.2.2.1 pgoyette sc->sc_unit != rep_idx) {
268 1.2.2.1 pgoyette aprint_error_dev(self, ": remote id %d doens't match"
269 1.2.2.1 pgoyette " discovered unit number %d\n",
270 1.2.2.1 pgoyette rep_idx, sc->sc_unit);
271 1.2.2.1 pgoyette return;
272 1.2.2.1 pgoyette }
273 1.2.2.1 pgoyette if (!device_is_a(fdt_endpoint_device(rep), "sunxitcon")) {
274 1.2.2.1 pgoyette aprint_error_dev(self,
275 1.2.2.1 pgoyette ": output %d connected to unknown device\n",
276 1.2.2.1 pgoyette fdt_endpoint_index(ep));
277 1.2.2.1 pgoyette return;
278 1.2.2.1 pgoyette }
279 1.2.2.1 pgoyette if (rep_idx != -1)
280 1.2.2.1 pgoyette sc->sc_unit = rep_idx;
281 1.2.2.1 pgoyette else {
282 1.2.2.1 pgoyette /* assume only one debe */
283 1.2.2.1 pgoyette sc->sc_unit = 0;
284 1.2.2.1 pgoyette }
285 1.2.2.1 pgoyette if (do_print)
286 1.2.2.1 pgoyette aprint_verbose_dev(self, "debe unit %d\n", sc->sc_unit);
287 1.2.2.1 pgoyette }
288 1.2.2.1 pgoyette }
289 1.2.2.1 pgoyette
290 1.2.2.1 pgoyette static int
291 1.2.2.1 pgoyette sunxi_debe_alloc_videomem(struct sunxi_debe_softc *sc)
292 1.2.2.1 pgoyette {
293 1.2.2.1 pgoyette int error, nsegs;
294 1.2.2.1 pgoyette
295 1.2.2.1 pgoyette error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmasize, 0x1000, 0,
296 1.2.2.1 pgoyette sc->sc_dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
297 1.2.2.1 pgoyette if (error)
298 1.2.2.1 pgoyette return error;
299 1.2.2.1 pgoyette error = bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, nsegs,
300 1.2.2.1 pgoyette sc->sc_dmasize, &sc->sc_dmap, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
301 1.2.2.1 pgoyette if (error)
302 1.2.2.1 pgoyette goto free;
303 1.2.2.1 pgoyette error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmasize, 1,
304 1.2.2.1 pgoyette sc->sc_dmasize, 0, BUS_DMA_WAITOK, &sc->sc_dmamap);
305 1.2.2.1 pgoyette if (error)
306 1.2.2.1 pgoyette goto unmap;
307 1.2.2.1 pgoyette error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmap,
308 1.2.2.1 pgoyette sc->sc_dmasize, NULL, BUS_DMA_WAITOK);
309 1.2.2.1 pgoyette if (error)
310 1.2.2.1 pgoyette goto destroy;
311 1.2.2.1 pgoyette
312 1.2.2.1 pgoyette memset(sc->sc_dmap, 0, sc->sc_dmasize);
313 1.2.2.1 pgoyette
314 1.2.2.1 pgoyette return 0;
315 1.2.2.1 pgoyette
316 1.2.2.1 pgoyette destroy:
317 1.2.2.1 pgoyette bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
318 1.2.2.1 pgoyette unmap:
319 1.2.2.1 pgoyette bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmap, sc->sc_dmasize);
320 1.2.2.1 pgoyette free:
321 1.2.2.1 pgoyette bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, nsegs);
322 1.2.2.1 pgoyette
323 1.2.2.1 pgoyette sc->sc_dmasize = 0;
324 1.2.2.1 pgoyette sc->sc_dmap = NULL;
325 1.2.2.1 pgoyette
326 1.2.2.1 pgoyette return error;
327 1.2.2.1 pgoyette }
328 1.2.2.1 pgoyette
329 1.2.2.1 pgoyette static void
330 1.2.2.1 pgoyette sunxi_debe_setup_fbdev(struct sunxi_debe_softc *sc, const struct videomode *mode)
331 1.2.2.1 pgoyette {
332 1.2.2.1 pgoyette if (mode == NULL)
333 1.2.2.1 pgoyette return;
334 1.2.2.1 pgoyette
335 1.2.2.1 pgoyette const u_int interlace_p = !!(mode->flags & VID_INTERLACE);
336 1.2.2.1 pgoyette const u_int fb_width = mode->hdisplay;
337 1.2.2.1 pgoyette const u_int fb_height = (mode->vdisplay << interlace_p);
338 1.2.2.1 pgoyette
339 1.2.2.1 pgoyette if (mode && sc->sc_fbdev == NULL) {
340 1.2.2.1 pgoyette struct sunxifb_attach_args afb = {
341 1.2.2.1 pgoyette .afb_fb = sc->sc_dmap,
342 1.2.2.1 pgoyette .afb_width = fb_width,
343 1.2.2.1 pgoyette .afb_height = fb_height,
344 1.2.2.1 pgoyette .afb_dmat = sc->sc_dmat,
345 1.2.2.1 pgoyette .afb_dmasegs = sc->sc_dmasegs,
346 1.2.2.1 pgoyette .afb_ndmasegs = 1
347 1.2.2.1 pgoyette };
348 1.2.2.1 pgoyette sc->sc_fbdev = config_found_ia(sc->sc_dev, "sunxidebe",
349 1.2.2.1 pgoyette &afb, NULL);
350 1.2.2.1 pgoyette } else if (sc->sc_fbdev != NULL) {
351 1.2.2.1 pgoyette sunxi_befb_set_videomode(sc->sc_fbdev, fb_width, fb_height);
352 1.2.2.1 pgoyette }
353 1.2.2.1 pgoyette }
354 1.2.2.1 pgoyette
355 1.2.2.1 pgoyette static int
356 1.2.2.1 pgoyette sunxi_debe_set_curpos(struct sunxi_debe_softc *sc, int x, int y)
357 1.2.2.1 pgoyette {
358 1.2.2.1 pgoyette int xx, yy;
359 1.2.2.1 pgoyette u_int yoff, xoff;
360 1.2.2.1 pgoyette
361 1.2.2.1 pgoyette xoff = yoff = 0;
362 1.2.2.1 pgoyette xx = x - sc->sc_hot_x;
363 1.2.2.1 pgoyette yy = y - sc->sc_hot_y;
364 1.2.2.1 pgoyette if (xx < 0) {
365 1.2.2.1 pgoyette xoff -= xx;
366 1.2.2.1 pgoyette xx = 0;
367 1.2.2.1 pgoyette }
368 1.2.2.1 pgoyette if (yy < 0) {
369 1.2.2.1 pgoyette yoff -= yy;
370 1.2.2.1 pgoyette yy = 0;
371 1.2.2.1 pgoyette }
372 1.2.2.1 pgoyette
373 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_HWCCTL_REG,
374 1.2.2.1 pgoyette __SHIFTIN(yy, SUNXI_DEBE_HWCCTL_YCOOR) |
375 1.2.2.1 pgoyette __SHIFTIN(xx, SUNXI_DEBE_HWCCTL_XCOOR));
376 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_HWCFBCTL_REG,
377 1.2.2.1 pgoyette #if SUNXI_DEBE_CURMAX == 32
378 1.2.2.1 pgoyette __SHIFTIN(SUNXI_DEBE_HWCFBCTL_YSIZE_32, SUNXI_DEBE_HWCFBCTL_YSIZE) |
379 1.2.2.1 pgoyette __SHIFTIN(SUNXI_DEBE_HWCFBCTL_XSIZE_32, SUNXI_DEBE_HWCFBCTL_XSIZE) |
380 1.2.2.1 pgoyette #else
381 1.2.2.1 pgoyette __SHIFTIN(SUNXI_DEBE_HWCFBCTL_YSIZE_64, SUNXI_DEBE_HWCFBCTL_YSIZE) |
382 1.2.2.1 pgoyette __SHIFTIN(SUNXI_DEBE_HWCFBCTL_XSIZE_64, SUNXI_DEBE_HWCFBCTL_XSIZE) |
383 1.2.2.1 pgoyette #endif
384 1.2.2.1 pgoyette __SHIFTIN(SUNXI_DEBE_HWCFBCTL_FBFMT_2BPP, SUNXI_DEBE_HWCFBCTL_FBFMT) |
385 1.2.2.1 pgoyette __SHIFTIN(yoff, SUNXI_DEBE_HWCFBCTL_YCOOROFF) |
386 1.2.2.1 pgoyette __SHIFTIN(xoff, SUNXI_DEBE_HWCFBCTL_XCOOROFF));
387 1.2.2.1 pgoyette
388 1.2.2.1 pgoyette return 0;
389 1.2.2.1 pgoyette }
390 1.2.2.1 pgoyette
391 1.2.2.1 pgoyette static int
392 1.2.2.1 pgoyette sunxi_debe_set_cursor(struct sunxi_debe_softc *sc, struct wsdisplay_cursor *cur)
393 1.2.2.1 pgoyette {
394 1.2.2.1 pgoyette uint32_t val;
395 1.2.2.1 pgoyette uint8_t r[4], g[4], b[4];
396 1.2.2.1 pgoyette u_int index, count, shift, off, pcnt;
397 1.2.2.1 pgoyette int i, j, idx, error;
398 1.2.2.1 pgoyette uint8_t mask;
399 1.2.2.1 pgoyette
400 1.2.2.1 pgoyette if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
401 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
402 1.2.2.1 pgoyette if (cur->enable)
403 1.2.2.1 pgoyette val |= SUNXI_DEBE_MODCTL_HWC_EN;
404 1.2.2.1 pgoyette else
405 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_MODCTL_HWC_EN;
406 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val);
407 1.2.2.1 pgoyette
408 1.2.2.1 pgoyette sc->sc_cursor_enable = cur->enable;
409 1.2.2.1 pgoyette }
410 1.2.2.1 pgoyette
411 1.2.2.1 pgoyette if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
412 1.2.2.1 pgoyette sc->sc_hot_x = cur->hot.x;
413 1.2.2.1 pgoyette sc->sc_hot_y = cur->hot.y;
414 1.2.2.1 pgoyette cur->which |= WSDISPLAY_CURSOR_DOPOS;
415 1.2.2.1 pgoyette }
416 1.2.2.1 pgoyette
417 1.2.2.1 pgoyette if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
418 1.2.2.1 pgoyette sunxi_debe_set_curpos(sc, cur->pos.x, cur->pos.y);
419 1.2.2.1 pgoyette }
420 1.2.2.1 pgoyette
421 1.2.2.1 pgoyette if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
422 1.2.2.1 pgoyette index = cur->cmap.index;
423 1.2.2.1 pgoyette count = cur->cmap.count;
424 1.2.2.1 pgoyette if (index >= 2 || count > 2 - index)
425 1.2.2.1 pgoyette return EINVAL;
426 1.2.2.1 pgoyette error = copyin(cur->cmap.red, &r[index], count);
427 1.2.2.1 pgoyette if (error)
428 1.2.2.1 pgoyette return error;
429 1.2.2.1 pgoyette error = copyin(cur->cmap.green, &g[index], count);
430 1.2.2.1 pgoyette if (error)
431 1.2.2.1 pgoyette return error;
432 1.2.2.1 pgoyette error = copyin(cur->cmap.blue, &b[index], count);
433 1.2.2.1 pgoyette if (error)
434 1.2.2.1 pgoyette return error;
435 1.2.2.1 pgoyette
436 1.2.2.1 pgoyette for (i = index; i < (index + count); i++) {
437 1.2.2.1 pgoyette DEBE_WRITE(sc,
438 1.2.2.1 pgoyette SUNXI_DEBE_HWC_PALETTE_TABLE + (4 * (i + 2)),
439 1.2.2.1 pgoyette (r[i] << 16) | (g[i] << 8) | b[i] | 0xff000000);
440 1.2.2.1 pgoyette }
441 1.2.2.1 pgoyette }
442 1.2.2.1 pgoyette
443 1.2.2.1 pgoyette if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
444 1.2.2.1 pgoyette error = copyin(cur->mask, sc->sc_cursor_mask,
445 1.2.2.1 pgoyette SUNXI_DEBE_CURMAX * 8);
446 1.2.2.1 pgoyette if (error)
447 1.2.2.1 pgoyette return error;
448 1.2.2.1 pgoyette error = copyin(cur->image, sc->sc_cursor_bitmap,
449 1.2.2.1 pgoyette SUNXI_DEBE_CURMAX * 8);
450 1.2.2.1 pgoyette if (error)
451 1.2.2.1 pgoyette return error;
452 1.2.2.1 pgoyette }
453 1.2.2.1 pgoyette
454 1.2.2.1 pgoyette if (cur->which & (WSDISPLAY_CURSOR_DOCMAP|WSDISPLAY_CURSOR_DOSHAPE)) {
455 1.2.2.1 pgoyette for (i = 0, pcnt = 0; i < SUNXI_DEBE_CURMAX * 8; i++) {
456 1.2.2.1 pgoyette for (j = 0, mask = 1; j < 8; j++, mask <<= 1, pcnt++) {
457 1.2.2.1 pgoyette idx = ((sc->sc_cursor_mask[i] & mask) ? 2 : 0) |
458 1.2.2.1 pgoyette ((sc->sc_cursor_bitmap[i] & mask) ? 1 : 0);
459 1.2.2.1 pgoyette off = (pcnt >> 4) * 4;
460 1.2.2.1 pgoyette shift = (pcnt & 0xf) * 2;
461 1.2.2.1 pgoyette val = DEBE_READ(sc,
462 1.2.2.1 pgoyette SUNXI_DEBE_HWC_PATTERN_BLOCK + off);
463 1.2.2.1 pgoyette val &= ~(3 << shift);
464 1.2.2.1 pgoyette val |= (idx << shift);
465 1.2.2.1 pgoyette DEBE_WRITE(sc,
466 1.2.2.1 pgoyette SUNXI_DEBE_HWC_PATTERN_BLOCK + off, val);
467 1.2.2.1 pgoyette }
468 1.2.2.1 pgoyette }
469 1.2.2.1 pgoyette }
470 1.2.2.1 pgoyette
471 1.2.2.1 pgoyette return 0;
472 1.2.2.1 pgoyette }
473 1.2.2.1 pgoyette
474 1.2.2.1 pgoyette static int
475 1.2.2.1 pgoyette sunxi_debe_ep_enable(device_t dev, struct fdt_endpoint *ep, bool enable)
476 1.2.2.1 pgoyette {
477 1.2.2.1 pgoyette struct sunxi_debe_softc *sc;
478 1.2.2.1 pgoyette uint32_t val;
479 1.2.2.1 pgoyette
480 1.2.2.1 pgoyette KASSERT(device_is_a(dev, "sunxidebe"));
481 1.2.2.1 pgoyette sc = device_private(dev);
482 1.2.2.1 pgoyette
483 1.2.2.1 pgoyette if (enable) {
484 1.2.2.1 pgoyette if (clk_enable(sc->sc_clk_ram) != 0) {
485 1.2.2.1 pgoyette device_printf(dev,
486 1.2.2.1 pgoyette ": warning: failed to enable ram clock\n");
487 1.2.2.1 pgoyette }
488 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_REGBUFFCTL_REG);
489 1.2.2.1 pgoyette val |= SUNXI_DEBE_REGBUFFCTL_REGLOADCTL;
490 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_REGBUFFCTL_REG, val);
491 1.2.2.1 pgoyette
492 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
493 1.2.2.1 pgoyette val |= SUNXI_DEBE_MODCTL_START_CTL;
494 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val);
495 1.2.2.1 pgoyette #ifdef SUNXI_DEBE_DEBUG
496 1.2.2.1 pgoyette sunxi_debe_dump_regs(sc->sc_unit);
497 1.2.2.1 pgoyette #endif
498 1.2.2.1 pgoyette } else {
499 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
500 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_MODCTL_START_CTL;
501 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val);
502 1.2.2.1 pgoyette if (clk_disable(sc->sc_clk_ram) != 0) {
503 1.2.2.1 pgoyette device_printf(dev,
504 1.2.2.1 pgoyette ": warning: failed to disable ram clock\n");
505 1.2.2.1 pgoyette }
506 1.2.2.1 pgoyette }
507 1.2.2.1 pgoyette #if 0
508 1.2.2.1 pgoyette for (int i = 0; i < 0x1000; i += 4) {
509 1.2.2.1 pgoyette printf("DEBE 0x%04x: 0x%08x\n", i, DEBE_READ(sc, i));
510 1.2.2.1 pgoyette }
511 1.2.2.1 pgoyette #endif
512 1.2.2.1 pgoyette return 0;
513 1.2.2.1 pgoyette }
514 1.2.2.1 pgoyette
515 1.2.2.1 pgoyette void
516 1.2.2.1 pgoyette sunxi_debe_set_videomode(device_t dev, const struct videomode *mode)
517 1.2.2.1 pgoyette {
518 1.2.2.1 pgoyette struct sunxi_debe_softc *sc;
519 1.2.2.1 pgoyette uint32_t val;
520 1.2.2.1 pgoyette
521 1.2.2.1 pgoyette KASSERT(device_is_a(dev, "sunxidebe"));
522 1.2.2.1 pgoyette sc = device_private(dev);
523 1.2.2.1 pgoyette
524 1.2.2.1 pgoyette if (mode) {
525 1.2.2.1 pgoyette const u_int interlace_p = !!(mode->flags & VID_INTERLACE);
526 1.2.2.1 pgoyette const u_int width = mode->hdisplay;
527 1.2.2.1 pgoyette const u_int height = (mode->vdisplay << interlace_p);
528 1.2.2.1 pgoyette const u_int fb_width = width;
529 1.2.2.1 pgoyette const u_int fb_height = height;
530 1.2.2.1 pgoyette uint32_t vmem = width * height * 4;
531 1.2.2.1 pgoyette
532 1.2.2.1 pgoyette if (vmem > sc->sc_dmasize) {
533 1.2.2.1 pgoyette device_printf(sc->sc_dev,
534 1.2.2.1 pgoyette "not enough memory for %ux%u fb (req %u have %u)\n",
535 1.2.2.1 pgoyette width, height, vmem, (unsigned int)sc->sc_dmasize);
536 1.2.2.1 pgoyette return;
537 1.2.2.1 pgoyette }
538 1.2.2.1 pgoyette
539 1.2.2.1 pgoyette paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr;
540 1.2.2.1 pgoyette #if !defined(ALLWINNER_A80) && 0
541 1.2.2.1 pgoyette #define SUNXI_SDRAM_PBASE-0 0x40000000
542 1.2.2.1 pgoyette /*
543 1.2.2.1 pgoyette * On 2GB systems, we need to subtract AWIN_SDRAM_PBASE from
544 1.2.2.1 pgoyette * the phys addr.
545 1.2.2.1 pgoyette */
546 1.2.2.1 pgoyette if (pa >= SUNXI_SDRAM_PBASE)
547 1.2.2.1 pgoyette pa -= SUNXI_SDRAM_PBASE;
548 1.2.2.1 pgoyette #endif
549 1.2.2.1 pgoyette
550 1.2.2.1 pgoyette /* notify fb */
551 1.2.2.1 pgoyette sunxi_debe_setup_fbdev(sc, mode);
552 1.2.2.1 pgoyette
553 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_DISSIZE_REG,
554 1.2.2.1 pgoyette ((height - 1) << 16) | (width - 1));
555 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_LAYSIZE_REG,
556 1.2.2.1 pgoyette ((fb_height - 1) << 16) | (fb_width - 1));
557 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_LAYCOOR_REG, 0);
558 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_LAYLINEWIDTH_REG, (fb_width << 5));
559 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_LAYFB_L32ADD_REG, pa << 3);
560 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_LAYFB_H4ADD_REG, pa >> 29);
561 1.2.2.1 pgoyette
562 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_ATTCTL1_REG);
563 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_ATTCTL1_LAY_FBFMT;
564 1.2.2.1 pgoyette val |= __SHIFTIN(SUNXI_DEBE_ATTCTL1_LAY_FBFMT_XRGB8888,
565 1.2.2.1 pgoyette SUNXI_DEBE_ATTCTL1_LAY_FBFMT);
566 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_ATTCTL1_LAY_BRSWAPEN;
567 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_ATTCTL1_LAY_FBPS;
568 1.2.2.1 pgoyette #if __ARMEB__
569 1.2.2.1 pgoyette val |= __SHIFTIN(SUNXI_DEBE_ATTCTL1_LAY_FBPS_32BPP_BGRA,
570 1.2.2.1 pgoyette SUNXI_DEBE_ATTCTL1_LAY_FBPS);
571 1.2.2.1 pgoyette #else
572 1.2.2.1 pgoyette val |= __SHIFTIN(SUNXI_DEBE_ATTCTL1_LAY_FBPS_32BPP_ARGB,
573 1.2.2.1 pgoyette SUNXI_DEBE_ATTCTL1_LAY_FBPS);
574 1.2.2.1 pgoyette #endif
575 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_ATTCTL1_REG, val);
576 1.2.2.1 pgoyette
577 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
578 1.2.2.1 pgoyette val |= SUNXI_DEBE_MODCTL_LAY0_EN;
579 1.2.2.1 pgoyette if (interlace_p) {
580 1.2.2.1 pgoyette val |= SUNXI_DEBE_MODCTL_ITLMOD_EN;
581 1.2.2.1 pgoyette } else {
582 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_MODCTL_ITLMOD_EN;
583 1.2.2.1 pgoyette }
584 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_MODCTL_OUT_SEL;
585 1.2.2.1 pgoyette if (sc->sc_unit == 1) {
586 1.2.2.1 pgoyette val |= __SHIFTIN(SUNXI_DEBE_MODCTL_OUT_SEL_LCD1,
587 1.2.2.1 pgoyette SUNXI_DEBE_MODCTL_OUT_SEL);
588 1.2.2.1 pgoyette }
589 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val);
590 1.2.2.1 pgoyette } else {
591 1.2.2.1 pgoyette /* disable */
592 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
593 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_MODCTL_LAY0_EN;
594 1.2.2.1 pgoyette val &= ~SUNXI_DEBE_MODCTL_START_CTL;
595 1.2.2.1 pgoyette DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val);
596 1.2.2.1 pgoyette
597 1.2.2.1 pgoyette /* notify fb */
598 1.2.2.1 pgoyette sunxi_debe_setup_fbdev(sc, mode);
599 1.2.2.1 pgoyette }
600 1.2.2.1 pgoyette }
601 1.2.2.1 pgoyette
602 1.2.2.1 pgoyette static int
603 1.2.2.1 pgoyette sunxi_debe_ioctl(device_t self, u_long cmd, void *data)
604 1.2.2.1 pgoyette {
605 1.2.2.1 pgoyette struct sunxi_debe_softc *sc = device_private(self);
606 1.2.2.1 pgoyette struct wsdisplay_curpos *cp;
607 1.2.2.1 pgoyette uint32_t val;
608 1.2.2.1 pgoyette int enable;
609 1.2.2.1 pgoyette
610 1.1 jmcneill switch (cmd) {
611 1.2.2.1 pgoyette case WSDISPLAYIO_SVIDEO:
612 1.2.2.1 pgoyette enable = *(int *)data;
613 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
614 1.2.2.1 pgoyette if (enable) {
615 1.2.2.1 pgoyette if (val & SUNXI_DEBE_MODCTL_START_CTL) {
616 1.2.2.1 pgoyette /* already enabled */
617 1.2.2.1 pgoyette return 0;
618 1.2.2.1 pgoyette }
619 1.2.2.1 pgoyette } else {
620 1.2.2.1 pgoyette if ((val & SUNXI_DEBE_MODCTL_START_CTL) == 0) {
621 1.2.2.1 pgoyette /* already disabled */
622 1.2.2.1 pgoyette return 0;
623 1.2.2.1 pgoyette }
624 1.2.2.1 pgoyette }
625 1.2.2.1 pgoyette return fdt_endpoint_enable(sc->sc_out_ep, enable);
626 1.2.2.1 pgoyette case WSDISPLAYIO_GVIDEO:
627 1.2.2.1 pgoyette val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG);
628 1.2.2.1 pgoyette *(int *)data = !!(val & SUNXI_DEBE_MODCTL_LAY0_EN);
629 1.1 jmcneill return 0;
630 1.2.2.1 pgoyette case WSDISPLAYIO_GCURPOS:
631 1.2.2.1 pgoyette cp = data;
632 1.2.2.1 pgoyette cp->x = sc->sc_cursor_x;
633 1.2.2.1 pgoyette cp->y = sc->sc_cursor_y;
634 1.1 jmcneill return 0;
635 1.2.2.1 pgoyette case WSDISPLAYIO_SCURPOS:
636 1.2.2.1 pgoyette cp = data;
637 1.2.2.1 pgoyette return sunxi_debe_set_curpos(sc, cp->x, cp->y);
638 1.2.2.1 pgoyette case WSDISPLAYIO_GCURMAX:
639 1.2.2.1 pgoyette cp = data;
640 1.2.2.1 pgoyette cp->x = SUNXI_DEBE_CURMAX;
641 1.2.2.1 pgoyette cp->y = SUNXI_DEBE_CURMAX;
642 1.2.2.1 pgoyette return 0;
643 1.2.2.1 pgoyette case WSDISPLAYIO_SCURSOR:
644 1.2.2.1 pgoyette return sunxi_debe_set_cursor(sc, data);
645 1.1 jmcneill }
646 1.2.2.1 pgoyette
647 1.2.2.1 pgoyette return EPASSTHROUGH;
648 1.1 jmcneill }
649 1.1 jmcneill
650 1.2.2.1 pgoyette /* genfb attachement */
651 1.1 jmcneill
652 1.2.2.1 pgoyette struct sunxi_befb_softc {
653 1.2.2.1 pgoyette struct genfb_softc sc_gen;
654 1.2.2.1 pgoyette device_t sc_debedev;
655 1.2.2.1 pgoyette
656 1.2.2.1 pgoyette bus_dma_tag_t sc_dmat;
657 1.2.2.1 pgoyette bus_dma_segment_t *sc_dmasegs;
658 1.2.2.1 pgoyette int sc_ndmasegs;
659 1.2.2.1 pgoyette };
660 1.2.2.1 pgoyette
661 1.2.2.1 pgoyette static device_t sunxi_befb_consoledev = NULL;
662 1.2.2.1 pgoyette
663 1.2.2.1 pgoyette static int sunxi_befb_match(device_t, cfdata_t, void *);
664 1.2.2.1 pgoyette static void sunxi_befb_attach(device_t, device_t, void *);
665 1.2.2.1 pgoyette
666 1.2.2.1 pgoyette static int sunxi_befb_ioctl(void *, void *, u_long, void *, int, lwp_t *);
667 1.2.2.1 pgoyette static paddr_t sunxi_befb_mmap(void *, void *, off_t, int);
668 1.2.2.1 pgoyette static bool sunxi_befb_shutdown(device_t, int);
669 1.1 jmcneill
670 1.2.2.1 pgoyette CFATTACH_DECL_NEW(sunxi_befb, sizeof(struct sunxi_befb_softc),
671 1.2.2.1 pgoyette sunxi_befb_match, sunxi_befb_attach, NULL, NULL);
672 1.2.2.1 pgoyette
673 1.2.2.1 pgoyette static int
674 1.2.2.1 pgoyette sunxi_befb_match(device_t parent, cfdata_t cf, void *aux)
675 1.2.2.1 pgoyette {
676 1.2.2.1 pgoyette return 1;
677 1.1 jmcneill }
678 1.1 jmcneill
679 1.1 jmcneill static void
680 1.2.2.1 pgoyette sunxi_befb_attach(device_t parent, device_t self, void *aux)
681 1.1 jmcneill {
682 1.2.2.1 pgoyette struct sunxi_befb_softc *sc = device_private(self);
683 1.2.2.1 pgoyette struct sunxifb_attach_args * const afb = aux;
684 1.2.2.1 pgoyette prop_dictionary_t cfg = device_properties(self);
685 1.1 jmcneill struct genfb_ops ops;
686 1.1 jmcneill
687 1.2.2.1 pgoyette if (sunxi_befb_consoledev == NULL)
688 1.2.2.1 pgoyette sunxi_befb_consoledev = self;
689 1.1 jmcneill
690 1.2.2.1 pgoyette sc->sc_gen.sc_dev = self;
691 1.2.2.1 pgoyette sc->sc_debedev = parent;
692 1.2.2.1 pgoyette sc->sc_dmat = afb->afb_dmat;
693 1.2.2.1 pgoyette sc->sc_dmasegs = afb->afb_dmasegs;
694 1.2.2.1 pgoyette sc->sc_ndmasegs = afb->afb_ndmasegs;
695 1.2.2.1 pgoyette
696 1.2.2.1 pgoyette prop_dictionary_set_uint32(cfg, "width", afb->afb_width);
697 1.2.2.1 pgoyette prop_dictionary_set_uint32(cfg, "height", afb->afb_height);
698 1.2.2.1 pgoyette prop_dictionary_set_uint8(cfg, "depth", 32);
699 1.2.2.1 pgoyette prop_dictionary_set_uint16(cfg, "linebytes", afb->afb_width * 4);
700 1.2.2.1 pgoyette prop_dictionary_set_uint32(cfg, "address", 0);
701 1.2.2.1 pgoyette prop_dictionary_set_uint32(cfg, "virtual_address",
702 1.2.2.1 pgoyette (uintptr_t)afb->afb_fb);
703 1.1 jmcneill
704 1.1 jmcneill genfb_init(&sc->sc_gen);
705 1.1 jmcneill
706 1.1 jmcneill if (sc->sc_gen.sc_width == 0 || sc->sc_gen.sc_fbsize == 0) {
707 1.1 jmcneill aprint_normal(": disabled\n");
708 1.1 jmcneill return;
709 1.1 jmcneill }
710 1.1 jmcneill
711 1.2.2.1 pgoyette pmf_device_register1(self, NULL, NULL, sunxi_befb_shutdown);
712 1.1 jmcneill
713 1.1 jmcneill memset(&ops, 0, sizeof(ops));
714 1.2.2.1 pgoyette ops.genfb_ioctl = sunxi_befb_ioctl;
715 1.2.2.1 pgoyette ops.genfb_mmap = sunxi_befb_mmap;
716 1.2.2.1 pgoyette
717 1.2.2.1 pgoyette aprint_naive("\n");
718 1.1 jmcneill
719 1.1 jmcneill bool is_console = false;
720 1.2.2.1 pgoyette prop_dictionary_set_bool(cfg, "is_console", is_console);
721 1.1 jmcneill
722 1.1 jmcneill if (is_console)
723 1.2.2.1 pgoyette aprint_normal(": switching to framebuffer console\n");
724 1.2.2.1 pgoyette else
725 1.2.2.1 pgoyette aprint_normal("\n");
726 1.1 jmcneill
727 1.1 jmcneill genfb_attach(&sc->sc_gen, &ops);
728 1.1 jmcneill }
729 1.1 jmcneill
730 1.1 jmcneill static int
731 1.2.2.1 pgoyette sunxi_befb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l)
732 1.1 jmcneill {
733 1.2.2.1 pgoyette struct sunxi_befb_softc *sc = v;
734 1.2.2.1 pgoyette struct wsdisplayio_bus_id *busid;
735 1.2.2.1 pgoyette struct wsdisplayio_fbinfo *fbi;
736 1.2.2.1 pgoyette struct rasops_info *ri;
737 1.2.2.1 pgoyette int error;
738 1.1 jmcneill
739 1.2.2.1 pgoyette switch (cmd) {
740 1.2.2.1 pgoyette case WSDISPLAYIO_GTYPE:
741 1.2.2.1 pgoyette *(u_int *)data = WSDISPLAY_TYPE_ALLWINNER;
742 1.2.2.1 pgoyette return 0;
743 1.2.2.1 pgoyette case WSDISPLAYIO_GET_BUSID:
744 1.2.2.1 pgoyette busid = data;
745 1.2.2.1 pgoyette busid->bus_type = WSDISPLAYIO_BUS_SOC;
746 1.2.2.1 pgoyette return 0;
747 1.2.2.1 pgoyette case WSDISPLAYIO_GET_FBINFO:
748 1.2.2.1 pgoyette fbi = data;
749 1.2.2.1 pgoyette ri = &sc->sc_gen.vd.active->scr_ri;
750 1.2.2.1 pgoyette error = wsdisplayio_get_fbinfo(ri, fbi);
751 1.2.2.1 pgoyette if (error == 0) {
752 1.2.2.1 pgoyette fbi->fbi_flags |= WSFB_VRAM_IS_RAM;
753 1.2.2.1 pgoyette fbi->fbi_fbsize = sc->sc_dmasegs[0].ds_len;
754 1.2.2.1 pgoyette }
755 1.2.2.1 pgoyette return error;
756 1.2.2.1 pgoyette case WSDISPLAYIO_SVIDEO:
757 1.2.2.1 pgoyette case WSDISPLAYIO_GVIDEO:
758 1.2.2.1 pgoyette case WSDISPLAYIO_GCURPOS:
759 1.2.2.1 pgoyette case WSDISPLAYIO_SCURPOS:
760 1.2.2.1 pgoyette case WSDISPLAYIO_GCURMAX:
761 1.2.2.1 pgoyette case WSDISPLAYIO_SCURSOR:
762 1.2.2.1 pgoyette return sunxi_debe_ioctl(sc->sc_debedev, cmd, data);
763 1.2.2.1 pgoyette default:
764 1.2.2.1 pgoyette return EPASSTHROUGH;
765 1.2.2.1 pgoyette }
766 1.2.2.1 pgoyette }
767 1.2.2.1 pgoyette
768 1.2.2.1 pgoyette static paddr_t
769 1.2.2.1 pgoyette sunxi_befb_mmap(void *v, void *vs, off_t off, int prot)
770 1.2.2.1 pgoyette {
771 1.2.2.1 pgoyette struct sunxi_befb_softc *sc = v;
772 1.2.2.1 pgoyette
773 1.2.2.1 pgoyette if (off < 0 || off >= sc->sc_dmasegs[0].ds_len)
774 1.2.2.1 pgoyette return -1;
775 1.2.2.1 pgoyette
776 1.2.2.1 pgoyette return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dmasegs, sc->sc_ndmasegs,
777 1.2.2.1 pgoyette off, prot, BUS_DMA_PREFETCHABLE);
778 1.2.2.1 pgoyette }
779 1.2.2.1 pgoyette
780 1.2.2.1 pgoyette static bool
781 1.2.2.1 pgoyette sunxi_befb_shutdown(device_t self, int flags)
782 1.2.2.1 pgoyette {
783 1.2.2.1 pgoyette genfb_enable_polling(self);
784 1.2.2.1 pgoyette return true;
785 1.1 jmcneill }
786 1.1 jmcneill
787 1.1 jmcneill static void
788 1.2.2.1 pgoyette sunxi_befb_set_videomode(device_t dev, u_int width, u_int height)
789 1.1 jmcneill {
790 1.2.2.1 pgoyette struct sunxi_befb_softc *sc = device_private(dev);
791 1.1 jmcneill
792 1.2.2.1 pgoyette if (sc->sc_gen.sc_width != width || sc->sc_gen.sc_height != height) {
793 1.2.2.1 pgoyette device_printf(sc->sc_gen.sc_dev,
794 1.2.2.1 pgoyette "mode switching not yet supported\n");
795 1.1 jmcneill }
796 1.2.2.1 pgoyette }
797 1.1 jmcneill
798 1.2.2.1 pgoyette int
799 1.2.2.1 pgoyette sunxi_debe_pipeline(int phandle, bool active)
800 1.2.2.1 pgoyette {
801 1.2.2.1 pgoyette device_t dev;
802 1.2.2.1 pgoyette struct sunxi_debe_softc *sc;
803 1.2.2.1 pgoyette struct fdt_endpoint *ep;
804 1.2.2.1 pgoyette int i, error;
805 1.2.2.1 pgoyette
806 1.2.2.1 pgoyette if (!active)
807 1.2.2.1 pgoyette return EOPNOTSUPP;
808 1.2.2.1 pgoyette
809 1.2.2.1 pgoyette for (i = 0;;i++) {
810 1.2.2.1 pgoyette dev = device_find_by_driver_unit("sunxidebe", i);
811 1.2.2.1 pgoyette if (dev == NULL)
812 1.2.2.1 pgoyette return ENODEV;
813 1.2.2.1 pgoyette sc = device_private(dev);
814 1.2.2.1 pgoyette if (sc->sc_phandle == phandle)
815 1.2.2.1 pgoyette break;
816 1.1 jmcneill }
817 1.2.2.1 pgoyette aprint_normal("activate %s\n", device_xname(dev));
818 1.2.2.1 pgoyette if (clk_enable(sc->sc_clk_ahb) != 0 ||
819 1.2.2.1 pgoyette clk_enable(sc->sc_clk_mod) != 0) {
820 1.2.2.1 pgoyette aprint_error_dev(dev, "couldn't enable clocks\n");
821 1.2.2.1 pgoyette return EIO;
822 1.1 jmcneill }
823 1.2.2.1 pgoyette /* connect debd0 to tcon0, debe1 to tcon1 */
824 1.2.2.1 pgoyette ep = fdt_endpoint_get_from_index(&sc->sc_ports, SUNXI_PORT_OUTPUT,
825 1.2.2.1 pgoyette sc->sc_unit);
826 1.2.2.1 pgoyette if (ep == NULL) {
827 1.2.2.1 pgoyette aprint_error_dev(dev, "no output endpoint for %d\n",
828 1.2.2.1 pgoyette sc->sc_unit);
829 1.2.2.1 pgoyette return ENODEV;
830 1.1 jmcneill }
831 1.2.2.1 pgoyette error = fdt_endpoint_activate(ep, true);
832 1.2.2.1 pgoyette if (error == 0) {
833 1.2.2.1 pgoyette sc->sc_out_ep = ep;
834 1.2.2.1 pgoyette fdt_endpoint_enable(ep, true);
835 1.2.2.1 pgoyette }
836 1.2.2.1 pgoyette return error;
837 1.2.2.1 pgoyette }
838 1.1 jmcneill
839 1.2.2.1 pgoyette #if defined(SUNXI_DEBE_DEBUG)
840 1.2.2.1 pgoyette void
841 1.2.2.1 pgoyette sunxi_debe_dump_regs(int u)
842 1.2.2.1 pgoyette {
843 1.2.2.1 pgoyette static const struct {
844 1.2.2.1 pgoyette const char *name;
845 1.2.2.1 pgoyette uint16_t reg;
846 1.2.2.1 pgoyette } regs[] = {
847 1.2.2.1 pgoyette { "SUNXI_DEBE_MODCTL_REG", SUNXI_DEBE_MODCTL_REG},
848 1.2.2.1 pgoyette { "SUNXI_DEBE_BACKCOLOR_REG", SUNXI_DEBE_BACKCOLOR_REG},
849 1.2.2.1 pgoyette { "SUNXI_DEBE_DISSIZE_REG", SUNXI_DEBE_DISSIZE_REG},
850 1.2.2.1 pgoyette { "SUNXI_DEBE_LAYSIZE_REG", SUNXI_DEBE_LAYSIZE_REG},
851 1.2.2.1 pgoyette { "SUNXI_DEBE_LAYCOOR_REG", SUNXI_DEBE_LAYCOOR_REG},
852 1.2.2.1 pgoyette { "SUNXI_DEBE_LAYLINEWIDTH_REG", SUNXI_DEBE_LAYLINEWIDTH_REG},
853 1.2.2.1 pgoyette { "SUNXI_DEBE_LAYFB_L32ADD_REG", SUNXI_DEBE_LAYFB_L32ADD_REG},
854 1.2.2.1 pgoyette { "SUNXI_DEBE_LAYFB_H4ADD_REG", SUNXI_DEBE_LAYFB_H4ADD_REG},
855 1.2.2.1 pgoyette { "SUNXI_DEBE_REGBUFFCTL_REG", SUNXI_DEBE_REGBUFFCTL_REG},
856 1.2.2.1 pgoyette { "SUNXI_DEBE_CKMAX_REG", SUNXI_DEBE_CKMAX_REG},
857 1.2.2.1 pgoyette { "SUNXI_DEBE_CKMIN_REG", SUNXI_DEBE_CKMIN_REG},
858 1.2.2.1 pgoyette { "SUNXI_DEBE_CKCFG_REG", SUNXI_DEBE_CKCFG_REG},
859 1.2.2.1 pgoyette { "SUNXI_DEBE_ATTCTL0_REG", SUNXI_DEBE_ATTCTL0_REG},
860 1.2.2.1 pgoyette { "SUNXI_DEBE_ATTCTL1_REG", SUNXI_DEBE_ATTCTL1_REG},
861 1.2.2.1 pgoyette { "SUNXI_DEBE_HWCCTL_REG", SUNXI_DEBE_HWCCTL_REG},
862 1.2.2.1 pgoyette { "SUNXI_DEBE_HWCFBCTL_REG", SUNXI_DEBE_HWCFBCTL_REG},
863 1.2.2.1 pgoyette { "SUNXI_DEBE_WBCTL_REG", SUNXI_DEBE_WBCTL_REG},
864 1.2.2.1 pgoyette { "SUNXI_DEBE_WBADD_REG", SUNXI_DEBE_WBADD_REG},
865 1.2.2.1 pgoyette { "SUNXI_DEBE_WBLINEWIDTH_REG", SUNXI_DEBE_WBLINEWIDTH_REG},
866 1.2.2.1 pgoyette { "SUNXI_DEBE_IYUVCTL_REG", SUNXI_DEBE_IYUVCTL_REG},
867 1.2.2.1 pgoyette { "SUNXI_DEBE_IYUVADD_REG", SUNXI_DEBE_IYUVADD_REG},
868 1.2.2.1 pgoyette { "SUNXI_DEBE_IYUVLINEWIDTH_REG", SUNXI_DEBE_IYUVLINEWIDTH_REG},
869 1.2.2.1 pgoyette { "SUNXI_DEBE_YGCOEF_REG", SUNXI_DEBE_YGCOEF_REG},
870 1.2.2.1 pgoyette { "SUNXI_DEBE_YGCONS_REG", SUNXI_DEBE_YGCONS_REG},
871 1.2.2.1 pgoyette { "SUNXI_DEBE_URCOEF_REG", SUNXI_DEBE_URCOEF_REG},
872 1.2.2.1 pgoyette { "SUNXI_DEBE_URCONS_REG", SUNXI_DEBE_URCONS_REG},
873 1.2.2.1 pgoyette { "SUNXI_DEBE_VBCOEF_REG", SUNXI_DEBE_VBCOEF_REG},
874 1.2.2.1 pgoyette { "SUNXI_DEBE_VBCONS_REG", SUNXI_DEBE_VBCONS_REG},
875 1.2.2.1 pgoyette { "SUNXI_DEBE_OCCTL_REG", SUNXI_DEBE_OCCTL_REG},
876 1.2.2.1 pgoyette { "SUNXI_DEBE_OCRCOEF_REG", SUNXI_DEBE_OCRCOEF_REG},
877 1.2.2.1 pgoyette { "SUNXI_DEBE_OCRCONS_REG", SUNXI_DEBE_OCRCONS_REG},
878 1.2.2.1 pgoyette { "SUNXI_DEBE_OCGCOEF_REG", SUNXI_DEBE_OCGCOEF_REG},
879 1.2.2.1 pgoyette { "SUNXI_DEBE_OCGCONS_REG", SUNXI_DEBE_OCGCONS_REG},
880 1.2.2.1 pgoyette { "SUNXI_DEBE_OCBCOEF_REG", SUNXI_DEBE_OCBCOEF_REG},
881 1.2.2.1 pgoyette { "SUNXI_DEBE_OCBCONS_REG", SUNXI_DEBE_OCBCONS_REG},
882 1.2.2.1 pgoyette };
883 1.2.2.1 pgoyette struct sunxi_debe_softc *sc;
884 1.2.2.1 pgoyette device_t dev;
885 1.1 jmcneill
886 1.2.2.1 pgoyette dev = device_find_by_driver_unit("sunxidebe", u);
887 1.2.2.1 pgoyette if (dev == NULL)
888 1.1 jmcneill return;
889 1.2.2.1 pgoyette sc = device_private(dev);
890 1.1 jmcneill
891 1.2.2.1 pgoyette for (int i = 0; i < __arraycount(regs); i++) {
892 1.2.2.1 pgoyette printf("%s: 0x%08x\n", regs[i].name,
893 1.2.2.1 pgoyette DEBE_READ(sc, regs[i].reg));
894 1.1 jmcneill }
895 1.1 jmcneill }
896 1.2.2.1 pgoyette #endif
897