xref: /openbsd-src/sys/arch/armv7/omap/amdisplay.c (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1 /* $OpenBSD: amdisplay.c,v 1.17 2022/07/15 17:57:25 kettenis Exp $ */
2 /*
3  * Copyright (c) 2016 Ian Sutton <ians@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 
23 #include <dev/wscons/wsconsio.h>
24 #include <dev/wscons/wsdisplayvar.h>
25 #include <dev/rasops/rasops.h>
26 #include <dev/videomode/videomode.h>
27 #include <dev/videomode/edidvar.h>
28 
29 #include <dev/ofw/openfirm.h>
30 #include <dev/ofw/ofw_pinctrl.h>
31 #include <dev/ofw/fdt.h>
32 #include <machine/fdt.h>
33 
34 #include <armv7/omap/prcmvar.h>
35 #include <armv7/omap/amdisplayreg.h>
36 #include <armv7/omap/nxphdmivar.h>
37 
38 #ifdef LCD_DEBUG
39 #define str(X) #X
40 int lcd_dbg_thresh = 20;
41 #define DPRINTF(n,s)	do { if ((n) <= lcd_dbg_thresh) printf s; } while (0)
42 #else
43 #define DPRINTF(n,s)	do {} while (0)
44 #endif
45 
46 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
47 
48 #define LCD_MAX_PELCLK	170000		/* kHz */
49 #define LCD_MASTER_OSC	24000000	/* Hz */
50 #define LCD_M1_MAX	2048
51 #define LCD_M2_MAX	31
52 #define LCD_N_MAX	128
53 
54 #define HREAD4(sc, reg)							\
55 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
56 #define HWRITE4(sc, reg, val)						\
57 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
58 #define HSET4(sc, reg, bits)						\
59 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
60 #define HCLR4(sc, reg, bits)						\
61 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
62 
63 struct amdisplay_softc {
64 	struct device		sc_dev;
65 	bus_space_tag_t		sc_iot;
66 	bus_space_handle_t	sc_ioh;
67 	bus_dma_tag_t		sc_dmat;
68 	void			*sc_ih;
69 
70 	int			sc_flags;
71 #define LCD_RESET_PENDING	(1 << 0)
72 #define LCD_MODE_COMPAT		(1 << 1)
73 #define LCD_MODE_ALLOC		(1 << 2)
74 
75 	struct edid_info	sc_edid;
76 	struct videomode	*sc_active_mode;
77 	int			sc_active_depth;
78 
79 	bus_dmamap_t		sc_fb0_dma;
80 	bus_dma_segment_t	sc_fb0_dma_segs[1];
81 	void			*sc_fb0;
82 	int			sc_fb_dma_nsegs;
83 	bus_size_t		sc_fb_size;
84 
85 	struct rasops_info	sc_ro;
86 	struct wsscreen_descr	sc_wsd;
87 	struct wsscreen_list	sc_wsl;
88 	struct wsscreen_descr	*sc_scrlist[1];
89 };
90 
91 int	amdisplay_match(struct device *, void *, void *);
92 void	amdisplay_attach(struct device *, struct device *, void *);
93 int	amdisplay_detach(struct device *, int);
94 int	amdisplay_activate(struct device *, int);
95 int	amdisplay_intr(void *);
96 
97 int	amdisplay_ioctl(void *, u_long, caddr_t, int, struct proc *);
98 paddr_t	amdisplay_mmap(void *, off_t, int);
99 int	amdisplay_alloc_screen(void *, const struct wsscreen_descr *,
100 	    void **, int *, int *, uint32_t *);
101 
102 int	amdisplay_setup_dma(struct amdisplay_softc *);
103 void	amdisplay_conf_crt_timings(struct amdisplay_softc *);
104 void	amdisplay_calc_freq(uint64_t);
105 
106 struct wsdisplay_accessops amdisplay_accessops = {
107 	.ioctl = amdisplay_ioctl,
108 	.mmap = amdisplay_mmap,
109 	.alloc_screen = amdisplay_alloc_screen,
110 	.free_screen = rasops_free_screen,
111 	.show_screen = rasops_show_screen,
112 	.getchar = rasops_getchar,
113 	.load_font = rasops_load_font,
114 	.list_font = rasops_list_font,
115 };
116 
117 const struct cfattach amdisplay_ca = {
118 	sizeof(struct amdisplay_softc), amdisplay_match, amdisplay_attach,
119 	amdisplay_detach
120 };
121 
122 struct cfdriver amdisplay_cd = {
123 	NULL, "amdisplay", DV_DULL
124 };
125 
126 #ifdef LCD_DEBUG
127 void
128 preg(uint32_t reg, char *rn, struct amdisplay_softc *sc)
129 {
130 	uint32_t read;
131 
132 	read = HREAD4(sc, reg);
133 	DPRINTF(16, ("%s: %s: 0x%08x\n", DEVNAME(sc), rn, read));
134 }
135 
136 void
137 dumpregs(struct amdisplay_softc *sc)
138 {
139 	preg(LCD_PID, str(AMDISPLAY_PID), sc);
140 	preg(LCD_CTRL, str(AMDISPLAY_CTRL), sc);
141 	preg(LCD_RASTER_CTRL, str(AMDISPLAY_RASTER_CTRL), sc);
142 	preg(LCD_RASTER_TIMING_0, str(AMDISPLAY_RASTER_TIMING_0), sc);
143 	preg(LCD_RASTER_TIMING_1, str(AMDISPLAY_RASTER_TIMING_1), sc);
144 	preg(LCD_RASTER_TIMING_2, str(AMDISPLAY_RASTER_TIMING_2), sc);
145 	preg(LCD_RASTER_SUBPANEL, str(AMDISPLAY_RASTER_SUBPANEL), sc);
146 	preg(LCD_RASTER_SUBPANEL_2, str(AMDISPLAY_RASTER_SUBPANEL_2), sc);
147 	preg(LCD_LCDDMA_CTRL, str(AMDISPLAY_LCDDMA_CTRL), sc);
148 
149 	/* accessing these regs is liable to occur during CPU lockout period */
150 #if 0
151 	preg(LCD_LCDDMA_FB0_BASE, str(AMDISPLAY_LCDDMA_FB0_BASE), sc);
152 	preg(LCD_LCDDMA_FB0_CEILING, str(AMDISPLAY_LCDDMA_FB0_CEILING), sc);
153 	preg(LCD_LCDDMA_FB1_BASE, str(AMDISPLAY_LCDDMA_FB1_BASE), sc);
154 	preg(LCD_LCDDMA_FB1_CEILING, str(AMDISPLAY_LCDDMA_FB1_CEILING), sc);
155 #endif
156 
157 	preg(LCD_SYSCONFIG, str(AMDISPLAY_SYSCONFIG), sc);
158 	preg(LCD_IRQSTATUS_RAW, str(AMDISPLAY_IRQSTATUS_RAW), sc);
159 	preg(LCD_IRQSTATUS, str(AMDISPLAY_IRQSTATUS), sc);
160 	preg(LCD_IRQENABLE_SET, str(AMDISPLAY_IRQENABLE_SET), sc);
161 	preg(LCD_IRQENABLE_CLEAR, str(AMDISPLAY_IRQENABLE_CLEAR), sc);
162 	preg(LCD_CLKC_ENABLE, str(AMDISPLAY_CLKC_ENABLE), sc);
163 	preg(LCD_CLKC_RESET, str(AMDISPLAY_CLKC_RESET), sc);
164 }
165 #endif
166 
167 int
168 amdisplay_match(struct device *parent, void *v, void *aux)
169 {
170 	struct fdt_attach_args *faa = aux;
171 	return OF_is_compatible(faa->fa_node, "ti,am33xx-tilcdc");
172 }
173 
174 void
175 amdisplay_attach(struct device *parent, struct device *self, void *args)
176 {
177 	struct amdisplay_softc	*sc = (struct amdisplay_softc *) self;
178 	struct fdt_attach_args	*faa = args;
179 	struct wsemuldisplaydev_attach_args wsaa;
180 	uint64_t pel_clk = 0;
181 	uint32_t reg;
182 	uint8_t *edid_buf;
183 	int stride, i = 0;
184 
185 	sc->sc_iot  = faa->fa_iot;
186 	sc->sc_dmat = faa->fa_dmat;
187 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
188 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
189 		panic("%s: bus_space_map failed!", __func__);
190 
191 	/* enable clock module */
192 	prcm_enablemodule(PRCM_LCDC);
193 
194 	/* force ourselves out of standby/idle states */
195 	reg = HREAD4(sc, LCD_SYSCONFIG);
196 	reg &= ~(LCD_SYSCONFIG_STANDBYMODE | LCD_SYSCONFIG_IDLEMODE);
197 	reg |= (0x2 << LCD_SYSCONFIG_STANDBYMODE_SHAMT)
198 	    |  (0x2 << LCD_SYSCONFIG_IDLEMODE_SHAMT);
199 	HWRITE4(sc, LCD_SYSCONFIG, reg);
200 
201 	sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
202 	    amdisplay_intr, sc, DEVNAME(sc));
203 
204 	printf("\n");
205 
206 	/* read/parse EDID bits from TDA19988 HDMI PHY */
207 	edid_buf = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO);
208 	sc->sc_active_mode = malloc(sizeof(struct videomode), M_DEVBUF,
209 	    M_WAITOK | M_ZERO);
210 	sc->sc_flags |= LCD_MODE_ALLOC;
211 
212 	if (nxphdmi_get_edid(edid_buf, EDID_LENGTH) ||
213 	    edid_parse(edid_buf, &sc->sc_edid)) {
214 		printf("%s: no display attached.\n", DEVNAME(sc));
215 		free(edid_buf, M_DEVBUF, EDID_LENGTH);
216 		amdisplay_detach(self, 0);
217 		return;
218 	}
219 
220 	free(edid_buf, M_DEVBUF, EDID_LENGTH);
221 
222 #ifdef LCD_DEBUG
223 	edid_print(&sc->sc_edid);
224 #endif
225 
226 	/* determine max supported resolution our clock signal can handle */
227 	for (; i < sc->sc_edid.edid_nmodes - 1; i++) {
228 		if (sc->sc_edid.edid_modes[i].dot_clock < LCD_MAX_PELCLK &&
229 		    sc->sc_edid.edid_modes[i].dot_clock > pel_clk) {
230 			pel_clk = sc->sc_edid.edid_modes[i].dot_clock;
231 			memcpy(sc->sc_active_mode, &sc->sc_edid.edid_modes[i],
232 			    sizeof(struct videomode));
233 		}
234 	}
235 
236 	i = 0;
237 	printf("%s: %s :: %d kHz pclk\n", DEVNAME(sc),
238 	    sc->sc_active_mode->name, sc->sc_active_mode->dot_clock);
239 
240 	pel_clk *= 2000;
241 	amdisplay_calc_freq(pel_clk);
242 
243 	sc->sc_active_mode->flags |= VID_HSKEW;
244 	sc->sc_active_depth = 16;
245 
246 	/* configure DMA framebuffer */
247 	if (amdisplay_setup_dma(sc)) {
248 		printf("%s: couldn't allocate DMA framebuffer\n", DEVNAME(sc));
249 		amdisplay_detach(self, 0);
250 		return;
251 	}
252 
253 	/* setup rasops */
254 	stride = sc->sc_active_mode->hdisplay * sc->sc_active_depth / 8;
255 
256 	sc->sc_ro.ri_depth = sc->sc_active_depth;
257 	sc->sc_ro.ri_width = sc->sc_active_mode->hdisplay;
258 	sc->sc_ro.ri_height = sc->sc_active_mode->vdisplay;
259 	sc->sc_ro.ri_stride = stride;
260 	sc->sc_ro.ri_bits = sc->sc_fb0;
261 
262 	sc->sc_ro.ri_rpos = 0;
263 	sc->sc_ro.ri_rnum = 5;
264 	sc->sc_ro.ri_gpos = 5;
265 	sc->sc_ro.ri_gnum = 6;
266 	sc->sc_ro.ri_bpos = 11;
267 	sc->sc_ro.ri_bnum = 5;
268 	sc->sc_ro.ri_hw = sc;
269 	sc->sc_ro.ri_flg = RI_CENTER | RI_VCONS | RI_WRONLY |
270 	    RI_CLEAR | RI_FULLCLEAR;
271 
272 	if (rasops_init(&sc->sc_ro, 200, 200)) {
273 		printf("%s: no rasops\n", DEVNAME(sc));
274 		amdisplay_detach(self, 0);
275 		return;
276 	}
277 
278 	/* ensure controller is off */
279 	HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN);
280 	delay(100);
281 
282 	/* set clock divisor needed for 640x480 VGA timings */
283 	reg = HREAD4(sc, LCD_CTRL);
284 	reg &= ~LCD_CTRL_CLKDIV;
285 	reg |= (0x2 << LCD_CTRL_CLKDIV_SHAMT);
286 
287 	/* select raster mode & reset-on-underflow, write */
288 	reg |= LCD_CTRL_MODESEL;
289 	HWRITE4(sc, LCD_CTRL, reg);
290 
291 	/* set stn565 + active matrix + palette loading only mode, delay */
292 	reg = HREAD4(sc, LCD_RASTER_CTRL);
293 	reg &= 0xF8000C7C;
294 	reg |= (LCD_RASTER_CTRL_LCDTFT)
295 	    |  (0x02  << LCD_RASTER_CTRL_PALMODE_SHAMT)
296 	    |  (0xFF << LCD_RASTER_CTRL_REQDLY_SHAMT);
297 	HWRITE4(sc, LCD_RASTER_CTRL, reg);
298 
299 	/* set timing values */
300 	amdisplay_conf_crt_timings(sc);
301 
302 	/* configure HDMI transmitter (TDA19988) with our mode details */
303 	nxphdmi_set_videomode(sc->sc_active_mode);
304 
305 	/* latch pins/pads according to fdt node */
306 	pinctrl_byphandle(LCD_FDT_PHANDLE);
307 
308 	/* configure DMA transfer settings */
309 	reg = HREAD4(sc, LCD_LCDDMA_CTRL);
310 	reg &= ~(LCD_LCDDMA_CTRL_DMA_MASTER_PRIO
311 	    | LCD_LCDDMA_CTRL_TH_FIFO_READY
312 	    | LCD_LCDDMA_CTRL_BURST_SIZE
313 	    | LCD_LCDDMA_CTRL_BYTE_SWAP
314 	    | LCD_LCDDMA_CTRL_BIGENDIAN
315 	    | LCD_LCDDMA_CTRL_FRAME_MODE);
316 	reg |= (0x4 << LCD_LCDDMA_CTRL_BURST_SIZE_SHAMT)
317 	    |  LCD_LCDDMA_CTRL_FRAME_MODE;
318 	HWRITE4(sc, LCD_LCDDMA_CTRL, reg);
319 
320 	/* set framebuffer location + bounds */
321 	HWRITE4(sc, LCD_LCDDMA_FB0, sc->sc_fb0_dma_segs[0].ds_addr);
322 	HWRITE4(sc, LCD_LCDDMA_FB0_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr
323 	    + sc->sc_fb_size));
324 	HWRITE4(sc, LCD_LCDDMA_FB1, sc->sc_fb0_dma_segs[0].ds_addr);
325 	HWRITE4(sc, LCD_LCDDMA_FB1_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr
326 	    + sc->sc_fb_size));
327 
328 	/* enable all intrs. */
329 	reg = 0;
330 	reg |= (LCD_IRQ_EOF1 | LCD_IRQ_EOF0 | LCD_IRQ_PL | LCD_IRQ_FUF |
331 	        LCD_IRQ_ACB | LCD_IRQ_SYNC | LCD_IRQ_RR_DONE | LCD_IRQ_DONE);
332 
333 	HWRITE4(sc, LCD_IRQENABLE_SET, reg);
334 
335 	/* enable dma & core clocks */
336 	HSET4(sc, LCD_CLKC_ENABLE, LCD_CLKC_ENABLE_DMA_CLK_EN
337 	    | LCD_CLKC_ENABLE_CORE_CLK_EN
338 	    | LCD_CLKC_ENABLE_LIDD_CLK_EN);
339 
340 	/* perform controller clock reset */
341 	HSET4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST);
342 	delay(100);
343 	HCLR4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST);
344 
345 	/* configure wsdisplay descr. */
346 	strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
347 	sc->sc_wsd.capabilities = sc->sc_ro.ri_caps;
348 	sc->sc_wsd.nrows = sc->sc_ro.ri_rows;
349 	sc->sc_wsd.ncols = sc->sc_ro.ri_cols;
350 	sc->sc_wsd.textops = &sc->sc_ro.ri_ops;
351 	sc->sc_wsd.fontwidth = sc->sc_ro.ri_font->fontwidth;
352 	sc->sc_wsd.fontheight = sc->sc_ro.ri_font->fontheight;
353 
354 	sc->sc_scrlist[0] = &sc->sc_wsd;
355 	sc->sc_wsl.nscreens = 1;
356 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
357 
358 	/* attach console */
359 	memset(&wsaa, 0, sizeof(wsaa));
360 	wsaa.scrdata = &sc->sc_wsl;
361 	wsaa.accessops = &amdisplay_accessops;
362 	wsaa.accesscookie = &sc->sc_ro;
363 
364 	config_found_sm(self, &wsaa, wsemuldisplaydevprint,
365 	    wsemuldisplaydevsubmatch);
366 
367 	/* enable controller */
368 	HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN);
369 }
370 
371 int
372 amdisplay_detach(struct device *self, int flags)
373 {
374 	struct amdisplay_softc *sc = (struct amdisplay_softc *)self;
375 
376 	if (ISSET(sc->sc_flags, LCD_MODE_ALLOC))
377 		free(sc->sc_active_mode, M_DEVBUF, sizeof(struct videomode));
378 
379 	if (!sc->sc_fb0)
380 		return 0;
381 
382 	bus_dmamap_sync(sc->sc_dmat, sc->sc_fb0_dma, 0, sc->sc_fb_size,
383 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
384 
385 	bus_dmamap_unload(sc->sc_dmat, sc->sc_fb0_dma);
386 	bus_dmamem_unmap(sc->sc_dmat, (caddr_t)(sc->sc_fb0), sc->sc_fb_size);
387 	bus_dmamem_free(sc->sc_dmat, sc->sc_fb0_dma_segs, sc->sc_fb_dma_nsegs);
388 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_fb0_dma);
389 
390 	return 0;
391 }
392 
393 int
394 amdisplay_intr(void *arg)
395 {
396 	struct amdisplay_softc *sc = arg;
397 	uint32_t reg;
398 
399 	reg = HREAD4(sc, LCD_IRQSTATUS);
400 	HWRITE4(sc, LCD_IRQSTATUS, reg);
401 
402 	DPRINTF(25, ("%s: intr 0x%08x\n", DEVNAME(sc), reg));
403 
404 	if (ISSET(reg, LCD_IRQ_PL)) {
405 		DPRINTF(10, ("%s: palette loaded, irq: 0x%08x\n",
406 		    DEVNAME(sc), reg));
407 		HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN);
408 		delay(100);
409 		HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_PALMODE);
410 		HSET4(sc, LCD_RASTER_CTRL, 0x02 << LCD_RASTER_CTRL_PALMODE_SHAMT);
411 		HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN);
412 	}
413 
414 	if (ISSET(reg, LCD_IRQ_FUF)) {
415 		DPRINTF(15, ("%s: FIFO underflow\n", DEVNAME(sc)));
416 	}
417 
418 	if (ISSET(reg, LCD_IRQ_SYNC)) {
419 		sc->sc_flags |= LCD_RESET_PENDING;
420 		DPRINTF(18, ("%s: sync lost\n", DEVNAME(sc)));
421 	}
422 
423 	if (ISSET(reg, LCD_IRQ_RR_DONE)) {
424 		DPRINTF(21, ("%s: frame done\n", DEVNAME(sc)));
425 		HWRITE4(sc, LCD_LCDDMA_FB0, sc->sc_fb0_dma_segs[0].ds_addr);
426 		HWRITE4(sc, LCD_LCDDMA_FB0_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr
427 		    + sc->sc_fb_size) - 1);
428 	}
429 
430 	if (ISSET(reg, LCD_IRQ_EOF0)) {
431 		DPRINTF(21, ("%s: framebuffer 0 done\n", DEVNAME(sc)));
432 	}
433 
434 	if (ISSET(reg, LCD_IRQ_EOF1)) {
435 		DPRINTF(21, ("%s: framebuffer 1 done\n", DEVNAME(sc)));
436 	}
437 
438 	if (ISSET(reg, LCD_IRQ_DONE)) {
439 		if (ISSET(sc->sc_flags, LCD_RESET_PENDING)) {
440 			HWRITE4(sc, LCD_IRQSTATUS, 0xFFFFFFFF);
441 			HSET4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST);
442 			delay(10);
443 			HCLR4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST);
444 			HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN);
445 			sc->sc_flags &= ~LCD_RESET_PENDING;
446 		}
447 		DPRINTF(15, ("%s: last frame done\n", DEVNAME(sc)));
448 	}
449 
450 	if (ISSET(reg, LCD_IRQ_ACB)) {
451 		DPRINTF(15, ("%s: AC bias event\n", DEVNAME(sc)));
452 	}
453 
454 	HWRITE4(sc, LCD_IRQ_END, 0);
455 
456 	return 0;
457 }
458 
459 int
460 amdisplay_setup_dma(struct amdisplay_softc *sc)
461 {
462 	bus_size_t bsize;
463 
464 	bsize = (sc->sc_active_mode->hdisplay * sc->sc_active_mode->vdisplay
465 	    * sc->sc_active_depth) >> 3;
466 
467 	sc->sc_fb_size = bsize;
468 	sc->sc_fb_dma_nsegs = 1;
469 
470 	if (bus_dmamap_create(sc->sc_dmat, sc->sc_fb_size, sc->sc_fb_dma_nsegs,
471 	    sc->sc_fb_size, 0, BUS_DMA_NOWAIT, &(sc->sc_fb0_dma)))
472 		return -1;
473 
474 	if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_fb_size, 4, 0,
475 	    sc->sc_fb0_dma_segs, 1, &(sc->sc_fb_dma_nsegs),
476 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT))
477 		return -2;
478 
479 	if (bus_dmamem_map(sc->sc_dmat, sc->sc_fb0_dma_segs,
480 	    sc->sc_fb_dma_nsegs, sc->sc_fb_size, (caddr_t *)&(sc->sc_fb0),
481 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_NOCACHE))
482 		return -3;
483 
484 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_fb0_dma, sc->sc_fb0, bsize,
485 	    NULL, BUS_DMA_NOWAIT))
486 		return -4;
487 
488 	memset(sc->sc_fb0, 0, bsize);
489 
490 	bus_dmamap_sync(sc->sc_dmat, sc->sc_fb0_dma, 0, bsize,
491 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
492 
493 	return 0;
494 }
495 
496 void
497 amdisplay_conf_crt_timings(struct amdisplay_softc *sc)
498 {
499 	uint32_t timing0, timing1, timing2;
500 	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, width, height;
501 	struct videomode *m = sc->sc_active_mode;
502 
503 	timing0 = 0;
504 	timing1 = 0;
505 	timing2 = 0;
506 
507 	hbp = (m->htotal - m->hsync_end) - 1;
508 	hfp = (m->hsync_start - m->hdisplay) - 1;
509 	hsw = (m->hsync_end - m->hsync_start) - 1;
510 
511 	vbp = (m->vtotal - m->vsync_end);
512 	vfp = (m->vsync_start - m->vdisplay);
513 	vsw = (m->vsync_end - m->vsync_start) - 1;
514 
515 	height = m->vdisplay - 1;
516 	width = m->hdisplay - 1;
517 
518 	/* Horizontal back porch */
519 	timing0 |= (hbp & 0xff) << LCD_RASTER_TIMING_0_HBP_SHAMT;
520 	timing2 |= ((hbp >> 8) & 3) << LCD_RASTER_TIMING_2_HPB_HIGHBITS_SHAMT;
521 	/* Horizontal front porch */
522 	timing0 |= (hfp & 0xff) << LCD_RASTER_TIMING_0_HFP_SHAMT;
523 	timing2 |= ((hfp >> 8) & 3) << 0;
524 	/* Horizontal sync width */
525 	timing0 |= (hsw & 0x3f) << LCD_RASTER_TIMING_0_HSW_SHAMT;
526 	timing2 |= ((hsw >> 6) & 0xf) << LCD_RASTER_TIMING_2_HSW_HIGHBITS_SHAMT;
527 
528 	/* Vertical back porch, front porch, sync width */
529 	timing1 |= (vbp & 0xff) << LCD_RASTER_TIMING_1_VBP_SHAMT;
530 	timing1 |= (vfp & 0xff) << LCD_RASTER_TIMING_1_VFP_SHAMT;
531 	timing1 |= (vsw & 0x3f) << LCD_RASTER_TIMING_1_VSW_SHAMT;
532 
533 	/* Pixels per line */
534 	timing0 |= ((width >> 10) & 1)
535 	    << LCD_RASTER_TIMING_0_PPLMSB_SHAMT;
536 	timing0 |= ((width >> 4) & 0x3f)
537 	    << LCD_RASTER_TIMING_0_PPLLSB_SHAMT;
538 
539 	/* Lines per panel */
540 	timing1 |= (height & 0x3ff);
541 	timing2 |= ((height >> 10 ) & 1)
542 	    << LCD_RASTER_TIMING_2_LPP_B10_SHAMT;
543 
544 	/* waveform settings */
545 	timing2 |= LCD_RASTER_TIMING_2_PHSVS_ON_OFF;
546 	timing2 |= (0xff << LCD_RASTER_TIMING_2_ACBI_SHAMT);
547 
548 	if (!ISSET(m->flags, VID_NHSYNC))
549 		timing2 |= LCD_RASTER_TIMING_2_IHS;
550 	if (!ISSET(m->flags, VID_NVSYNC))
551 		timing2 |= LCD_RASTER_TIMING_2_IVS;
552 
553 	HWRITE4(sc, LCD_RASTER_TIMING_0, timing0);
554 	HWRITE4(sc, LCD_RASTER_TIMING_1, timing1);
555 	HWRITE4(sc, LCD_RASTER_TIMING_2, timing2);
556 }
557 
558 void
559 amdisplay_calc_freq(uint64_t freq)
560 {
561 	uint64_t mul, div, i, j, delta, min_delta;
562 
563 	min_delta = freq;
564 	for (i = 1; i < LCD_M1_MAX; i++) {
565 		for (j = 1; j < LCD_N_MAX; j++) {
566 			delta = abs(freq - i * (LCD_MASTER_OSC / j));
567 			if (delta < min_delta) {
568 				mul = i;
569 				div = j;
570 				min_delta = delta;
571 			}
572 			if (min_delta == 0)
573 				break;
574 		}
575 	}
576 	div--;
577 
578 	prcm_setclock(4, div);
579 	prcm_setclock(3, mul);
580 	prcm_setclock(5, 1);
581 }
582 
583 int
584 amdisplay_ioctl(void *sconf, u_long cmd, caddr_t data, int flat, struct proc *p)
585 {
586 	struct rasops_info *ri = sconf;
587 	struct wsdisplay_fbinfo	*wdf;
588 
589 	switch (cmd) {
590 	case WSDISPLAYIO_GTYPE:
591 		*(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
592 		return 0;
593 	case WSDISPLAYIO_GINFO:
594 		wdf = (struct wsdisplay_fbinfo *)data;
595 		wdf->width = ri->ri_width;
596 		wdf->height = ri->ri_height;
597 		wdf->depth = ri->ri_depth;
598 		wdf->stride = ri->ri_stride;
599 		wdf->offset = 0;
600 		wdf->cmsize = 0;
601 		break;
602 	case WSDISPLAYIO_LINEBYTES:
603 		*(u_int *)data = ri->ri_stride;
604 		break;
605 	case WSDISPLAYIO_SMODE:
606 		break;
607 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
608 		switch (ri->ri_depth) {
609 		case 32:
610 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
611 			break;
612 		case 24:
613 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_24;
614 			break;
615 		case 16:
616 			*(u_int *)data = WSDISPLAYIO_DEPTH_16;
617 			break;
618 		case 15:
619 			*(u_int *)data = WSDISPLAYIO_DEPTH_15;
620 			break;
621 		default:
622 			return -1;
623 		}
624 		break;
625 	default:
626 		return -1;
627 	}
628 
629 	return 0;
630 }
631 
632 paddr_t
633 amdisplay_mmap(void *sconf, off_t off, int prot)
634 {
635 	struct rasops_info *ri = sconf;
636 	struct amdisplay_softc *sc = ri->ri_hw;
637 
638 	if (off < 0 || off >= sc->sc_fb_size)
639 		return -1;
640 
641 	return bus_dmamem_mmap(sc->sc_dmat, &sc->sc_fb0_dma_segs[0],
642 	    sc->sc_fb_dma_nsegs, off, prot, BUS_DMA_COHERENT);
643 }
644 
645 int
646 amdisplay_alloc_screen(void *sconf, const struct wsscreen_descr *type,
647     void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
648 {
649 	return rasops_alloc_screen(sconf, cookiep, curxp, curyp, attrp);
650 }
651