1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012-2017 Oleksandr Tymoshenko <gonzo@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/arm/versatile/versatile_clcd.c 356110 2019-12-27 03:00:18Z kevans $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38#include <sys/rman.h>
39#include <sys/fbio.h>
40#include <sys/consio.h>
41#include <sys/kdb.h>
42
43#include <machine/bus.h>
44#include <machine/cpu.h>
45#include <machine/intr.h>
46
47#include <dev/fdt/fdt_common.h>
48#include <dev/ofw/openfirm.h>
49#include <dev/ofw/ofw_bus.h>
50#include <dev/ofw/ofw_bus_subr.h>
51
52#include <dev/fb/fbreg.h>
53#include <dev/syscons/syscons.h>
54
55#include <arm/versatile/versatile_scm.h>
56
57#include <machine/bus.h>
58
59#define	PL110_VENDOR_ARM926PXP	1
60
61#define	CLCD_MODE_RGB888	0x0
62#define	CLCD_MODE_RGB555	0x01
63#define	CLCD_MODE_RBG565	0x02
64#define	CLCD_MODE_RGB565	0x03
65
66#define	CLCDC_TIMING0		0x00
67#define	CLCDC_TIMING1		0x04
68#define	CLCDC_TIMING2		0x08
69#define	CLCDC_TIMING3		0x0C
70#define	CLCDC_TIMING3		0x0C
71#define	CLCDC_UPBASE		0x10
72#define	CLCDC_LPBASE		0x14
73#ifdef PL110_VENDOR_ARM926PXP
74#define	CLCDC_CONTROL		0x18
75#define	CLCDC_IMSC		0x1C
76#else
77#define	CLCDC_IMSC		0x18
78#define	CLCDC_CONTROL		0x1C
79#endif
80#define		CONTROL_WATERMARK	(1 << 16)
81#define		CONTROL_VCOMP_VS	(0 << 12)
82#define		CONTROL_VCOMP_BP	(1 << 12)
83#define		CONTROL_VCOMP_SAV	(2 << 12)
84#define		CONTROL_VCOMP_FP	(3 << 12)
85#define		CONTROL_PWR		(1 << 11)
86#define		CONTROL_BEPO		(1 << 10)
87#define		CONTROL_BEBO		(1 << 9)
88#define		CONTROL_BGR		(1 << 8)
89#define		CONTROL_DUAL		(1 << 7)
90#define		CONTROL_MONO8		(1 << 6)
91#define		CONTROL_TFT		(1 << 5)
92#define		CONTROL_BW		(1 << 4)
93#define		CONTROL_BPP1		(0x00 << 1)
94#define		CONTROL_BPP2		(0x01 << 1)
95#define		CONTROL_BPP4		(0x02 << 1)
96#define		CONTROL_BPP8		(0x03 << 1)
97#define		CONTROL_BPP16		(0x04 << 1)
98#define		CONTROL_BPP24		(0x05 << 1)
99#define		CONTROL_EN	(1 << 0)
100#define	CLCDC_RIS		0x20
101#define	CLCDC_MIS		0x24
102#define		INTR_MBERR		(1 << 4)
103#define		INTR_VCOMP		(1 << 3)
104#define		INTR_LNB		(1 << 2)
105#define		INTR_FUF		(1 << 1)
106#define	CLCDC_ICR		0x28
107
108#ifdef DEBUG
109#define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
110    printf(fmt,##args); } while (0)
111#else
112#define dprintf(fmt, args...)
113#endif
114
115#define	versatile_clcdc_read_4(sc, reg)	\
116	bus_read_4((sc)->mem_res, (reg))
117#define	versatile_clcdc_write_4(sc, reg, val)	\
118	bus_write_4((sc)->mem_res, (reg), (val))
119
120struct versatile_clcdc_softc {
121	struct resource*	mem_res;
122
123	struct mtx		mtx;
124
125	int			width;
126	int			height;
127	int			mode;
128
129	bus_dma_tag_t		dma_tag;
130	bus_dmamap_t		dma_map;
131	bus_addr_t		fb_phys;
132	uint8_t			*fb_base;
133
134};
135
136struct video_adapter_softc {
137	/* Videoadpater part */
138	video_adapter_t	va;
139	int		console;
140
141	intptr_t	fb_addr;
142	unsigned int	fb_size;
143
144	unsigned int	height;
145	unsigned int	width;
146	unsigned int	depth;
147	unsigned int	stride;
148
149	unsigned int	xmargin;
150	unsigned int	ymargin;
151
152	unsigned char	*font;
153	int		initialized;
154};
155
156struct argb {
157	uint8_t		a;
158	uint8_t		r;
159	uint8_t		g;
160	uint8_t		b;
161};
162
163static struct argb versatilefb_palette[16] = {
164	{0x00, 0x00, 0x00, 0x00},
165	{0x00, 0x00, 0x00, 0xaa},
166	{0x00, 0x00, 0xaa, 0x00},
167	{0x00, 0x00, 0xaa, 0xaa},
168	{0x00, 0xaa, 0x00, 0x00},
169	{0x00, 0xaa, 0x00, 0xaa},
170	{0x00, 0xaa, 0x55, 0x00},
171	{0x00, 0xaa, 0xaa, 0xaa},
172	{0x00, 0x55, 0x55, 0x55},
173	{0x00, 0x55, 0x55, 0xff},
174	{0x00, 0x55, 0xff, 0x55},
175	{0x00, 0x55, 0xff, 0xff},
176	{0x00, 0xff, 0x55, 0x55},
177	{0x00, 0xff, 0x55, 0xff},
178	{0x00, 0xff, 0xff, 0x55},
179	{0x00, 0xff, 0xff, 0xff}
180};
181
182/* mouse pointer from dev/syscons/scgfbrndr.c */
183static u_char mouse_pointer[16] = {
184        0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
185        0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
186};
187
188#define FB_WIDTH		640
189#define FB_HEIGHT		480
190#define FB_DEPTH		16
191
192#define	VERSATILE_FONT_HEIGHT	16
193
194static struct video_adapter_softc va_softc;
195
196static int versatilefb_configure(int);
197static void versatilefb_update_margins(video_adapter_t *adp);
198
199static void
200versatile_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
201{
202	bus_addr_t *addr;
203
204	if (err)
205		return;
206
207	addr = (bus_addr_t*)arg;
208	*addr = segs[0].ds_addr;
209}
210
211static int
212versatile_clcdc_probe(device_t dev)
213{
214
215	if (!ofw_bus_status_okay(dev))
216		return (ENXIO);
217
218	if (ofw_bus_is_compatible(dev, "arm,pl110")) {
219		device_set_desc(dev, "PL110 CLCD controller");
220		return (BUS_PROBE_DEFAULT);
221	}
222
223	return (ENXIO);
224}
225
226static int
227versatile_clcdc_attach(device_t dev)
228{
229	struct versatile_clcdc_softc *sc = device_get_softc(dev);
230	struct video_adapter_softc *va_sc = &va_softc;
231	int err, rid;
232	uint32_t reg;
233	int clcdid;
234	int dma_size;
235
236	/* Request memory resources */
237	rid = 0;
238	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
239	if (sc->mem_res == NULL) {
240		device_printf(dev, "could not allocate memory resources\n");
241		return (ENXIO);
242	}
243
244	err = versatile_scm_reg_read_4(SCM_CLCD, &reg);
245	if (err) {
246		device_printf(dev, "failed to read SCM register\n");
247		goto fail;
248	}
249	clcdid = (reg >> SCM_CLCD_CLCDID_SHIFT) & SCM_CLCD_CLCDID_MASK;
250	switch (clcdid) {
251		case 31:
252			device_printf(dev, "QEMU VGA 640x480\n");
253			sc->width = 640;
254			sc->height = 480;
255			break;
256		default:
257			device_printf(dev, "Unsupported: %d\n", clcdid);
258			goto fail;
259	}
260
261	reg &= ~SCM_CLCD_LCD_MODE_MASK;
262	reg |= CLCD_MODE_RGB565;
263	sc->mode = CLCD_MODE_RGB565;
264	versatile_scm_reg_write_4(SCM_CLCD, reg);
265 	dma_size = sc->width*sc->height*2;
266
267 	/*
268	 * Power on LCD
269	 */
270	reg |= SCM_CLCD_PWR3V5VSWITCH | SCM_CLCD_NLCDIOON;
271	versatile_scm_reg_write_4(SCM_CLCD, reg);
272
273	/*
274	 * XXX: hardcoded timing for VGA. For other modes/panels
275	 * we need to keep table of timing register values
276	 */
277	/*
278	 * XXX: set SYS_OSC1
279	 */
280	versatile_clcdc_write_4(sc, CLCDC_TIMING0, 0x3F1F3F9C);
281	versatile_clcdc_write_4(sc, CLCDC_TIMING1, 0x090B61DF);
282	versatile_clcdc_write_4(sc, CLCDC_TIMING2, 0x067F1800);
283	/* XXX: timing 3? */
284
285	/*
286	 * Now allocate framebuffer memory
287	 */
288	err = bus_dma_tag_create(
289	    bus_get_dma_tag(dev),
290	    4, 0,		/* alignment, boundary */
291	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
292	    BUS_SPACE_MAXADDR,		/* highaddr */
293	    NULL, NULL,			/* filter, filterarg */
294	    dma_size, 1,		/* maxsize, nsegments */
295	    dma_size, 0,		/* maxsegsize, flags */
296	    NULL, NULL,			/* lockfunc, lockarg */
297	    &sc->dma_tag);
298
299	err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_base,
300	    0, &sc->dma_map);
301	if (err) {
302		device_printf(dev, "cannot allocate framebuffer\n");
303		goto fail;
304	}
305
306	err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_base,
307	    dma_size, versatile_fb_dmamap_cb, &sc->fb_phys, BUS_DMA_NOWAIT);
308
309	if (err) {
310		device_printf(dev, "cannot load DMA map\n");
311		goto fail;
312	}
313
314	/* Make sure it's blank */
315	memset(sc->fb_base, 0x00, dma_size);
316
317	versatile_clcdc_write_4(sc, CLCDC_UPBASE, sc->fb_phys);
318
319	err = (sc_attach_unit(device_get_unit(dev),
320	    device_get_flags(dev) | SC_AUTODETECT_KBD));
321
322	if (err) {
323		device_printf(dev, "failed to attach syscons\n");
324		goto fail;
325	}
326
327	/*
328	 * XXX: hardcoded for VGA
329	 */
330	reg = CONTROL_VCOMP_BP | CONTROL_TFT | CONTROL_BGR | CONTROL_EN;
331	reg |= CONTROL_BPP16;
332	versatile_clcdc_write_4(sc, CLCDC_CONTROL, reg);
333	DELAY(20);
334	reg |= CONTROL_PWR;
335	versatile_clcdc_write_4(sc, CLCDC_CONTROL, reg);
336
337	va_sc->fb_addr = (vm_offset_t)sc->fb_base;
338	va_sc->fb_size = dma_size;
339	va_sc->width = sc->width;
340	va_sc->height = sc->height;
341	va_sc->depth = 16;
342	va_sc->stride = sc->width * 2;
343	versatilefb_update_margins(&va_sc->va);
344
345	return (0);
346
347fail:
348	if (sc->fb_base)
349		bus_dmamem_free(sc->dma_tag, sc->fb_base, sc->dma_map);
350	if (sc->dma_tag)
351		bus_dma_tag_destroy(sc->dma_tag);
352	return (err);
353}
354
355static device_method_t versatile_clcdc_methods[] = {
356	DEVMETHOD(device_probe,		versatile_clcdc_probe),
357	DEVMETHOD(device_attach,	versatile_clcdc_attach),
358
359	DEVMETHOD_END
360};
361
362static driver_t versatile_clcdc_driver = {
363	"clcdc",
364	versatile_clcdc_methods,
365	sizeof(struct versatile_clcdc_softc),
366};
367
368static devclass_t versatile_clcdc_devclass;
369
370DRIVER_MODULE(versatile_clcdc, simplebus, versatile_clcdc_driver, versatile_clcdc_devclass, 0, 0);
371
372/*
373 * Video driver routines and glue.
374 */
375static vi_probe_t		versatilefb_probe;
376static vi_init_t		versatilefb_init;
377static vi_get_info_t		versatilefb_get_info;
378static vi_query_mode_t		versatilefb_query_mode;
379static vi_set_mode_t		versatilefb_set_mode;
380static vi_save_font_t		versatilefb_save_font;
381static vi_load_font_t		versatilefb_load_font;
382static vi_show_font_t		versatilefb_show_font;
383static vi_save_palette_t	versatilefb_save_palette;
384static vi_load_palette_t	versatilefb_load_palette;
385static vi_set_border_t		versatilefb_set_border;
386static vi_save_state_t		versatilefb_save_state;
387static vi_load_state_t		versatilefb_load_state;
388static vi_set_win_org_t		versatilefb_set_win_org;
389static vi_read_hw_cursor_t	versatilefb_read_hw_cursor;
390static vi_set_hw_cursor_t	versatilefb_set_hw_cursor;
391static vi_set_hw_cursor_shape_t	versatilefb_set_hw_cursor_shape;
392static vi_blank_display_t	versatilefb_blank_display;
393static vi_mmap_t		versatilefb_mmap;
394static vi_ioctl_t		versatilefb_ioctl;
395static vi_clear_t		versatilefb_clear;
396static vi_fill_rect_t		versatilefb_fill_rect;
397static vi_bitblt_t		versatilefb_bitblt;
398static vi_diag_t		versatilefb_diag;
399static vi_save_cursor_palette_t	versatilefb_save_cursor_palette;
400static vi_load_cursor_palette_t	versatilefb_load_cursor_palette;
401static vi_copy_t		versatilefb_copy;
402static vi_putp_t		versatilefb_putp;
403static vi_putc_t		versatilefb_putc;
404static vi_puts_t		versatilefb_puts;
405static vi_putm_t		versatilefb_putm;
406
407static video_switch_t versatilefbvidsw = {
408	.probe			= versatilefb_probe,
409	.init			= versatilefb_init,
410	.get_info		= versatilefb_get_info,
411	.query_mode		= versatilefb_query_mode,
412	.set_mode		= versatilefb_set_mode,
413	.save_font		= versatilefb_save_font,
414	.load_font		= versatilefb_load_font,
415	.show_font		= versatilefb_show_font,
416	.save_palette		= versatilefb_save_palette,
417	.load_palette		= versatilefb_load_palette,
418	.set_border		= versatilefb_set_border,
419	.save_state		= versatilefb_save_state,
420	.load_state		= versatilefb_load_state,
421	.set_win_org		= versatilefb_set_win_org,
422	.read_hw_cursor		= versatilefb_read_hw_cursor,
423	.set_hw_cursor		= versatilefb_set_hw_cursor,
424	.set_hw_cursor_shape	= versatilefb_set_hw_cursor_shape,
425	.blank_display		= versatilefb_blank_display,
426	.mmap			= versatilefb_mmap,
427	.ioctl			= versatilefb_ioctl,
428	.clear			= versatilefb_clear,
429	.fill_rect		= versatilefb_fill_rect,
430	.bitblt			= versatilefb_bitblt,
431	.diag			= versatilefb_diag,
432	.save_cursor_palette	= versatilefb_save_cursor_palette,
433	.load_cursor_palette	= versatilefb_load_cursor_palette,
434	.copy			= versatilefb_copy,
435	.putp			= versatilefb_putp,
436	.putc			= versatilefb_putc,
437	.puts			= versatilefb_puts,
438	.putm			= versatilefb_putm,
439};
440
441VIDEO_DRIVER(versatilefb, versatilefbvidsw, versatilefb_configure);
442
443static vr_init_t clcdr_init;
444static vr_clear_t clcdr_clear;
445static vr_draw_border_t clcdr_draw_border;
446static vr_draw_t clcdr_draw;
447static vr_set_cursor_t clcdr_set_cursor;
448static vr_draw_cursor_t clcdr_draw_cursor;
449static vr_blink_cursor_t clcdr_blink_cursor;
450static vr_set_mouse_t clcdr_set_mouse;
451static vr_draw_mouse_t clcdr_draw_mouse;
452
453/*
454 * We use our own renderer; this is because we must emulate a hardware
455 * cursor.
456 */
457static sc_rndr_sw_t clcdrend = {
458	clcdr_init,
459	clcdr_clear,
460	clcdr_draw_border,
461	clcdr_draw,
462	clcdr_set_cursor,
463	clcdr_draw_cursor,
464	clcdr_blink_cursor,
465	clcdr_set_mouse,
466	clcdr_draw_mouse
467};
468
469RENDERER(versatilefb, 0, clcdrend, gfb_set);
470RENDERER_MODULE(versatilefb, gfb_set);
471
472static void
473clcdr_init(scr_stat* scp)
474{
475}
476
477static void
478clcdr_clear(scr_stat* scp, int c, int attr)
479{
480}
481
482static void
483clcdr_draw_border(scr_stat* scp, int color)
484{
485}
486
487static void
488clcdr_draw(scr_stat* scp, int from, int count, int flip)
489{
490	video_adapter_t* adp = scp->sc->adp;
491	int i, c, a;
492
493	if (!flip) {
494		/* Normal printing */
495		vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
496	} else {
497		/* This is for selections and such: invert the color attribute */
498		for (i = count; i-- > 0; ++from) {
499			c = sc_vtb_getc(&scp->vtb, from);
500			a = sc_vtb_geta(&scp->vtb, from) >> 8;
501			vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
502		}
503	}
504}
505
506static void
507clcdr_set_cursor(scr_stat* scp, int base, int height, int blink)
508{
509}
510
511static void
512clcdr_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
513{
514	video_adapter_t* adp = scp->sc->adp;
515	struct video_adapter_softc *sc;
516	int row, col;
517	uint8_t *addr;
518	int i,j;
519
520	sc = (struct video_adapter_softc *)adp;
521
522	if (scp->curs_attr.height <= 0)
523		return;
524
525	if (sc->fb_addr == 0)
526		return;
527
528	if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
529		return;
530
531	/* calculate the coordinates in the video buffer */
532	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
533	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
534
535	addr = (uint8_t *)sc->fb_addr
536	    + (row + sc->ymargin)*(sc->stride)
537	    + (sc->depth/8) * (col + sc->xmargin);
538
539	/* our cursor consists of simply inverting the char under it */
540	for (i = 0; i < adp->va_info.vi_cheight; i++) {
541		for (j = 0; j < adp->va_info.vi_cwidth; j++) {
542
543			addr[2*j] ^= 0xff;
544			addr[2*j + 1] ^= 0xff;
545		}
546
547		addr += sc->stride;
548	}
549}
550
551static void
552clcdr_blink_cursor(scr_stat* scp, int at, int flip)
553{
554}
555
556static void
557clcdr_set_mouse(scr_stat* scp)
558{
559}
560
561static void
562clcdr_draw_mouse(scr_stat* scp, int x, int y, int on)
563{
564	vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
565
566}
567
568static uint16_t versatilefb_static_window[ROW*COL];
569extern u_char dflt_font_16[];
570
571/*
572 * Update videoadapter settings after changing resolution
573 */
574static void
575versatilefb_update_margins(video_adapter_t *adp)
576{
577	struct video_adapter_softc *sc;
578	video_info_t *vi;
579
580	sc = (struct video_adapter_softc *)adp;
581	vi = &adp->va_info;
582
583	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
584	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
585}
586
587static int
588versatilefb_configure(int flags)
589{
590	struct video_adapter_softc *va_sc;
591
592	va_sc = &va_softc;
593
594	if (va_sc->initialized)
595		return (0);
596
597	va_sc->width = FB_WIDTH;
598	va_sc->height = FB_HEIGHT;
599	va_sc->depth = FB_DEPTH;
600
601	versatilefb_init(0, &va_sc->va, 0);
602
603	va_sc->initialized = 1;
604
605	return (0);
606}
607
608static int
609versatilefb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
610{
611
612	return (0);
613}
614
615static int
616versatilefb_init(int unit, video_adapter_t *adp, int flags)
617{
618	struct video_adapter_softc *sc;
619	video_info_t *vi;
620
621	sc = (struct video_adapter_softc *)adp;
622	vi = &adp->va_info;
623
624	vid_init_struct(adp, "versatilefb", -1, unit);
625
626	sc->font = dflt_font_16;
627	vi->vi_cheight = VERSATILE_FONT_HEIGHT;
628	vi->vi_cwidth = 8;
629
630	vi->vi_width = sc->width/8;
631	vi->vi_height = sc->height/vi->vi_cheight;
632
633	/*
634	 * Clamp width/height to syscons maximums
635	 */
636	if (vi->vi_width > COL)
637		vi->vi_width = COL;
638	if (vi->vi_height > ROW)
639		vi->vi_height = ROW;
640
641	sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
642	sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
643
644	adp->va_window = (vm_offset_t) versatilefb_static_window;
645	adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
646
647	vid_register(&sc->va);
648
649	return (0);
650}
651
652static int
653versatilefb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
654{
655	bcopy(&adp->va_info, info, sizeof(*info));
656	return (0);
657}
658
659static int
660versatilefb_query_mode(video_adapter_t *adp, video_info_t *info)
661{
662	return (0);
663}
664
665static int
666versatilefb_set_mode(video_adapter_t *adp, int mode)
667{
668	return (0);
669}
670
671static int
672versatilefb_save_font(video_adapter_t *adp, int page, int size, int width,
673    u_char *data, int c, int count)
674{
675	return (0);
676}
677
678static int
679versatilefb_load_font(video_adapter_t *adp, int page, int size, int width,
680    u_char *data, int c, int count)
681{
682	struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
683
684	sc->font = data;
685
686	return (0);
687}
688
689static int
690versatilefb_show_font(video_adapter_t *adp, int page)
691{
692	return (0);
693}
694
695static int
696versatilefb_save_palette(video_adapter_t *adp, u_char *palette)
697{
698	return (0);
699}
700
701static int
702versatilefb_load_palette(video_adapter_t *adp, u_char *palette)
703{
704	return (0);
705}
706
707static int
708versatilefb_set_border(video_adapter_t *adp, int border)
709{
710	return (versatilefb_blank_display(adp, border));
711}
712
713static int
714versatilefb_save_state(video_adapter_t *adp, void *p, size_t size)
715{
716	return (0);
717}
718
719static int
720versatilefb_load_state(video_adapter_t *adp, void *p)
721{
722	return (0);
723}
724
725static int
726versatilefb_set_win_org(video_adapter_t *adp, off_t offset)
727{
728	return (0);
729}
730
731static int
732versatilefb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
733{
734	*col = *row = 0;
735
736	return (0);
737}
738
739static int
740versatilefb_set_hw_cursor(video_adapter_t *adp, int col, int row)
741{
742
743	return (0);
744}
745
746static int
747versatilefb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
748    int celsize, int blink)
749{
750	return (0);
751}
752
753static int
754versatilefb_blank_display(video_adapter_t *adp, int mode)
755{
756
757	struct video_adapter_softc *sc;
758
759	sc = (struct video_adapter_softc *)adp;
760	if (sc && sc->fb_addr)
761		memset((void*)sc->fb_addr, 0, sc->fb_size);
762
763	return (0);
764}
765
766static int
767versatilefb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
768    int prot, vm_memattr_t *memattr)
769{
770	struct video_adapter_softc *sc;
771
772	sc = (struct video_adapter_softc *)adp;
773
774	/*
775	 * This might be a legacy VGA mem request: if so, just point it at the
776	 * framebuffer, since it shouldn't be touched
777	 */
778	if (offset < sc->stride*sc->height) {
779		*paddr = sc->fb_addr + offset;
780		return (0);
781	}
782
783	return (EINVAL);
784}
785
786static int
787versatilefb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
788{
789
790	return (0);
791}
792
793static int
794versatilefb_clear(video_adapter_t *adp)
795{
796
797	return (versatilefb_blank_display(adp, 0));
798}
799
800static int
801versatilefb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
802{
803
804	return (0);
805}
806
807static int
808versatilefb_bitblt(video_adapter_t *adp, ...)
809{
810
811	return (0);
812}
813
814static int
815versatilefb_diag(video_adapter_t *adp, int level)
816{
817
818	return (0);
819}
820
821static int
822versatilefb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
823{
824
825	return (0);
826}
827
828static int
829versatilefb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
830{
831
832	return (0);
833}
834
835static int
836versatilefb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
837{
838
839	return (0);
840}
841
842static int
843versatilefb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
844    int size, int bpp, int bit_ltor, int byte_ltor)
845{
846
847	return (0);
848}
849
850static int
851versatilefb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
852{
853	struct video_adapter_softc *sc;
854	int row;
855	int col;
856	int i, j, k;
857	uint8_t *addr;
858	u_char *p;
859	uint8_t fg, bg, color;
860	uint16_t rgb;
861
862	sc = (struct video_adapter_softc *)adp;
863
864	if (sc->fb_addr == 0)
865		return (0);
866
867	if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
868		return (0);
869
870	row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
871	col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
872	p = sc->font + c*VERSATILE_FONT_HEIGHT;
873	addr = (uint8_t *)sc->fb_addr
874	    + (row + sc->ymargin)*(sc->stride)
875	    + (sc->depth/8) * (col + sc->xmargin);
876
877	fg = a & 0xf ;
878	bg = (a >> 4) & 0xf;
879
880	for (i = 0; i < VERSATILE_FONT_HEIGHT; i++) {
881		for (j = 0, k = 7; j < 8; j++, k--) {
882			if ((p[i] & (1 << k)) == 0)
883				color = bg;
884			else
885				color = fg;
886
887			switch (sc->depth) {
888			case 16:
889				rgb = (versatilefb_palette[color].r >> 3) << 11;
890				rgb |= (versatilefb_palette[color].g >> 2) << 5;
891				rgb |= (versatilefb_palette[color].b >> 3);
892				addr[2*j] = rgb & 0xff;
893				addr[2*j + 1] = (rgb >> 8) & 0xff;
894			default:
895				/* Not supported yet */
896				break;
897			}
898		}
899
900		addr += (sc->stride);
901	}
902
903        return (0);
904}
905
906static int
907versatilefb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
908{
909	int i;
910
911	for (i = 0; i < len; i++)
912		versatilefb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
913
914	return (0);
915}
916
917static int
918versatilefb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
919    uint32_t pixel_mask, int size, int width)
920{
921
922	return (0);
923}
924