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