1146482Smarius/*-
2146482Smarius * Copyright (c) 2002 Bang Jun-Young
3191076Smarius * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
4146482Smarius * All rights reserved.
5146482Smarius *
6146482Smarius * Redistribution and use in source and binary forms, with or without
7146482Smarius * modification, are permitted provided that the following conditions
8146482Smarius * are met:
9146482Smarius * 1. Redistributions of source code must retain the above copyright
10146482Smarius *    notice, this list of conditions and the following disclaimer.
11146482Smarius * 2. Redistributions in binary form must reproduce the above copyright
12146482Smarius *    notice, this list of conditions and the following disclaimer in the
13146482Smarius *    documentation and/or other materials provided with the distribution.
14146482Smarius * 3. The name of the author may not be used to endorse or promote products
15146482Smarius *    derived from this software without specific prior written permission.
16146482Smarius *
17146482Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18146482Smarius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19146482Smarius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20146482Smarius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21146482Smarius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22146482Smarius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23146482Smarius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24146482Smarius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25146482Smarius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26146482Smarius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27146482Smarius *
28146482Smarius *	from: NetBSD: machfb.c,v 1.23 2005/03/07 21:45:24 martin Exp
29146482Smarius */
30191072Smarius
31146482Smarius#include <sys/cdefs.h>
32146482Smarius__FBSDID("$FreeBSD$");
33146482Smarius
34146482Smarius/*
35191072Smarius * Driver for ATI Mach64 graphics chips.  Some code is derived from the
36146482Smarius * ATI Rage Pro and Derivatives Programmer's Guide.
37146482Smarius */
38146482Smarius
39146482Smarius#include <sys/param.h>
40146482Smarius#include <sys/systm.h>
41146482Smarius#include <sys/bus.h>
42146482Smarius#include <sys/consio.h>
43191076Smarius#include <sys/endian.h>
44146482Smarius#include <sys/eventhandler.h>
45146482Smarius#include <sys/fbio.h>
46146482Smarius#include <sys/kernel.h>
47146482Smarius#include <sys/module.h>
48146482Smarius#include <sys/resource.h>
49146482Smarius
50191076Smarius#include <vm/vm.h>
51191076Smarius#include <vm/pmap.h>
52191076Smarius
53146482Smarius#include <dev/ofw/ofw_bus.h>
54146482Smarius#include <dev/ofw/openfirm.h>
55146482Smarius
56146482Smarius#include <machine/bus.h>
57146482Smarius#include <machine/bus_private.h>
58146482Smarius#include <machine/ofw_machdep.h>
59191076Smarius#include <machine/pmap.h>
60146482Smarius#include <machine/resource.h>
61146482Smarius#include <machine/sc_machdep.h>
62146482Smarius
63146482Smarius#include <sys/rman.h>
64146482Smarius
65146482Smarius#include <dev/fb/fbreg.h>
66170840Smarius#include <dev/fb/gfb.h>
67146482Smarius#include <dev/fb/machfbreg.h>
68146482Smarius#include <dev/pci/pcivar.h>
69146482Smarius#include <dev/pci/pcireg.h>
70146482Smarius#include <dev/syscons/syscons.h>
71146482Smarius
72146482Smarius/* #define MACHFB_DEBUG */
73146482Smarius
74146482Smarius#define	MACHFB_DRIVER_NAME	"machfb"
75146482Smarius
76146482Smarius#define	MACH64_REG_OFF		0x7ffc00
77146482Smarius#define	MACH64_REG_SIZE		1024
78146482Smarius
79146482Smariusstruct machfb_softc {
80146482Smarius	video_adapter_t		sc_va;		/* must be first */
81146482Smarius
82191072Smarius	phandle_t		sc_node;
83146482Smarius	uint16_t		sc_chip_id;
84146482Smarius	uint8_t			sc_chip_rev;
85146482Smarius
86146482Smarius	struct resource		*sc_memres;
87146482Smarius	struct resource		*sc_vmemres;
88146482Smarius	bus_space_tag_t		sc_memt;
89146482Smarius	bus_space_tag_t		sc_regt;
90230687Smarius	bus_space_tag_t		sc_vmemt;
91146482Smarius	bus_space_handle_t	sc_memh;
92230687Smarius	bus_space_handle_t	sc_vmemh;
93146482Smarius	bus_space_handle_t	sc_regh;
94191076Smarius	u_long			sc_mem;
95191076Smarius	u_long			sc_vmem;
96146482Smarius
97191076Smarius	u_int			sc_height;
98191076Smarius	u_int			sc_width;
99191076Smarius	u_int			sc_depth;
100191076Smarius	u_int			sc_xmargin;
101191076Smarius	u_int			sc_ymargin;
102146482Smarius
103146482Smarius	size_t			sc_memsize;
104191076Smarius	u_int			sc_memtype;
105191076Smarius	u_int			sc_mem_freq;
106191076Smarius	u_int			sc_ramdac_freq;
107191076Smarius	u_int			sc_ref_freq;
108146482Smarius
109191076Smarius	u_int			sc_ref_div;
110191076Smarius	u_int			sc_mclk_post_div;
111191076Smarius	u_int			sc_mclk_fb_div;
112146482Smarius
113170840Smarius	const u_char		*sc_font;
114191076Smarius	u_int			sc_cbwidth;
115146482Smarius	vm_offset_t		sc_curoff;
116146482Smarius
117147881Smarius	int			sc_bg_cache;
118147881Smarius	int			sc_fg_cache;
119191076Smarius	u_int			sc_draw_cache;
120146482Smarius#define	MACHFB_DRAW_CHAR	(1 << 0)
121146482Smarius#define	MACHFB_DRAW_FILLRECT	(1 << 1)
122146482Smarius
123191076Smarius	u_int			sc_flags;
124146482Smarius#define	MACHFB_CONSOLE		(1 << 0)
125146482Smarius#define	MACHFB_CUREN		(1 << 1)
126146482Smarius#define	MACHFB_DSP		(1 << 2)
127191076Smarius#define	MACHFB_SWAP		(1 << 3)
128146482Smarius};
129146482Smarius
130147881Smariusstatic const struct {
131146482Smarius	uint16_t	chip_id;
132146482Smarius	const char	*name;
133146482Smarius	uint32_t	ramdac_freq;
134263764Sdim} machfb_info[] = {
135146482Smarius	{ ATI_MACH64_CT, "ATI Mach64 CT", 135000 },
136146482Smarius	{ ATI_RAGE_PRO_AGP, "ATI 3D Rage Pro (AGP)", 230000 },
137146482Smarius	{ ATI_RAGE_PRO_AGP1X, "ATI 3D Rage Pro (AGP 1x)", 230000 },
138146482Smarius	{ ATI_RAGE_PRO_PCI_B, "ATI 3D Rage Pro Turbo", 230000 },
139146482Smarius	{ ATI_RAGE_XC_PCI66, "ATI Rage XL (PCI66)", 230000 },
140146482Smarius	{ ATI_RAGE_XL_AGP, "ATI Rage XL (AGP)", 230000 },
141146482Smarius	{ ATI_RAGE_XC_AGP, "ATI Rage XC (AGP)", 230000 },
142147881Smarius	{ ATI_RAGE_XL_PCI66, "ATI Rage XL (PCI66)", 230000 },
143146482Smarius	{ ATI_RAGE_PRO_PCI_P, "ATI 3D Rage Pro", 230000 },
144146482Smarius	{ ATI_RAGE_PRO_PCI_L, "ATI 3D Rage Pro (limited 3D)", 230000 },
145146482Smarius	{ ATI_RAGE_XL_PCI, "ATI Rage XL", 230000 },
146146482Smarius	{ ATI_RAGE_XC_PCI, "ATI Rage XC", 230000 },
147146482Smarius	{ ATI_RAGE_II, "ATI 3D Rage I/II", 135000 },
148146482Smarius	{ ATI_RAGE_IIP, "ATI 3D Rage II+", 200000 },
149146482Smarius	{ ATI_RAGE_IIC_PCI, "ATI 3D Rage IIC", 230000 },
150146482Smarius	{ ATI_RAGE_IIC_AGP_B, "ATI 3D Rage IIC (AGP)", 230000 },
151146482Smarius	{ ATI_RAGE_IIC_AGP_P, "ATI 3D Rage IIC (AGP)", 230000 },
152146482Smarius	{ ATI_RAGE_LT_PRO_AGP, "ATI 3D Rage LT Pro (AGP 133MHz)", 230000 },
153146482Smarius	{ ATI_RAGE_MOB_M3_PCI, "ATI Rage Mobility M3", 230000 },
154146482Smarius	{ ATI_RAGE_MOB_M3_AGP, "ATI Rage Mobility M3 (AGP)", 230000 },
155146482Smarius	{ ATI_RAGE_LT, "ATI 3D Rage LT", 230000 },
156146482Smarius	{ ATI_RAGE_LT_PRO_PCI, "ATI 3D Rage LT Pro", 230000 },
157146482Smarius	{ ATI_RAGE_MOBILITY, "ATI Rage Mobility", 230000 },
158146482Smarius	{ ATI_RAGE_L_MOBILITY, "ATI Rage L Mobility", 230000 },
159146482Smarius	{ ATI_RAGE_LT_PRO, "ATI 3D Rage LT Pro", 230000 },
160146482Smarius	{ ATI_RAGE_LT_PRO2, "ATI 3D Rage LT Pro", 230000 },
161146482Smarius	{ ATI_RAGE_MOB_M1_PCI, "ATI Rage Mobility M1 (PCI)", 230000 },
162146482Smarius	{ ATI_RAGE_L_MOB_M1_PCI, "ATI Rage L Mobility (PCI)", 230000 },
163146482Smarius	{ ATI_MACH64_VT, "ATI Mach64 VT", 170000 },
164146482Smarius	{ ATI_MACH64_VTB, "ATI Mach64 VTB", 200000 },
165146482Smarius	{ ATI_MACH64_VT4, "ATI Mach64 VT4", 230000 }
166146482Smarius};
167146482Smarius
168147881Smariusstatic const struct machfb_cmap {
169146482Smarius	uint8_t red;
170146482Smarius	uint8_t green;
171146482Smarius	uint8_t blue;
172263764Sdim} machfb_default_cmap[16] = {
173146482Smarius	{0x00, 0x00, 0x00},	/* black */
174146482Smarius	{0x00, 0x00, 0xff},	/* blue */
175146482Smarius	{0x00, 0xff, 0x00},	/* green */
176146482Smarius	{0x00, 0xc0, 0xc0},	/* cyan */
177146482Smarius	{0xff, 0x00, 0x00},	/* red */
178146482Smarius	{0xc0, 0x00, 0xc0},	/* magenta */
179146482Smarius	{0xc0, 0xc0, 0x00},	/* brown */
180146482Smarius	{0xc0, 0xc0, 0xc0},	/* light grey */
181146482Smarius	{0x80, 0x80, 0x80},	/* dark grey */
182146482Smarius	{0x80, 0x80, 0xff},	/* light blue */
183146482Smarius	{0x80, 0xff, 0x80},	/* light green */
184146482Smarius	{0x80, 0xff, 0xff},	/* light cyan */
185146482Smarius	{0xff, 0x80, 0x80},	/* light red */
186146482Smarius	{0xff, 0x80, 0xff},	/* light magenta */
187146482Smarius	{0xff, 0xff, 0x80},	/* yellow */
188146482Smarius	{0xff, 0xff, 0xff}	/* white */
189146482Smarius};
190146482Smarius
191147881Smarius#define	MACHFB_CMAP_OFF		16
192147881Smarius
193263764Sdimstatic const u_char machfb_mouse_pointer_bits[64][8] = {
194146482Smarius	{ 0x00, 0x00, },	/* ............ */
195146482Smarius	{ 0x80, 0x00, },	/* *........... */
196146482Smarius	{ 0xc0, 0x00, },	/* **.......... */
197146482Smarius	{ 0xe0, 0x00, },	/* ***......... */
198146482Smarius	{ 0xf0, 0x00, },	/* ****........ */
199146482Smarius	{ 0xf8, 0x00, },	/* *****....... */
200146482Smarius	{ 0xfc, 0x00, },	/* ******...... */
201146482Smarius	{ 0xfe, 0x00, },	/* *******..... */
202146482Smarius	{ 0xff, 0x00, },	/* ********.... */
203146482Smarius	{ 0xff, 0x80, },	/* *********... */
204146482Smarius	{ 0xfc, 0xc0, },	/* ******..**.. */
205146482Smarius	{ 0xdc, 0x00, },	/* **.***...... */
206146482Smarius	{ 0x8e, 0x00, },	/* *...***..... */
207146482Smarius	{ 0x0e, 0x00, },	/* ....***..... */
208146482Smarius	{ 0x07, 0x00, },	/* .....***.... */
209146482Smarius	{ 0x04, 0x00, },	/* .....*...... */
210146482Smarius	{ 0x00, 0x00, },	/* ............ */
211146482Smarius	{ 0x00, 0x00, },	/* ............ */
212146482Smarius	{ 0x00, 0x00, },	/* ............ */
213146482Smarius	{ 0x00, 0x00, },	/* ............ */
214146482Smarius	{ 0x00, 0x00, },	/* ............ */
215146482Smarius	{ 0x00, 0x00, },	/* ............ */
216146482Smarius};
217146482Smarius
218146482Smarius/*
219146482Smarius * Lookup table to perform a bit-swap of the mouse pointer bits,
220146482Smarius * map set bits to CUR_CLR0 and unset bits to transparent.
221146482Smarius */
222263764Sdimstatic const u_char machfb_mouse_pointer_lut[] = {
223146482Smarius	0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
224146482Smarius	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
225146482Smarius};
226146482Smarius
227191076Smariusstatic const char *const machfb_memtype_names[] = {
228146482Smarius	"(N/A)", "DRAM", "EDO DRAM", "EDO DRAM", "SDRAM", "SGRAM", "WRAM",
229146482Smarius	"(unknown type)"
230146482Smarius};
231146482Smarius
232170840Smariusextern const struct gfb_font gallant12x22;
233170840Smarius
234146482Smariusstatic struct machfb_softc machfb_softc;
235146482Smariusstatic struct bus_space_tag machfb_bst_store[1];
236146482Smarius
237146482Smariusstatic device_probe_t machfb_pci_probe;
238146482Smariusstatic device_attach_t machfb_pci_attach;
239146482Smariusstatic device_detach_t machfb_pci_detach;
240146482Smarius
241146482Smariusstatic device_method_t machfb_methods[] = {
242146482Smarius	/* Device interface */
243146482Smarius	DEVMETHOD(device_probe,		machfb_pci_probe),
244146482Smarius	DEVMETHOD(device_attach,	machfb_pci_attach),
245146482Smarius	DEVMETHOD(device_detach,	machfb_pci_detach),
246146482Smarius
247146482Smarius	{ 0, 0 }
248146482Smarius};
249146482Smarius
250146482Smariusstatic driver_t machfb_pci_driver = {
251146482Smarius	MACHFB_DRIVER_NAME,
252146482Smarius	machfb_methods,
253146482Smarius	sizeof(struct machfb_softc),
254146482Smarius};
255146482Smarius
256146482Smariusstatic devclass_t machfb_devclass;
257146482Smarius
258146482SmariusDRIVER_MODULE(machfb, pci, machfb_pci_driver, machfb_devclass, 0, 0);
259146482SmariusMODULE_DEPEND(machfb, pci, 1, 1, 1);
260146482Smarius
261146482Smariusstatic void machfb_cursor_enable(struct machfb_softc *, int);
262146482Smariusstatic int machfb_cursor_install(struct machfb_softc *);
263146482Smariusstatic int machfb_get_memsize(struct machfb_softc *);
264146482Smariusstatic void machfb_reset_engine(struct machfb_softc *);
265146482Smariusstatic void machfb_init_engine(struct machfb_softc *);
266146482Smarius#if 0
267146482Smariusstatic void machfb_adjust_frame(struct machfb_softc *, int, int);
268146482Smarius#endif
269146971Smariusstatic void machfb_shutdown_final(void *);
270146971Smariusstatic void machfb_shutdown_reset(void *);
271146482Smarius
272146971Smariusstatic int machfb_configure(int);
273146482Smarius
274146482Smariusstatic vi_probe_t machfb_probe;
275146482Smariusstatic vi_init_t machfb_init;
276146482Smariusstatic vi_get_info_t machfb_get_info;
277146482Smariusstatic vi_query_mode_t machfb_query_mode;
278146482Smariusstatic vi_set_mode_t machfb_set_mode;
279146482Smariusstatic vi_save_font_t machfb_save_font;
280146482Smariusstatic vi_load_font_t machfb_load_font;
281146482Smariusstatic vi_show_font_t machfb_show_font;
282146482Smariusstatic vi_save_palette_t machfb_save_palette;
283146482Smariusstatic vi_load_palette_t machfb_load_palette;
284146482Smariusstatic vi_set_border_t machfb_set_border;
285146482Smariusstatic vi_save_state_t machfb_save_state;
286146482Smariusstatic vi_load_state_t machfb_load_state;
287146482Smariusstatic vi_set_win_org_t machfb_set_win_org;
288146482Smariusstatic vi_read_hw_cursor_t machfb_read_hw_cursor;
289146482Smariusstatic vi_set_hw_cursor_t machfb_set_hw_cursor;
290146482Smariusstatic vi_set_hw_cursor_shape_t machfb_set_hw_cursor_shape;
291146482Smariusstatic vi_blank_display_t machfb_blank_display;
292146482Smariusstatic vi_mmap_t machfb_mmap;
293146482Smariusstatic vi_ioctl_t machfb_ioctl;
294146482Smariusstatic vi_clear_t machfb_clear;
295146482Smariusstatic vi_fill_rect_t machfb_fill_rect;
296146482Smariusstatic vi_bitblt_t machfb_bitblt;
297146482Smariusstatic vi_diag_t machfb_diag;
298146482Smariusstatic vi_save_cursor_palette_t machfb_save_cursor_palette;
299146482Smariusstatic vi_load_cursor_palette_t machfb_load_cursor_palette;
300146482Smariusstatic vi_copy_t machfb_copy;
301146482Smariusstatic vi_putp_t machfb_putp;
302146482Smariusstatic vi_putc_t machfb_putc;
303146482Smariusstatic vi_puts_t machfb_puts;
304146482Smariusstatic vi_putm_t machfb_putm;
305146482Smarius
306146482Smariusstatic video_switch_t machfbvidsw = {
307146482Smarius	.probe			= machfb_probe,
308146482Smarius	.init			= machfb_init,
309146482Smarius	.get_info		= machfb_get_info,
310146482Smarius	.query_mode		= machfb_query_mode,
311146482Smarius	.set_mode		= machfb_set_mode,
312146482Smarius	.save_font		= machfb_save_font,
313146482Smarius	.load_font		= machfb_load_font,
314146482Smarius	.show_font		= machfb_show_font,
315146482Smarius	.save_palette		= machfb_save_palette,
316146482Smarius	.load_palette		= machfb_load_palette,
317146482Smarius	.set_border		= machfb_set_border,
318146482Smarius	.save_state		= machfb_save_state,
319146482Smarius	.load_state		= machfb_load_state,
320146482Smarius	.set_win_org		= machfb_set_win_org,
321146482Smarius	.read_hw_cursor		= machfb_read_hw_cursor,
322146482Smarius	.set_hw_cursor		= machfb_set_hw_cursor,
323146482Smarius	.set_hw_cursor_shape	= machfb_set_hw_cursor_shape,
324146482Smarius	.blank_display		= machfb_blank_display,
325146482Smarius	.mmap			= machfb_mmap,
326146482Smarius	.ioctl			= machfb_ioctl,
327146482Smarius	.clear			= machfb_clear,
328146482Smarius	.fill_rect		= machfb_fill_rect,
329146482Smarius	.bitblt			= machfb_bitblt,
330146482Smarius	.diag			= machfb_diag,
331146482Smarius	.save_cursor_palette	= machfb_save_cursor_palette,
332146482Smarius	.load_cursor_palette	= machfb_load_cursor_palette,
333146482Smarius	.copy			= machfb_copy,
334146482Smarius	.putp			= machfb_putp,
335146482Smarius	.putc			= machfb_putc,
336146482Smarius	.puts			= machfb_puts,
337146482Smarius	.putm			= machfb_putm
338146482Smarius};
339146482Smarius
340146482SmariusVIDEO_DRIVER(machfb, machfbvidsw, machfb_configure);
341146482Smarius
342146482Smariusextern sc_rndr_sw_t txtrndrsw;
343146482SmariusRENDERER(machfb, 0, txtrndrsw, gfb_set);
344146482Smarius
345146482SmariusRENDERER_MODULE(machfb, gfb_set);
346146482Smarius
347146482Smarius/*
348146482Smarius * Inline functions for getting access to register aperture.
349146482Smarius */
350146482Smariusstatic inline uint32_t regr(struct machfb_softc *, uint32_t);
351146482Smariusstatic inline uint8_t regrb(struct machfb_softc *, uint32_t);
352146482Smariusstatic inline void regw(struct machfb_softc *, uint32_t, uint32_t);
353146482Smariusstatic inline void regwb(struct machfb_softc *, uint32_t, uint8_t);
354146482Smariusstatic inline void regwb_pll(struct machfb_softc *, uint32_t, uint8_t);
355146482Smarius
356146482Smariusstatic inline uint32_t
357146482Smariusregr(struct machfb_softc *sc, uint32_t index)
358146482Smarius{
359146482Smarius
360146482Smarius	return bus_space_read_4(sc->sc_regt, sc->sc_regh, index);
361146482Smarius}
362146482Smarius
363146482Smariusstatic inline uint8_t
364146482Smariusregrb(struct machfb_softc *sc, uint32_t index)
365146482Smarius{
366146482Smarius
367146482Smarius	return bus_space_read_1(sc->sc_regt, sc->sc_regh, index);
368146482Smarius}
369146482Smarius
370146482Smariusstatic inline void
371146482Smariusregw(struct machfb_softc *sc, uint32_t index, uint32_t data)
372146482Smarius{
373146482Smarius
374146482Smarius	bus_space_write_4(sc->sc_regt, sc->sc_regh, index, data);
375146482Smarius	bus_space_barrier(sc->sc_regt, sc->sc_regh, index, 4,
376146482Smarius	    BUS_SPACE_BARRIER_WRITE);
377146482Smarius}
378146482Smarius
379146482Smariusstatic inline void
380146482Smariusregwb(struct machfb_softc *sc, uint32_t index, uint8_t data)
381146482Smarius{
382146482Smarius
383146482Smarius	bus_space_write_1(sc->sc_regt, sc->sc_regh, index, data);
384146482Smarius	bus_space_barrier(sc->sc_regt, sc->sc_regh, index, 1,
385146482Smarius	    BUS_SPACE_BARRIER_WRITE);
386146482Smarius}
387146482Smarius
388146482Smariusstatic inline void
389146482Smariusregwb_pll(struct machfb_softc *sc, uint32_t index, uint8_t data)
390146482Smarius{
391146482Smarius
392146482Smarius	regwb(sc, CLOCK_CNTL + 1, (index << 2) | PLL_WR_EN);
393146482Smarius	regwb(sc, CLOCK_CNTL + 2, data);
394146482Smarius	regwb(sc, CLOCK_CNTL + 1, (index << 2) & ~PLL_WR_EN);
395146482Smarius}
396146482Smarius
397146482Smariusstatic inline void
398146482Smariuswait_for_fifo(struct machfb_softc *sc, uint8_t v)
399146482Smarius{
400146482Smarius
401146482Smarius	while ((regr(sc, FIFO_STAT) & 0xffff) > (0x8000 >> v))
402146482Smarius		;
403146482Smarius}
404146482Smarius
405146482Smariusstatic inline void
406146482Smariuswait_for_idle(struct machfb_softc *sc)
407146482Smarius{
408146482Smarius
409146482Smarius	wait_for_fifo(sc, 16);
410146482Smarius	while ((regr(sc, GUI_STAT) & 1) != 0)
411146482Smarius		;
412146482Smarius}
413146482Smarius
414146482Smarius/*
415147881Smarius * Inline functions for setting the background and foreground colors.
416147881Smarius */
417147881Smariusstatic inline void machfb_setbg(struct machfb_softc *sc, int bg);
418147881Smariusstatic inline void machfb_setfg(struct machfb_softc *sc, int fg);
419147881Smarius
420147881Smariusstatic inline void
421147881Smariusmachfb_setbg(struct machfb_softc *sc, int bg)
422147881Smarius{
423147881Smarius
424147881Smarius	if (bg == sc->sc_bg_cache)
425147881Smarius		return;
426147881Smarius	sc->sc_bg_cache = bg;
427147881Smarius	wait_for_fifo(sc, 1);
428147881Smarius	regw(sc, DP_BKGD_CLR, bg + MACHFB_CMAP_OFF);
429147881Smarius}
430147881Smarius
431147881Smariusstatic inline void
432147881Smariusmachfb_setfg(struct machfb_softc *sc, int fg)
433147881Smarius{
434147881Smarius
435147881Smarius	if (fg == sc->sc_fg_cache)
436147881Smarius		return;
437147881Smarius	sc->sc_fg_cache = fg;
438147881Smarius	wait_for_fifo(sc, 1);
439147881Smarius	regw(sc, DP_FRGD_CLR, fg + MACHFB_CMAP_OFF);
440147881Smarius}
441147881Smarius
442147881Smarius/*
443146482Smarius * video driver interface
444146482Smarius */
445146482Smariusstatic int
446146482Smariusmachfb_configure(int flags)
447146482Smarius{
448146482Smarius	struct machfb_softc *sc;
449146482Smarius	phandle_t chosen, output;
450146482Smarius	ihandle_t stdout;
451146482Smarius	bus_addr_t addr;
452146482Smarius	uint32_t id;
453146482Smarius	int i, space;
454146482Smarius
455146971Smarius	/*
456146971Smarius	 * For the high-level console probing return the number of
457146971Smarius	 * registered adapters.
458146971Smarius	 */
459146971Smarius	if (!(flags & VIO_PROBE_ONLY)) {
460146971Smarius		for (i = 0; vid_find_adapter(MACHFB_DRIVER_NAME, i) >= 0; i++)
461146971Smarius			;
462146971Smarius		return (i);
463146971Smarius	}
464146971Smarius
465146971Smarius	/* Low-level console probing and initialization. */
466146971Smarius
467146482Smarius	sc = &machfb_softc;
468146971Smarius	if (sc->sc_va.va_flags & V_ADP_REGISTERED)
469146971Smarius		goto found;
470146482Smarius
471146482Smarius	if ((chosen = OF_finddevice("/chosen")) == -1)	/* Quis contra nos? */
472146482Smarius		return (0);
473146482Smarius	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1)
474146482Smarius		return (0);
475146482Smarius	if ((output = OF_instance_to_package(stdout)) == -1)
476146482Smarius		return (0);
477146482Smarius	if ((OF_getprop(output, "vendor-id", &id, sizeof(id)) == -1) ||
478146482Smarius	    id != ATI_VENDOR)
479146482Smarius		return (0);
480146482Smarius	if (OF_getprop(output, "device-id", &id, sizeof(id)) == -1)
481146482Smarius		return (0);
482146482Smarius	for (i = 0; i < sizeof(machfb_info) / sizeof(machfb_info[0]); i++) {
483146482Smarius		if (id == machfb_info[i].chip_id) {
484146482Smarius			sc->sc_flags = MACHFB_CONSOLE;
485146482Smarius			sc->sc_node = output;
486146482Smarius			sc->sc_chip_id = id;
487146482Smarius			break;
488146482Smarius		}
489146482Smarius	}
490146482Smarius	if (!(sc->sc_flags & MACHFB_CONSOLE))
491146482Smarius		return (0);
492146482Smarius
493146482Smarius	if (OF_getprop(output, "revision-id", &sc->sc_chip_rev,
494146482Smarius	    sizeof(sc->sc_chip_rev)) == -1)
495146482Smarius		return (0);
496146482Smarius	if (OF_decode_addr(output, 0, &space, &addr) != 0)
497146482Smarius		return (0);
498146482Smarius	sc->sc_memt = &machfb_bst_store[0];
499146482Smarius	sc->sc_memh = sparc64_fake_bustag(space, addr, sc->sc_memt);
500146482Smarius	sc->sc_regt = sc->sc_memt;
501146482Smarius	bus_space_subregion(sc->sc_regt, sc->sc_memh, MACH64_REG_OFF,
502146482Smarius	    MACH64_REG_SIZE, &sc->sc_regh);
503146482Smarius
504146482Smarius	if (machfb_init(0, &sc->sc_va, 0) < 0)
505146482Smarius		 return (0);
506146482Smarius
507146482Smarius found:
508146482Smarius	/* Return number of found adapters. */
509146482Smarius	return (1);
510146482Smarius}
511146482Smarius
512146482Smariusstatic int
513146482Smariusmachfb_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
514146482Smarius{
515146482Smarius
516146482Smarius	return (0);
517146482Smarius}
518146482Smarius
519146482Smariusstatic int
520146482Smariusmachfb_init(int unit, video_adapter_t *adp, int flags)
521146482Smarius{
522146482Smarius	struct machfb_softc *sc;
523146482Smarius	phandle_t options;
524146482Smarius	video_info_t *vi;
525146482Smarius	char buf[32];
526147881Smarius	int i;
527147881Smarius	uint8_t	dac_mask, dac_rindex, dac_windex;
528146482Smarius
529146482Smarius	sc = (struct machfb_softc *)adp;
530146482Smarius	vi = &adp->va_info;
531146482Smarius
532146482Smarius	if ((regr(sc, CONFIG_CHIP_ID) & 0xffff) != sc->sc_chip_id)
533146482Smarius		return (ENXIO);
534146482Smarius
535146482Smarius	sc->sc_ramdac_freq = 0;
536146482Smarius	for (i = 0; i < sizeof(machfb_info) / sizeof(machfb_info[0]); i++) {
537146482Smarius		if (sc->sc_chip_id == machfb_info[i].chip_id) {
538146482Smarius			sc->sc_ramdac_freq = machfb_info[i].ramdac_freq;
539146482Smarius			break;
540146482Smarius		}
541146482Smarius	}
542146482Smarius	if (sc->sc_ramdac_freq == 0)
543146482Smarius		return (ENXIO);
544146482Smarius	if (sc->sc_chip_id == ATI_RAGE_II && sc->sc_chip_rev & 0x07)
545146482Smarius		sc->sc_ramdac_freq = 170000;
546146482Smarius
547146482Smarius	vid_init_struct(adp, MACHFB_DRIVER_NAME, -1, unit);
548146482Smarius
549191072Smarius	if (OF_getprop(sc->sc_node, "height", &sc->sc_height,
550146482Smarius	    sizeof(sc->sc_height)) == -1)
551146482Smarius		return (ENXIO);
552146482Smarius	if (OF_getprop(sc->sc_node, "width", &sc->sc_width,
553146482Smarius	    sizeof(sc->sc_width)) == -1)
554146482Smarius		return (ENXIO);
555146482Smarius	if (OF_getprop(sc->sc_node, "depth", &sc->sc_depth,
556146482Smarius	    sizeof(sc->sc_depth)) == -1)
557146482Smarius		return (ENXIO);
558146482Smarius	if ((options = OF_finddevice("/options")) == -1)
559146482Smarius		return (ENXIO);
560146482Smarius	if (OF_getprop(options, "screen-#rows", buf, sizeof(buf)) == -1)
561146482Smarius		return (ENXIO);
562146482Smarius	vi->vi_height = strtol(buf, NULL, 10);
563146482Smarius	if (OF_getprop(options, "screen-#columns", buf, sizeof(buf)) == -1)
564146482Smarius		return (ENXIO);
565146482Smarius	vi->vi_width = strtol(buf, NULL, 10);
566170840Smarius	vi->vi_cwidth = gallant12x22.width;
567170840Smarius	vi->vi_cheight = gallant12x22.height;
568146482Smarius	vi->vi_flags = V_INFO_COLOR;
569146482Smarius	vi->vi_mem_model = V_INFO_MM_OTHER;
570146482Smarius
571170840Smarius	sc->sc_font = gallant12x22.data;
572170840Smarius	sc->sc_cbwidth = howmany(vi->vi_cwidth, NBBY);	/* width in bytes */
573146482Smarius	sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2;
574146482Smarius	sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight)) / 2;
575146482Smarius
576146482Smarius	if (sc->sc_chip_id != ATI_MACH64_CT &&
577146482Smarius	    !((sc->sc_chip_id == ATI_MACH64_VT ||
578146482Smarius	    sc->sc_chip_id == ATI_RAGE_II) &&
579146482Smarius	    (sc->sc_chip_rev & 0x07) == 0))
580146482Smarius		sc->sc_flags |= MACHFB_DSP;
581146482Smarius
582146482Smarius	sc->sc_memsize = machfb_get_memsize(sc);
583146482Smarius	if (sc->sc_memsize == 8192)
584146482Smarius		/* The last page is used as register aperture. */
585146482Smarius		sc->sc_memsize -= 4;
586146482Smarius	sc->sc_memtype = regr(sc, CONFIG_STAT0) & 0x07;
587146482Smarius
588146482Smarius	if ((sc->sc_chip_id >= ATI_RAGE_XC_PCI66 &&
589146482Smarius	    sc->sc_chip_id <= ATI_RAGE_XL_PCI66) ||
590146482Smarius	    (sc->sc_chip_id >= ATI_RAGE_XL_PCI &&
591146482Smarius	    sc->sc_chip_id <= ATI_RAGE_XC_PCI))
592146482Smarius		sc->sc_ref_freq = 29498;
593146482Smarius	else
594146482Smarius		sc->sc_ref_freq = 14318;
595146482Smarius
596146482Smarius	regwb(sc, CLOCK_CNTL + 1, PLL_REF_DIV << 2);
597146482Smarius	sc->sc_ref_div = regrb(sc, CLOCK_CNTL + 2);
598146482Smarius	regwb(sc, CLOCK_CNTL + 1, MCLK_FB_DIV << 2);
599146482Smarius	sc->sc_mclk_fb_div = regrb(sc, CLOCK_CNTL + 2);
600146482Smarius	sc->sc_mem_freq = (2 * sc->sc_ref_freq * sc->sc_mclk_fb_div) /
601146482Smarius	    (sc->sc_ref_div * 2);
602146482Smarius	sc->sc_mclk_post_div = (sc->sc_mclk_fb_div * 2 * sc->sc_ref_freq) /
603146482Smarius	    (sc->sc_mem_freq * sc->sc_ref_div);
604146482Smarius
605146482Smarius	machfb_init_engine(sc);
606146482Smarius#if 0
607191072Smarius	machfb_adjust_frame(0, 0);
608146482Smarius#endif
609147881Smarius	machfb_set_mode(adp, 0);
610146482Smarius
611147881Smarius	/*
612191072Smarius	 * Install our 16-color color map.  This is done only once and with
613147881Smarius	 * an offset of 16 on sparc64 as there the OBP driver expects white
614147881Smarius	 * to be at index 0 and black at 255 (some versions also use 1 - 8
615147881Smarius	 * for color text support or the full palette for the boot banner
616147881Smarius	 * logo but no versions seems to use the ISO 6429-1983 color map).
617147881Smarius	 * Otherwise the colors are inverted when back in the OFW.
618147881Smarius	 */
619147881Smarius	dac_rindex = regrb(sc, DAC_RINDEX);
620147881Smarius	dac_windex = regrb(sc, DAC_WINDEX);
621147881Smarius	dac_mask = regrb(sc, DAC_MASK);
622147881Smarius	regwb(sc, DAC_MASK, 0xff);
623147881Smarius	regwb(sc, DAC_WINDEX, MACHFB_CMAP_OFF);
624147881Smarius	for (i = 0; i < 16; i++) {
625147881Smarius		regwb(sc, DAC_DATA, machfb_default_cmap[i].red);
626147881Smarius		regwb(sc, DAC_DATA, machfb_default_cmap[i].green);
627147881Smarius		regwb(sc, DAC_DATA, machfb_default_cmap[i].blue);
628147881Smarius	}
629147881Smarius	regwb(sc, DAC_MASK, dac_mask);
630147881Smarius	regwb(sc, DAC_RINDEX, dac_rindex);
631147881Smarius	regwb(sc, DAC_WINDEX, dac_windex);
632146482Smarius
633147881Smarius	machfb_blank_display(adp, V_DISPLAY_ON);
634147881Smarius	machfb_clear(adp);
635146482Smarius
636147881Smarius	/*
637147881Smarius	 * Setting V_ADP_MODECHANGE serves as hack so machfb_set_mode()
638147881Smarius	 * (which will invalidate our caches) is called as a precaution
639147881Smarius	 * when the X server shuts down.
640147881Smarius	 */
641147881Smarius	adp->va_flags |= V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_PALETTE |
642147881Smarius	    V_ADP_BORDER | V_ADP_INITIALIZED;
643146482Smarius	if (vid_register(adp) < 0)
644146482Smarius		return (ENXIO);
645146482Smarius	adp->va_flags |= V_ADP_REGISTERED;
646146482Smarius
647146482Smarius	return (0);
648146482Smarius}
649146482Smarius
650146482Smariusstatic int
651146482Smariusmachfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
652146482Smarius{
653146482Smarius
654146482Smarius	bcopy(&adp->va_info, info, sizeof(*info));
655146482Smarius
656146482Smarius	return (0);
657146482Smarius}
658146482Smarius
659146482Smariusstatic int
660146482Smariusmachfb_query_mode(video_adapter_t *adp, video_info_t *info)
661146482Smarius{
662146482Smarius
663146482Smarius	return (ENODEV);
664146482Smarius}
665146482Smarius
666146482Smariusstatic int
667146482Smariusmachfb_set_mode(video_adapter_t *adp, int mode)
668146482Smarius{
669147881Smarius	struct machfb_softc *sc;
670146482Smarius
671147881Smarius	sc = (struct machfb_softc *)adp;
672147881Smarius
673147881Smarius	sc->sc_bg_cache = -1;
674147881Smarius	sc->sc_fg_cache = -1;
675191076Smarius	sc->sc_draw_cache = 0;
676147881Smarius
677147881Smarius	return (0);
678146482Smarius}
679146482Smarius
680146482Smariusstatic int
681150686Smariusmachfb_save_font(video_adapter_t *adp, int page, int size, int width,
682150686Smarius    u_char *data, int c, int count)
683146482Smarius{
684146482Smarius
685146482Smarius	return (ENODEV);
686146482Smarius}
687146482Smarius
688146482Smariusstatic int
689150686Smariusmachfb_load_font(video_adapter_t *adp, int page, int size, int width,
690150686Smarius    u_char *data, int c, int count)
691146482Smarius{
692146482Smarius
693146482Smarius	return (ENODEV);
694146482Smarius}
695146482Smarius
696146482Smariusstatic int
697146482Smariusmachfb_show_font(video_adapter_t *adp, int page)
698146482Smarius{
699146482Smarius
700146482Smarius	return (ENODEV);
701146482Smarius}
702146482Smarius
703146482Smariusstatic int
704146482Smariusmachfb_save_palette(video_adapter_t *adp, u_char *palette)
705146482Smarius{
706147881Smarius	struct machfb_softc *sc;
707147881Smarius	int i;
708147881Smarius	uint8_t	dac_mask, dac_rindex, dac_windex;
709146482Smarius
710147881Smarius	sc = (struct machfb_softc *)adp;
711147881Smarius
712147881Smarius	dac_rindex = regrb(sc, DAC_RINDEX);
713147881Smarius	dac_windex = regrb(sc, DAC_WINDEX);
714147881Smarius	dac_mask = regrb(sc, DAC_MASK);
715147881Smarius	regwb(sc, DAC_MASK, 0xff);
716147881Smarius	regwb(sc, DAC_RINDEX, 0x0);
717147881Smarius	for (i = 0; i < 256 * 3; i++)
718147881Smarius		palette[i] = regrb(sc, DAC_DATA);
719147881Smarius	regwb(sc, DAC_MASK, dac_mask);
720147881Smarius	regwb(sc, DAC_RINDEX, dac_rindex);
721147881Smarius	regwb(sc, DAC_WINDEX, dac_windex);
722147881Smarius
723147881Smarius	return (0);
724146482Smarius}
725146482Smarius
726146482Smariusstatic int
727146482Smariusmachfb_load_palette(video_adapter_t *adp, u_char *palette)
728146482Smarius{
729147881Smarius	struct machfb_softc *sc;
730147881Smarius	int i;
731147881Smarius	uint8_t	dac_mask, dac_rindex, dac_windex;
732146482Smarius
733147881Smarius	sc = (struct machfb_softc *)adp;
734147881Smarius
735147881Smarius	dac_rindex = regrb(sc, DAC_RINDEX);
736147881Smarius	dac_windex = regrb(sc, DAC_WINDEX);
737147881Smarius	dac_mask = regrb(sc, DAC_MASK);
738147881Smarius	regwb(sc, DAC_MASK, 0xff);
739147881Smarius	regwb(sc, DAC_WINDEX, 0x0);
740147881Smarius	for (i = 0; i < 256 * 3; i++)
741147881Smarius		regwb(sc, DAC_DATA, palette[i]);
742147881Smarius	regwb(sc, DAC_MASK, dac_mask);
743147881Smarius	regwb(sc, DAC_RINDEX, dac_rindex);
744147881Smarius	regwb(sc, DAC_WINDEX, dac_windex);
745147881Smarius
746147881Smarius	return (0);
747146482Smarius}
748146482Smarius
749146482Smariusstatic int
750146482Smariusmachfb_set_border(video_adapter_t *adp, int border)
751146482Smarius{
752146482Smarius	struct machfb_softc *sc;
753146482Smarius
754146482Smarius	sc = (struct machfb_softc *)adp;
755146482Smarius
756146482Smarius	machfb_fill_rect(adp, border, 0, 0, sc->sc_width, sc->sc_ymargin);
757146482Smarius	machfb_fill_rect(adp, border, 0, sc->sc_height - sc->sc_ymargin,
758146482Smarius	    sc->sc_width, sc->sc_ymargin);
759146482Smarius	machfb_fill_rect(adp, border, 0, 0, sc->sc_xmargin, sc->sc_height);
760146482Smarius	machfb_fill_rect(adp, border, sc->sc_width - sc->sc_xmargin, 0,
761146482Smarius	    sc->sc_xmargin, sc->sc_height);
762146482Smarius
763146482Smarius	return (0);
764146482Smarius}
765146482Smarius
766146482Smariusstatic int
767146482Smariusmachfb_save_state(video_adapter_t *adp, void *p, size_t size)
768146482Smarius{
769146482Smarius
770146482Smarius	return (ENODEV);
771146482Smarius}
772146482Smarius
773146482Smariusstatic int
774146482Smariusmachfb_load_state(video_adapter_t *adp, void *p)
775146482Smarius{
776146482Smarius
777146482Smarius	return (ENODEV);
778146482Smarius}
779146482Smarius
780146482Smariusstatic int
781146482Smariusmachfb_set_win_org(video_adapter_t *adp, off_t offset)
782146482Smarius{
783146482Smarius
784146482Smarius	return (ENODEV);
785146482Smarius}
786146482Smarius
787146482Smariusstatic int
788146482Smariusmachfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
789146482Smarius{
790146482Smarius
791146482Smarius	*col = 0;
792146482Smarius	*row = 0;
793146482Smarius
794146482Smarius	return (0);
795146482Smarius}
796146482Smarius
797146482Smariusstatic int
798146482Smariusmachfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
799146482Smarius{
800146482Smarius
801146482Smarius	return (ENODEV);
802146482Smarius}
803146482Smarius
804146482Smariusstatic int
805146482Smariusmachfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
806146482Smarius    int celsize, int blink)
807146482Smarius{
808146482Smarius
809146482Smarius	return (ENODEV);
810146482Smarius}
811146482Smarius
812146482Smariusstatic int
813146482Smariusmachfb_blank_display(video_adapter_t *adp, int mode)
814146482Smarius{
815146482Smarius	struct machfb_softc *sc;
816147881Smarius	uint32_t crtc_gen_cntl;
817146482Smarius
818146482Smarius	sc = (struct machfb_softc *)adp;
819146482Smarius
820147881Smarius	crtc_gen_cntl = (regr(sc, CRTC_GEN_CNTL) | CRTC_EXT_DISP_EN | CRTC_EN) &
821147881Smarius	    ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
822147881Smarius	switch (mode) {
823147881Smarius	case V_DISPLAY_ON:
824147881Smarius		break;
825147881Smarius	case V_DISPLAY_BLANK:
826147881Smarius		crtc_gen_cntl |= CRTC_HSYNC_DIS | CRTC_VSYNC_DIS |
827147881Smarius		    CRTC_DISPLAY_DIS;
828147881Smarius		break;
829147881Smarius	case V_DISPLAY_STAND_BY:
830147881Smarius		crtc_gen_cntl |= CRTC_HSYNC_DIS | CRTC_DISPLAY_DIS;
831147881Smarius		break;
832147881Smarius	case V_DISPLAY_SUSPEND:
833147881Smarius		crtc_gen_cntl |= CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS;
834147881Smarius		break;
835147881Smarius	}
836147881Smarius	regw(sc, CRTC_GEN_CNTL, crtc_gen_cntl);
837146482Smarius
838146482Smarius	return (0);
839146482Smarius}
840146482Smarius
841146482Smariusstatic int
842201223Srnolandmachfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
843201223Srnoland    int prot, vm_memattr_t *memattr)
844146482Smarius{
845146482Smarius	struct machfb_softc *sc;
846191076Smarius	video_info_t *vi;
847146482Smarius
848146482Smarius	sc = (struct machfb_softc *)adp;
849191076Smarius	vi = &adp->va_info;
850146482Smarius
851191076Smarius	/* BAR 2 - VGA memory */
852191076Smarius	if (sc->sc_vmem != 0 && offset >= sc->sc_vmem &&
853191076Smarius	    offset < sc->sc_vmem + vi->vi_registers_size) {
854191076Smarius		*paddr = vi->vi_registers + offset - sc->sc_vmem;
855146482Smarius		return (0);
856146482Smarius	}
857146482Smarius
858191076Smarius	/* BAR 0 - framebuffer */
859191076Smarius	if (offset >= sc->sc_mem &&
860191076Smarius	    offset < sc->sc_mem + vi->vi_buffer_size) {
861191076Smarius		*paddr = vi->vi_buffer + offset - sc->sc_mem;
862146482Smarius		return (0);
863146482Smarius	}
864146482Smarius
865146482Smarius	/* 'regular' framebuffer mmap()ing */
866146482Smarius	if (offset < adp->va_window_size) {
867191076Smarius		*paddr = vi->vi_window + offset;
868146482Smarius		return (0);
869146482Smarius	}
870146482Smarius
871146482Smarius	return (EINVAL);
872146482Smarius}
873146482Smarius
874146482Smariusstatic int
875146482Smariusmachfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
876146482Smarius{
877146482Smarius	struct machfb_softc *sc;
878146482Smarius	struct fbcursor *fbc;
879146482Smarius	struct fbtype *fb;
880146482Smarius
881146482Smarius	sc = (struct machfb_softc *)adp;
882146482Smarius
883146482Smarius	switch (cmd) {
884146482Smarius	case FBIOGTYPE:
885146482Smarius		fb = (struct fbtype *)data;
886146482Smarius		fb->fb_type = FBTYPE_PCIMISC;
887146482Smarius		fb->fb_height = sc->sc_height;
888146482Smarius		fb->fb_width = sc->sc_width;
889146482Smarius		fb->fb_depth = sc->sc_depth;
890146482Smarius		if (sc->sc_depth <= 1 || sc->sc_depth > 8)
891146482Smarius			fb->fb_cmsize = 0;
892146482Smarius		else
893146482Smarius			fb->fb_cmsize = 1 << sc->sc_depth;
894146482Smarius		fb->fb_size = adp->va_buffer_size;
895146482Smarius		break;
896146482Smarius	case FBIOSCURSOR:
897146482Smarius		fbc = (struct fbcursor *)data;
898146971Smarius		if (fbc->set & FB_CUR_SETCUR && fbc->enable == 0) {
899146971Smarius			machfb_cursor_enable(sc, 0);
900146971Smarius			sc->sc_flags &= ~MACHFB_CUREN;
901146971Smarius		} else
902146971Smarius			return (ENODEV);
903146482Smarius		break;
904146482Smarius	default:
905146482Smarius		return (fb_commonioctl(adp, cmd, data));
906146482Smarius	}
907146482Smarius
908146482Smarius	return (0);
909146482Smarius}
910146482Smarius
911146482Smariusstatic int
912146482Smariusmachfb_clear(video_adapter_t *adp)
913146482Smarius{
914147881Smarius	struct machfb_softc *sc;
915146482Smarius
916147881Smarius	sc = (struct machfb_softc *)adp;
917147881Smarius
918147881Smarius	machfb_fill_rect(adp, (SC_NORM_ATTR >> 4) & 0xf, 0, 0, sc->sc_width,
919147881Smarius	    sc->sc_height);
920147881Smarius
921147881Smarius	return (0);
922146482Smarius}
923146482Smarius
924146482Smariusstatic int
925146482Smariusmachfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
926146482Smarius{
927146482Smarius	struct machfb_softc *sc;
928146482Smarius
929146482Smarius	sc = (struct machfb_softc *)adp;
930146482Smarius
931146482Smarius	if (sc->sc_draw_cache != MACHFB_DRAW_FILLRECT) {
932146482Smarius		wait_for_fifo(sc, 7);
933146482Smarius		regw(sc, DP_WRITE_MASK, 0xff);
934146482Smarius		regw(sc, DP_PIX_WIDTH, DST_8BPP | SRC_8BPP | HOST_8BPP);
935146482Smarius		regw(sc, DP_SRC, FRGD_SRC_FRGD_CLR);
936146482Smarius		regw(sc, DP_MIX, MIX_SRC << 16);
937146482Smarius		regw(sc, CLR_CMP_CNTL, 0);	/* no transparency */
938146482Smarius		regw(sc, SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT);
939146482Smarius		regw(sc, DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
940146482Smarius		sc->sc_draw_cache = MACHFB_DRAW_FILLRECT;
941146482Smarius	}
942147881Smarius	machfb_setfg(sc, val);
943147881Smarius	wait_for_fifo(sc, 4);
944146482Smarius	regw(sc, SRC_Y_X, (x << 16) | y);
945146482Smarius	regw(sc, SRC_WIDTH1, cx);
946146482Smarius	regw(sc, DST_Y_X, (x << 16) | y);
947146482Smarius	regw(sc, DST_HEIGHT_WIDTH, (cx << 16) | cy);
948146482Smarius
949146482Smarius	return (0);
950146482Smarius}
951146482Smarius
952146482Smariusstatic int
953146482Smariusmachfb_bitblt(video_adapter_t *adp, ...)
954146482Smarius{
955146482Smarius
956146482Smarius	return (ENODEV);
957146482Smarius}
958146482Smarius
959146482Smariusstatic int
960146482Smariusmachfb_diag(video_adapter_t *adp, int level)
961146482Smarius{
962146482Smarius	video_info_t info;
963146482Smarius
964146482Smarius	fb_dump_adp_info(adp->va_name, adp, level);
965146482Smarius	machfb_get_info(adp, 0, &info);
966146482Smarius	fb_dump_mode_info(adp->va_name, adp, &info, level);
967146482Smarius
968146482Smarius	return (0);
969146482Smarius}
970146482Smarius
971146482Smariusstatic int
972146482Smariusmachfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
973146482Smarius{
974146482Smarius
975146482Smarius	return (ENODEV);
976146482Smarius}
977146482Smarius
978146482Smariusstatic int
979146482Smariusmachfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
980146482Smarius{
981146482Smarius
982146482Smarius	return (ENODEV);
983146482Smarius}
984146482Smarius
985146482Smariusstatic int
986146482Smariusmachfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
987146482Smarius{
988146482Smarius
989146482Smarius	return (ENODEV);
990146482Smarius}
991146482Smarius
992146482Smariusstatic int
993146482Smariusmachfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
994146482Smarius    int size, int bpp, int bit_ltor, int byte_ltor)
995146482Smarius{
996146482Smarius
997146482Smarius	return (ENODEV);
998146482Smarius}
999146482Smarius
1000146482Smariusstatic int
1001146482Smariusmachfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
1002146482Smarius{
1003146482Smarius	struct machfb_softc *sc;
1004170840Smarius	const uint8_t *p;
1005146482Smarius	int i;
1006146482Smarius
1007146482Smarius	sc = (struct machfb_softc *)adp;
1008146482Smarius
1009146482Smarius	if (sc->sc_draw_cache != MACHFB_DRAW_CHAR) {
1010146482Smarius		wait_for_fifo(sc, 8);
1011146482Smarius		regw(sc, DP_WRITE_MASK, 0xff);	/* XXX only good for 8 bit */
1012146482Smarius		regw(sc, DP_PIX_WIDTH, DST_8BPP | SRC_1BPP | HOST_1BPP);
1013146482Smarius		regw(sc, DP_SRC, MONO_SRC_HOST | BKGD_SRC_BKGD_CLR |
1014146482Smarius		    FRGD_SRC_FRGD_CLR);
1015146482Smarius		regw(sc, DP_MIX ,((MIX_SRC & 0xffff) << 16) | MIX_SRC);
1016146482Smarius		regw(sc, CLR_CMP_CNTL, 0);	/* no transparency */
1017146482Smarius		regw(sc, SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT);
1018146482Smarius		regw(sc, DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT);
1019146482Smarius		regw(sc, HOST_CNTL, HOST_BYTE_ALIGN);
1020146482Smarius		sc->sc_draw_cache = MACHFB_DRAW_CHAR;
1021146482Smarius	}
1022147881Smarius	machfb_setbg(sc, (a >> 4) & 0xf);
1023147881Smarius	machfb_setfg(sc, a & 0xf);
1024147881Smarius	wait_for_fifo(sc, 4 + (adp->va_info.vi_cheight / sc->sc_cbwidth));
1025146482Smarius	regw(sc, SRC_Y_X, 0);
1026146482Smarius	regw(sc, SRC_WIDTH1, adp->va_info.vi_cwidth);
1027146482Smarius	regw(sc, DST_Y_X, ((((off % adp->va_info.vi_width) *
1028146482Smarius	    adp->va_info.vi_cwidth) + sc->sc_xmargin) << 16) |
1029146482Smarius	    (((off / adp->va_info.vi_width) * adp->va_info.vi_cheight) +
1030146482Smarius	    sc->sc_ymargin));
1031146482Smarius	regw(sc, DST_HEIGHT_WIDTH, (adp->va_info.vi_cwidth << 16) |
1032146482Smarius	    adp->va_info.vi_cheight);
1033147881Smarius	p = sc->sc_font + (c * adp->va_info.vi_cheight * sc->sc_cbwidth);
1034146482Smarius	for (i = 0; i < adp->va_info.vi_cheight * sc->sc_cbwidth; i += 4)
1035146482Smarius		regw(sc, HOST_DATA0 + i, (p[i + 3] << 24 | p[i + 2] << 16 |
1036146482Smarius		    p[i + 1] << 8 | p[i]));
1037146482Smarius
1038146482Smarius	return (0);
1039146482Smarius}
1040146482Smarius
1041146482Smariusstatic int
1042146482Smariusmachfb_puts(video_adapter_t *adp, vm_offset_t off, uint16_t *s, int len)
1043146482Smarius{
1044146482Smarius	struct machfb_softc *sc;
1045146482Smarius	int blanks, i, x1, x2, y1, y2;
1046146482Smarius	uint8_t a, c, color1, color2;
1047146482Smarius
1048146482Smarius	sc = (struct machfb_softc *)adp;
1049146482Smarius
1050146482Smarius#define	MACHFB_BLANK	machfb_fill_rect(adp, color1, x1, y1,		\
1051146482Smarius			    blanks * adp->va_info.vi_cwidth,		\
1052146482Smarius			    adp->va_info.vi_cheight)
1053146482Smarius
1054146482Smarius	blanks = color1 = x1 = y1 = 0;
1055146482Smarius	for (i = 0; i < len; i++) {
1056146482Smarius		/*
1057146482Smarius		 * Accelerate continuous blanks by drawing a respective
1058191072Smarius		 * rectangle instead.  Drawing a rectangle of any size
1059146482Smarius		 * takes about the same number of operations as drawing
1060146482Smarius		 * a single character.
1061146482Smarius		 */
1062146482Smarius		c = s[i] & 0xff;
1063146482Smarius		a = (s[i] & 0xff00) >> 8;
1064146482Smarius		if (c == 0x00 || c == 0x20 || c == 0xdb || c == 0xff) {
1065146482Smarius			color2 = (a >> (c == 0xdb ? 0 : 4) & 0xf);
1066191072Smarius			x2 = (((off + i) % adp->va_info.vi_width) *
1067146482Smarius			    adp->va_info.vi_cwidth) + sc->sc_xmargin;
1068146482Smarius			y2 = (((off + i) / adp->va_info.vi_width) *
1069146482Smarius			    adp->va_info.vi_cheight) + sc->sc_ymargin;
1070146482Smarius			if (blanks == 0) {
1071146482Smarius				color1 = color2;
1072146482Smarius				x1 = x2;
1073146482Smarius				y1 = y2;
1074146482Smarius				blanks++;
1075146482Smarius			} else if (color1 != color2 || y1 != y2) {
1076146482Smarius				MACHFB_BLANK;
1077146482Smarius				color1 = color2;
1078146482Smarius				x1 = x2;
1079146482Smarius				y1 = y2;
1080146482Smarius				blanks = 1;
1081146482Smarius			} else
1082146482Smarius				blanks++;
1083146482Smarius		} else {
1084146482Smarius			if (blanks != 0) {
1085146482Smarius				MACHFB_BLANK;
1086146482Smarius				blanks = 0;
1087146482Smarius			}
1088174985Swkoszek			vidd_putc(adp, off + i, c, a);
1089146482Smarius		}
1090146482Smarius	}
1091146482Smarius	if (blanks != 0)
1092146482Smarius		MACHFB_BLANK;
1093146482Smarius
1094146482Smarius#undef MACHFB_BLANK
1095146482Smarius
1096146482Smarius	return (0);
1097146482Smarius}
1098146482Smarius
1099146482Smariusstatic int
1100146482Smariusmachfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
1101150686Smarius    uint32_t pixel_mask, int size, int width)
1102146482Smarius{
1103146482Smarius	struct machfb_softc *sc;
1104146482Smarius	int error;
1105146482Smarius
1106146482Smarius	sc = (struct machfb_softc *)adp;
1107146482Smarius
1108146482Smarius	if ((!(sc->sc_flags & MACHFB_CUREN)) &&
1109146482Smarius	    (error = machfb_cursor_install(sc)) < 0)
1110191072Smarius		return (error);
1111146482Smarius	else {
1112146482Smarius		/*
1113146482Smarius		 * The hardware cursor always must be disabled when
1114146482Smarius		 * fiddling with its bits otherwise some artifacts
1115146482Smarius		 * may appear on the screen.
1116146482Smarius		 */
1117146482Smarius		machfb_cursor_enable(sc, 0);
1118146482Smarius	}
1119146482Smarius
1120146482Smarius	regw(sc, CUR_HORZ_VERT_OFF, 0);
1121146482Smarius	if ((regr(sc, GEN_TEST_CNTL) & CRTC_DBL_SCAN_EN) != 0)
1122146482Smarius		y <<= 1;
1123146482Smarius	regw(sc, CUR_HORZ_VERT_POSN, ((y + sc->sc_ymargin) << 16) |
1124146482Smarius	    (x + sc->sc_xmargin));
1125146482Smarius	machfb_cursor_enable(sc, 1);
1126146482Smarius	sc->sc_flags |= MACHFB_CUREN;
1127146482Smarius
1128146482Smarius	return (0);
1129146482Smarius}
1130146482Smarius
1131146482Smarius/*
1132146482Smarius * PCI bus interface
1133146482Smarius */
1134146482Smariusstatic int
1135146482Smariusmachfb_pci_probe(device_t dev)
1136146482Smarius{
1137146482Smarius	int i;
1138146482Smarius
1139146482Smarius	if (pci_get_class(dev) != PCIC_DISPLAY ||
1140146482Smarius	    pci_get_subclass(dev) != PCIS_DISPLAY_VGA)
1141146482Smarius		return (ENXIO);
1142146482Smarius
1143146482Smarius	for (i = 0; i < sizeof(machfb_info) / sizeof(machfb_info[0]); i++) {
1144146482Smarius		if (pci_get_device(dev) == machfb_info[i].chip_id) {
1145146482Smarius			device_set_desc(dev, machfb_info[i].name);
1146146482Smarius			return (BUS_PROBE_DEFAULT);
1147146482Smarius		}
1148146482Smarius	}
1149191072Smarius
1150146482Smarius	return (ENXIO);
1151146482Smarius}
1152146482Smarius
1153146482Smariusstatic int
1154146482Smariusmachfb_pci_attach(device_t dev)
1155146482Smarius{
1156146482Smarius	struct machfb_softc *sc;
1157146482Smarius	video_adapter_t *adp;
1158146482Smarius	video_switch_t *sw;
1159191076Smarius	video_info_t *vi;
1160146482Smarius	phandle_t node;
1161191076Smarius	int error, i, rid;
1162191076Smarius	uint32_t *p32, u32;
1163146482Smarius	uint8_t *p;
1164146482Smarius
1165146482Smarius	node = ofw_bus_get_node(dev);
1166146482Smarius	if ((sc = (struct machfb_softc *)vid_get_adapter(vid_find_adapter(
1167146482Smarius	    MACHFB_DRIVER_NAME, 0))) != NULL && sc->sc_node == node) {
1168191072Smarius		device_printf(dev, "console\n");
1169191072Smarius		device_set_softc(dev, sc);
1170146482Smarius	} else {
1171146482Smarius		sc = device_get_softc(dev);
1172146482Smarius
1173146482Smarius		sc->sc_node = node;
1174146482Smarius		sc->sc_chip_id = pci_get_device(dev);
1175146482Smarius		sc->sc_chip_rev = pci_get_revid(dev);
1176146482Smarius	}
1177146482Smarius	adp = &sc->sc_va;
1178191076Smarius	vi = &adp->va_info;
1179191072Smarius
1180191076Smarius	rid = PCIR_BAR(0);
1181230687Smarius	if ((sc->sc_memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1182230687Smarius	    RF_ACTIVE)) == NULL) {
1183146482Smarius		device_printf(dev, "cannot allocate memory resources\n");
1184146482Smarius		return (ENXIO);
1185146482Smarius	}
1186230687Smarius	sc->sc_memt = rman_get_bustag(sc->sc_memres);
1187230687Smarius	sc->sc_memh = rman_get_bushandle(sc->sc_memres);
1188230687Smarius	sc->sc_mem = rman_get_start(sc->sc_memres);
1189230687Smarius	vi->vi_buffer = sc->sc_memh;
1190230687Smarius	vi->vi_buffer_size = rman_get_size(sc->sc_memres);
1191191076Smarius	if (OF_getprop(sc->sc_node, "address", &u32, sizeof(u32)) > 0 &&
1192230687Smarius		vtophys(u32) == sc->sc_memh)
1193191076Smarius		adp->va_mem_base = u32;
1194191076Smarius	else {
1195230687Smarius		if (bus_space_map(sc->sc_memt, vi->vi_buffer,
1196230687Smarius		    vi->vi_buffer_size, BUS_SPACE_MAP_LINEAR,
1197230687Smarius		    &sc->sc_memh) != 0) {
1198230687Smarius			device_printf(dev, "cannot map memory resources\n");
1199230687Smarius			error = ENXIO;
1200230687Smarius			goto fail_memres;
1201191076Smarius		}
1202191076Smarius		adp->va_mem_base =
1203191076Smarius		    (vm_offset_t)rman_get_virtual(sc->sc_memres);
1204191076Smarius	}
1205230687Smarius	adp->va_mem_size = vi->vi_buffer_size;
1206191076Smarius	adp->va_buffer = adp->va_mem_base;
1207191076Smarius	adp->va_buffer_size = adp->va_mem_size;
1208230687Smarius	sc->sc_regt = sc->sc_memt;
1209230687Smarius	if (bus_space_subregion(sc->sc_regt, sc->sc_memh, MACH64_REG_OFF,
1210230687Smarius	    MACH64_REG_SIZE, &sc->sc_regh) != 0) {
1211230687Smarius		device_printf(dev, "cannot allocate register resources\n");
1212230687Smarius		error = ENXIO;
1213230687Smarius		goto fail_memmap;
1214230687Smarius	}
1215146482Smarius
1216146482Smarius	/*
1217146482Smarius	 * Depending on the firmware version the VGA I/O and/or memory
1218230687Smarius	 * resources of the Mach64 chips come up disabled.  These will be
1219230687Smarius	 * enabled by pci(4) when activating the resource in question but
1220230687Smarius	 * this doesn't necessarily mean that the resource is valid.
1221230687Smarius	 * Invalid resources seem to have in common that they start at
1222230687Smarius	 * address 0.  We don't allocate the VGA memory in this case in
1223230687Smarius	 * order to avoid warnings in apb(4) and crashes when using this
1224230687Smarius	 * invalid resources.  X.Org is aware of this and doesn't use the
1225230687Smarius	 * VGA memory resource in this case (but demands it if it's valid).
1226146482Smarius	 */
1227191076Smarius	rid = PCIR_BAR(2);
1228191076Smarius	if (bus_get_resource_start(dev, SYS_RES_MEMORY, rid) != 0) {
1229146482Smarius		if ((sc->sc_vmemres = bus_alloc_resource_any(dev,
1230191076Smarius		    SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL) {
1231146482Smarius			device_printf(dev,
1232146482Smarius			    "cannot allocate VGA memory resources\n");
1233146482Smarius			error = ENXIO;
1234230687Smarius			goto fail_memmap;
1235146482Smarius		}
1236230687Smarius		sc->sc_vmemt = rman_get_bustag(sc->sc_vmemres);
1237230687Smarius		sc->sc_vmemh = rman_get_bushandle(sc->sc_vmemres);
1238230687Smarius		sc->sc_vmem = rman_get_start(sc->sc_vmemres);
1239230687Smarius		vi->vi_registers = sc->sc_vmemh;
1240230687Smarius		vi->vi_registers_size = rman_get_size(sc->sc_vmemres);
1241230687Smarius		if (bus_space_map(sc->sc_vmemt, vi->vi_registers,
1242230687Smarius		    vi->vi_registers_size, BUS_SPACE_MAP_LINEAR,
1243230687Smarius		    &sc->sc_vmemh) != 0) {
1244230687Smarius			device_printf(dev,
1245230687Smarius			    "cannot map VGA memory resources\n");
1246230687Smarius			error = ENXIO;
1247230687Smarius			goto fail_vmemres;
1248230687Smarius		}
1249191076Smarius		adp->va_registers =
1250191076Smarius		    (vm_offset_t)rman_get_virtual(sc->sc_vmemres);
1251230687Smarius		adp->va_registers_size = vi->vi_registers_size;
1252146482Smarius	}
1253146482Smarius
1254146482Smarius	if (!(sc->sc_flags & MACHFB_CONSOLE)) {
1255146482Smarius		if ((sw = vid_get_switch(MACHFB_DRIVER_NAME)) == NULL) {
1256146482Smarius			device_printf(dev, "cannot get video switch\n");
1257146482Smarius			error = ENODEV;
1258230687Smarius			goto fail_vmemmap;
1259146482Smarius		}
1260146482Smarius		/*
1261146482Smarius		 * During device configuration we don't necessarily probe
1262146482Smarius		 * the adapter which is the console first so we can't use
1263191072Smarius		 * the device unit number for the video adapter unit.  The
1264146482Smarius		 * worst case would be that we use the video adapter unit
1265191072Smarius		 * 0 twice.  As it doesn't really matter which unit number
1266146482Smarius		 * the corresponding video adapter has just use the next
1267146482Smarius		 * unused one.
1268146482Smarius		 */
1269146482Smarius		for (i = 0; i < devclass_get_maxunit(machfb_devclass); i++)
1270146482Smarius			if (vid_find_adapter(MACHFB_DRIVER_NAME, i) < 0)
1271146482Smarius				break;
1272146482Smarius		if ((error = sw->init(i, adp, 0)) != 0) {
1273146482Smarius			device_printf(dev, "cannot initialize adapter\n");
1274230687Smarius			goto fail_vmemmap;
1275146482Smarius		}
1276146482Smarius	}
1277146482Smarius
1278146482Smarius	/*
1279146482Smarius	 * Test whether the aperture is byte swapped or not, set
1280191076Smarius	 * va_window and va_window_size as appropriate.  Note that
1281191076Smarius	 * the aperture could be mapped either big or little endian
1282230687Smarius	 * independently of the endianess of the host so this has
1283230687Smarius	 * to be a runtime test.
1284146482Smarius	 */
1285146482Smarius	p32 = (uint32_t *)adp->va_buffer;
1286191076Smarius	u32 = *p32;
1287146482Smarius	p = (uint8_t *)adp->va_buffer;
1288146482Smarius	*p32 = 0x12345678;
1289146482Smarius	if (!(p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78)) {
1290146482Smarius		adp->va_window = adp->va_buffer + 0x800000;
1291146482Smarius		adp->va_window_size = adp->va_buffer_size - 0x800000;
1292191076Smarius		vi->vi_window = vi->vi_buffer + 0x800000;
1293191076Smarius		vi->vi_window_size = vi->vi_buffer_size - 0x800000;
1294191076Smarius		sc->sc_flags |= MACHFB_SWAP;
1295146482Smarius	} else {
1296146482Smarius		adp->va_window = adp->va_buffer;
1297146482Smarius		adp->va_window_size = adp->va_buffer_size;
1298191076Smarius		vi->vi_window = vi->vi_buffer;
1299191076Smarius		vi->vi_window_size = vi->vi_buffer_size;
1300146482Smarius	}
1301191076Smarius	*p32 = u32;
1302146482Smarius	adp->va_window_gran = adp->va_window_size;
1303146482Smarius
1304191076Smarius	device_printf(dev,
1305191076Smarius	    "%d MB aperture at %p %sswapped\n",
1306191076Smarius	    (u_int)(adp->va_window_size / (1024 * 1024)),
1307191076Smarius	    (void *)adp->va_window, (sc->sc_flags & MACHFB_SWAP) ?
1308191076Smarius	    "" : "not ");
1309191076Smarius	device_printf(dev,
1310191076Smarius	    "%ld KB %s %d.%d MHz, maximum RAMDAC clock %d MHz, %sDSP\n",
1311191076Smarius	    (u_long)sc->sc_memsize, machfb_memtype_names[sc->sc_memtype],
1312191076Smarius	    sc->sc_mem_freq / 1000, sc->sc_mem_freq % 1000,
1313191076Smarius	    sc->sc_ramdac_freq / 1000,
1314191076Smarius	    (sc->sc_flags & MACHFB_DSP) ? "" : "no ");
1315191076Smarius	device_printf(dev, "resolution %dx%d at %d bpp\n",
1316191076Smarius	    sc->sc_width, sc->sc_height, sc->sc_depth);
1317191076Smarius
1318146482Smarius	/*
1319146482Smarius	 * Allocate one page for the mouse pointer image at the end of
1320146482Smarius	 * the little endian aperture, right before the memory mapped
1321191072Smarius	 * registers that might also reside there.  Must be done after
1322146482Smarius	 * sc_memsize was set and possibly adjusted to account for the
1323146482Smarius	 * memory mapped registers.
1324146482Smarius	 */
1325146482Smarius	sc->sc_curoff = (sc->sc_memsize * 1024) - PAGE_SIZE;
1326146482Smarius	sc->sc_memsize -= PAGE_SIZE / 1024;
1327146482Smarius	machfb_cursor_enable(sc, 0);
1328146482Smarius	/* Initialize with an all transparent image. */
1329146482Smarius	memset((void *)(adp->va_buffer + sc->sc_curoff), 0xaa, PAGE_SIZE);
1330146482Smarius
1331146482Smarius	/*
1332146971Smarius	 * Register a handler that performs some cosmetic surgery like
1333146971Smarius	 * turning off the mouse pointer on halt in preparation for
1334191072Smarius	 * handing the screen over to the OFW.  Register another handler
1335146971Smarius	 * that turns off the CRTC when resetting, otherwise the OFW
1336146971Smarius	 * boot command issued by cpu_reset() just doesn't work.
1337146482Smarius	 */
1338146482Smarius	EVENTHANDLER_REGISTER(shutdown_final, machfb_shutdown_final, sc,
1339146482Smarius	    SHUTDOWN_PRI_DEFAULT);
1340146482Smarius	EVENTHANDLER_REGISTER(shutdown_reset, machfb_shutdown_reset, sc,
1341146482Smarius	    SHUTDOWN_PRI_DEFAULT);
1342146482Smarius
1343146482Smarius	return (0);
1344146482Smarius
1345230687Smarius fail_vmemmap:
1346230687Smarius	if (adp->va_registers != 0)
1347230687Smarius		bus_space_unmap(sc->sc_vmemt, sc->sc_vmemh,
1348230687Smarius		    vi->vi_registers_size);
1349146482Smarius fail_vmemres:
1350191072Smarius	if (sc->sc_vmemres != NULL)
1351191076Smarius		bus_release_resource(dev, SYS_RES_MEMORY,
1352191076Smarius		    rman_get_rid(sc->sc_vmemres), sc->sc_vmemres);
1353230687Smarius fail_memmap:
1354230687Smarius	bus_space_unmap(sc->sc_memt, sc->sc_memh, vi->vi_buffer_size);
1355146482Smarius fail_memres:
1356191076Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
1357191076Smarius	    rman_get_rid(sc->sc_memres), sc->sc_memres);
1358146482Smarius
1359146482Smarius	return (error);
1360146482Smarius}
1361146482Smarius
1362146482Smariusstatic int
1363146482Smariusmachfb_pci_detach(device_t dev)
1364146482Smarius{
1365146482Smarius
1366146482Smarius	return (EINVAL);
1367146482Smarius}
1368146482Smarius
1369146482Smarius/*
1370146482Smarius * internal functions
1371146482Smarius */
1372146482Smariusstatic void
1373146482Smariusmachfb_cursor_enable(struct machfb_softc *sc, int onoff)
1374146482Smarius{
1375146482Smarius
1376146482Smarius	if (onoff)
1377146482Smarius		regw(sc, GEN_TEST_CNTL,
1378146482Smarius		    regr(sc, GEN_TEST_CNTL) | HWCURSOR_ENABLE);
1379146482Smarius	else
1380146482Smarius		regw(sc, GEN_TEST_CNTL,
1381146482Smarius		    regr(sc, GEN_TEST_CNTL) &~ HWCURSOR_ENABLE);
1382146482Smarius}
1383146482Smarius
1384146482Smariusstatic int
1385146482Smariusmachfb_cursor_install(struct machfb_softc *sc)
1386146482Smarius{
1387191076Smarius	uint16_t *p, v;
1388146482Smarius	uint8_t fg;
1389146482Smarius	int i, j;
1390146482Smarius
1391146482Smarius	if (sc->sc_curoff == 0)
1392146482Smarius		return (ENODEV);
1393146482Smarius
1394146482Smarius	machfb_cursor_enable(sc, 0);
1395146482Smarius	regw(sc, CUR_OFFSET, sc->sc_curoff >> 3);
1396146482Smarius	fg = SC_NORM_ATTR & 0xf;
1397147881Smarius	regw(sc, CUR_CLR0, machfb_default_cmap[fg].red << 24 |
1398147881Smarius	    machfb_default_cmap[fg].green << 16 |
1399147881Smarius	    machfb_default_cmap[fg].blue << 8);
1400146482Smarius	p = (uint16_t *)(sc->sc_va.va_buffer + sc->sc_curoff);
1401191076Smarius	for (i = 0; i < 64; i++) {
1402191076Smarius		for (j = 0; j < 8; j++) {
1403191076Smarius			v = machfb_mouse_pointer_lut[
1404191076Smarius			    machfb_mouse_pointer_bits[i][j] >> 4] << 8 |
1405146482Smarius			    machfb_mouse_pointer_lut[
1406191076Smarius			    machfb_mouse_pointer_bits[i][j] & 0x0f];
1407191076Smarius			if (sc->sc_flags & MACHFB_SWAP)
1408191076Smarius				*(p++) = bswap16(v);
1409191076Smarius			else
1410191076Smarius				*(p++) = v;
1411191076Smarius		}
1412191076Smarius	}
1413146482Smarius
1414146482Smarius	return (0);
1415146482Smarius}
1416146482Smarius
1417146482Smariusstatic int
1418146482Smariusmachfb_get_memsize(struct machfb_softc *sc)
1419146482Smarius{
1420146482Smarius	int tmp, memsize;
1421263764Sdim	const int mem_tab[] = {
1422146482Smarius		512, 1024, 2048, 4096, 6144, 8192, 12288, 16384
1423146482Smarius	};
1424146482Smarius
1425146482Smarius	tmp = regr(sc, MEM_CNTL);
1426146482Smarius#ifdef MACHFB_DEBUG
1427146482Smarius	printf("memcntl=0x%08x\n", tmp);
1428146482Smarius#endif
1429146482Smarius	if (sc->sc_flags & MACHFB_DSP) {
1430146482Smarius		tmp &= 0x0000000f;
1431146482Smarius		if (tmp < 8)
1432146482Smarius			memsize = (tmp + 1) * 512;
1433146482Smarius		else if (tmp < 12)
1434146482Smarius			memsize = (tmp - 3) * 1024;
1435146482Smarius		else
1436146482Smarius			memsize = (tmp - 7) * 2048;
1437146482Smarius	} else
1438146482Smarius		memsize = mem_tab[tmp & 0x07];
1439146482Smarius
1440146482Smarius	return (memsize);
1441146482Smarius}
1442146482Smarius
1443146482Smariusstatic void
1444146482Smariusmachfb_reset_engine(struct machfb_softc *sc)
1445146482Smarius{
1446146482Smarius
1447146482Smarius	/* Reset engine.*/
1448146482Smarius	regw(sc, GEN_TEST_CNTL, regr(sc, GEN_TEST_CNTL) & ~GUI_ENGINE_ENABLE);
1449146482Smarius
1450146482Smarius	/* Enable engine. */
1451146482Smarius	regw(sc, GEN_TEST_CNTL, regr(sc, GEN_TEST_CNTL) | GUI_ENGINE_ENABLE);
1452146482Smarius
1453146482Smarius	/*
1454146482Smarius	 * Ensure engine is not locked up by clearing any FIFO or
1455146482Smarius	 * host errors.
1456146482Smarius	 */
1457146482Smarius	regw(sc, BUS_CNTL, regr(sc, BUS_CNTL) | BUS_HOST_ERR_ACK |
1458146482Smarius	    BUS_FIFO_ERR_ACK);
1459146482Smarius}
1460146482Smarius
1461146482Smariusstatic void
1462146482Smariusmachfb_init_engine(struct machfb_softc *sc)
1463146482Smarius{
1464146482Smarius	uint32_t pitch_value;
1465146482Smarius
1466146482Smarius	pitch_value = sc->sc_width;
1467146482Smarius
1468146482Smarius	if (sc->sc_depth == 24)
1469146482Smarius		pitch_value *= 3;
1470146482Smarius
1471146482Smarius	machfb_reset_engine(sc);
1472146482Smarius
1473146482Smarius	wait_for_fifo(sc, 14);
1474146482Smarius
1475146482Smarius	regw(sc, CONTEXT_MASK, 0xffffffff);
1476146482Smarius
1477146482Smarius	regw(sc, DST_OFF_PITCH, (pitch_value / 8) << 22);
1478146482Smarius
1479146482Smarius	regw(sc, DST_Y_X, 0);
1480146482Smarius	regw(sc, DST_HEIGHT, 0);
1481146482Smarius	regw(sc, DST_BRES_ERR, 0);
1482146482Smarius	regw(sc, DST_BRES_INC, 0);
1483146482Smarius	regw(sc, DST_BRES_DEC, 0);
1484146482Smarius
1485146482Smarius	regw(sc, DST_CNTL, DST_LAST_PEL | DST_X_LEFT_TO_RIGHT |
1486146482Smarius	    DST_Y_TOP_TO_BOTTOM);
1487146482Smarius
1488146482Smarius	regw(sc, SRC_OFF_PITCH, (pitch_value / 8) << 22);
1489146482Smarius
1490146482Smarius	regw(sc, SRC_Y_X, 0);
1491146482Smarius	regw(sc, SRC_HEIGHT1_WIDTH1, 1);
1492146482Smarius	regw(sc, SRC_Y_X_START, 0);
1493146482Smarius	regw(sc, SRC_HEIGHT2_WIDTH2, 1);
1494146482Smarius
1495146482Smarius	regw(sc, SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT);
1496146482Smarius
1497146482Smarius	wait_for_fifo(sc, 13);
1498146482Smarius	regw(sc, HOST_CNTL, 0);
1499146482Smarius
1500146482Smarius	regw(sc, PAT_REG0, 0);
1501146482Smarius	regw(sc, PAT_REG1, 0);
1502146482Smarius	regw(sc, PAT_CNTL, 0);
1503146482Smarius
1504146482Smarius	regw(sc, SC_LEFT, 0);
1505146482Smarius	regw(sc, SC_TOP, 0);
1506146482Smarius	regw(sc, SC_BOTTOM, sc->sc_height - 1);
1507146482Smarius	regw(sc, SC_RIGHT, pitch_value - 1);
1508146482Smarius
1509146482Smarius	regw(sc, DP_BKGD_CLR, 0);
1510146482Smarius	regw(sc, DP_FRGD_CLR, 0xffffffff);
1511146482Smarius	regw(sc, DP_WRITE_MASK, 0xffffffff);
1512146482Smarius	regw(sc, DP_MIX, (MIX_SRC << 16) | MIX_DST);
1513146482Smarius
1514146482Smarius	regw(sc, DP_SRC, FRGD_SRC_FRGD_CLR);
1515146482Smarius
1516146482Smarius	wait_for_fifo(sc, 3);
1517146482Smarius	regw(sc, CLR_CMP_CLR, 0);
1518146482Smarius	regw(sc, CLR_CMP_MASK, 0xffffffff);
1519146482Smarius	regw(sc, CLR_CMP_CNTL, 0);
1520146482Smarius
1521146482Smarius	wait_for_fifo(sc, 2);
1522146482Smarius	switch (sc->sc_depth) {
1523146482Smarius	case 8:
1524146482Smarius		regw(sc, DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP);
1525146482Smarius		regw(sc, DP_CHAIN_MASK, DP_CHAIN_8BPP);
1526146482Smarius		regw(sc, DAC_CNTL, regr(sc, DAC_CNTL) | DAC_8BIT_EN);
1527146482Smarius		break;
1528146482Smarius#if 0
1529146482Smarius	case 32:
1530146482Smarius		regw(sc, DP_PIX_WIDTH, HOST_32BPP | SRC_32BPP | DST_32BPP);
1531146482Smarius		regw(sc, DP_CHAIN_MASK, DP_CHAIN_32BPP);
1532146482Smarius		regw(sc, DAC_CNTL, regr(sc, DAC_CNTL) | DAC_8BIT_EN);
1533146482Smarius		break;
1534146482Smarius#endif
1535146482Smarius	}
1536146482Smarius
1537147881Smarius	wait_for_fifo(sc, 2);
1538146482Smarius	regw(sc, CRTC_INT_CNTL, regr(sc, CRTC_INT_CNTL) & ~0x20);
1539146482Smarius	regw(sc, GUI_TRAJ_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
1540146482Smarius
1541146482Smarius	wait_for_idle(sc);
1542146482Smarius}
1543146482Smarius
1544146482Smarius#if 0
1545146482Smariusstatic void
1546146482Smariusmachfb_adjust_frame(struct machfb_softc *sc, int x, int y)
1547146482Smarius{
1548146482Smarius	int offset;
1549146482Smarius
1550146482Smarius	offset = ((x + y * sc->sc_width) * (sc->sc_depth >> 3)) >> 3;
1551146482Smarius
1552146482Smarius	regw(sc, CRTC_OFF_PITCH, (regr(sc, CRTC_OFF_PITCH) & 0xfff00000) |
1553191072Smarius	    offset);
1554146482Smarius}
1555146482Smarius#endif
1556146482Smarius
1557146482Smariusstatic void
1558146482Smariusmachfb_shutdown_final(void *v)
1559146482Smarius{
1560146482Smarius	struct machfb_softc *sc = v;
1561146482Smarius
1562146482Smarius	machfb_cursor_enable(sc, 0);
1563146971Smarius	/*
1564146971Smarius	 * In case this is the console set the cursor of the stdout
1565146971Smarius	 * instance to the start of the last line so OFW output ends
1566146971Smarius	 * up beneath what FreeBSD left on the screen.
1567146971Smarius	 */
1568146971Smarius	if (sc->sc_flags & MACHFB_CONSOLE) {
1569146971Smarius		OF_interpret("stdout @ is my-self 0 to column#", 0);
1570146971Smarius		OF_interpret("stdout @ is my-self #lines 1 - to line#", 0);
1571146971Smarius	}
1572146482Smarius}
1573146482Smarius
1574146482Smariusstatic void
1575146482Smariusmachfb_shutdown_reset(void *v)
1576146482Smarius{
1577146482Smarius	struct machfb_softc *sc = v;
1578146482Smarius
1579146482Smarius	machfb_blank_display(&sc->sc_va, V_DISPLAY_STAND_BY);
1580146482Smarius}
1581