1*e5fbc36aSthorpej /* $NetBSD: crmfb.c,v 1.50 2023/12/20 15:29:07 thorpej Exp $ */
2d4c79dc9Sjmcneill
3d4c79dc9Sjmcneill /*-
4d4c79dc9Sjmcneill * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
5b86243deSmacallan * 2008 Michael Lorenz <macallan@netbsd.org>
6d4c79dc9Sjmcneill * All rights reserved.
7d4c79dc9Sjmcneill *
8d4c79dc9Sjmcneill * Redistribution and use in source and binary forms, with or without
9d4c79dc9Sjmcneill * modification, are permitted provided that the following conditions
10d4c79dc9Sjmcneill * are met:
11d4c79dc9Sjmcneill * 1. Redistributions of source code must retain the above copyright
12d4c79dc9Sjmcneill * notice, this list of conditions and the following disclaimer.
13d4c79dc9Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
14d4c79dc9Sjmcneill * notice, this list of conditions and the following disclaimer in the
15d4c79dc9Sjmcneill * documentation and/or other materials provided with the distribution.
16d4c79dc9Sjmcneill *
17d4c79dc9Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18d4c79dc9Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19d4c79dc9Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20d4c79dc9Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21d4c79dc9Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22d4c79dc9Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23d4c79dc9Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24d4c79dc9Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25d4c79dc9Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26d4c79dc9Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27d4c79dc9Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
28d4c79dc9Sjmcneill */
29d4c79dc9Sjmcneill
30d4c79dc9Sjmcneill /*
31d4c79dc9Sjmcneill * SGI-CRM (O2) Framebuffer driver
32d4c79dc9Sjmcneill */
33d4c79dc9Sjmcneill
34d4c79dc9Sjmcneill #include <sys/cdefs.h>
35*e5fbc36aSthorpej __KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.50 2023/12/20 15:29:07 thorpej Exp $");
36d4c79dc9Sjmcneill
37d4c79dc9Sjmcneill #include <sys/param.h>
38d4c79dc9Sjmcneill #include <sys/systm.h>
39d4c79dc9Sjmcneill #include <sys/device.h>
40d4c79dc9Sjmcneill
41d4c79dc9Sjmcneill #include <machine/autoconf.h>
42cf10107dSdyoung #include <sys/bus.h>
43d4c79dc9Sjmcneill #include <machine/machtype.h>
44d4c79dc9Sjmcneill #include <machine/vmparam.h>
45d4c79dc9Sjmcneill
467abea6b5Sjmcneill #include <dev/arcbios/arcbios.h>
477abea6b5Sjmcneill #include <dev/arcbios/arcbiosvar.h>
487abea6b5Sjmcneill
49d4c79dc9Sjmcneill #include <dev/wscons/wsdisplayvar.h>
50d4c79dc9Sjmcneill #include <dev/wscons/wsconsio.h>
51d4c79dc9Sjmcneill #include <dev/wsfont/wsfont.h>
52d4c79dc9Sjmcneill #include <dev/rasops/rasops.h>
53d4c79dc9Sjmcneill #include <dev/wscons/wsdisplay_vconsvar.h>
54d4c79dc9Sjmcneill
559b94525aSmacallan #include <dev/i2c/i2cvar.h>
569b94525aSmacallan #include <dev/i2c/i2c_bitbang.h>
579b94525aSmacallan #include <dev/i2c/ddcvar.h>
589b94525aSmacallan #include <dev/videomode/videomode.h>
5995923c6fSjmcneill #include <dev/videomode/vesagtf.h>
609b94525aSmacallan #include <dev/videomode/edidvar.h>
619b94525aSmacallan
620904724eSmacallan #include <arch/sgimips/dev/crmfbreg.h>
630904724eSmacallan
64713b73c8Smacallan #include "opt_crmfb.h"
65713b73c8Smacallan
66713b73c8Smacallan #ifdef CRMFB_DEBUG
67713b73c8Smacallan #define DPRINTF printf
68713b73c8Smacallan #else
69713b73c8Smacallan #define DPRINTF while (0) printf
70713b73c8Smacallan #endif
71b7875ec4Sjmcneill
72d4c79dc9Sjmcneill struct wsscreen_descr crmfb_defaultscreen = {
73d4c79dc9Sjmcneill "default",
74d4c79dc9Sjmcneill 0, 0,
75d4c79dc9Sjmcneill NULL,
76d4c79dc9Sjmcneill 8, 16,
77733da76fSmacallan WSSCREEN_WSCOLORS | WSSCREEN_RESIZE,
78d4c79dc9Sjmcneill NULL,
79d4c79dc9Sjmcneill };
80d4c79dc9Sjmcneill
81d4c79dc9Sjmcneill const struct wsscreen_descr *_crmfb_scrlist[] = {
82d4c79dc9Sjmcneill &crmfb_defaultscreen,
83d4c79dc9Sjmcneill };
84d4c79dc9Sjmcneill
85d4c79dc9Sjmcneill struct wsscreen_list crmfb_screenlist = {
86d4c79dc9Sjmcneill sizeof(_crmfb_scrlist) / sizeof(struct wsscreen_descr *),
87d4c79dc9Sjmcneill _crmfb_scrlist
88d4c79dc9Sjmcneill };
89d4c79dc9Sjmcneill
90d4c79dc9Sjmcneill static struct vcons_screen crmfb_console_screen;
91d4c79dc9Sjmcneill
92d4c79dc9Sjmcneill static int crmfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
93d4c79dc9Sjmcneill static paddr_t crmfb_mmap(void *, void *, off_t, int);
94d4c79dc9Sjmcneill static void crmfb_init_screen(void *, struct vcons_screen *, int, long *);
95d4c79dc9Sjmcneill
96d4c79dc9Sjmcneill struct wsdisplay_accessops crmfb_accessops = {
97d4c79dc9Sjmcneill crmfb_ioctl,
98d4c79dc9Sjmcneill crmfb_mmap,
99d4c79dc9Sjmcneill NULL, /* alloc_screen */
100d4c79dc9Sjmcneill NULL, /* free_screen */
101d4c79dc9Sjmcneill NULL, /* show_screen */
102d4c79dc9Sjmcneill NULL, /* load_font */
103d4c79dc9Sjmcneill NULL, /* pollc */
104d4c79dc9Sjmcneill NULL, /* scroll */
105d4c79dc9Sjmcneill };
106d4c79dc9Sjmcneill
107d4c79dc9Sjmcneill /* Memory to allocate to SGI-CRM -- remember, this is stolen from
108d4c79dc9Sjmcneill * host memory!
109d4c79dc9Sjmcneill */
110d4c79dc9Sjmcneill #define CRMFB_TILESIZE (512*128)
111d4c79dc9Sjmcneill
112e313f620Smacallan static int crmfb_match(device_t, struct cfdata *, void *);
113e313f620Smacallan static void crmfb_attach(device_t, device_t, void *);
114d4c79dc9Sjmcneill int crmfb_probe(void);
115d4c79dc9Sjmcneill
116d4c79dc9Sjmcneill #define KERNADDR(p) ((void *)((p).addr))
117d4c79dc9Sjmcneill #define DMAADDR(p) ((p).map->dm_segs[0].ds_addr)
118d4c79dc9Sjmcneill
119ab0a73e2Ssekiya #define CRMFB_REG_MASK(msb, lsb) \
120ab0a73e2Ssekiya ( (((uint32_t) 1 << ((msb)-(lsb)+1)) - 1) << (lsb) )
121ab0a73e2Ssekiya
122ab0a73e2Ssekiya
123d4c79dc9Sjmcneill struct crmfb_dma {
124d4c79dc9Sjmcneill bus_dmamap_t map;
125d4c79dc9Sjmcneill void *addr;
126d4c79dc9Sjmcneill bus_dma_segment_t segs[1];
127d4c79dc9Sjmcneill int nsegs;
128d4c79dc9Sjmcneill size_t size;
129d4c79dc9Sjmcneill };
130d4c79dc9Sjmcneill
131d4c79dc9Sjmcneill struct crmfb_softc {
132e313f620Smacallan device_t sc_dev;
133d4c79dc9Sjmcneill struct vcons_data sc_vd;
1349b94525aSmacallan struct i2c_controller sc_i2c;
1359b94525aSmacallan int sc_dir;
136d4c79dc9Sjmcneill
137d4c79dc9Sjmcneill bus_space_tag_t sc_iot;
138d4c79dc9Sjmcneill bus_space_handle_t sc_ioh;
139c5904c10Smacallan bus_space_handle_t sc_reh;
1400904724eSmacallan
141d4c79dc9Sjmcneill bus_dma_tag_t sc_dmat;
142d4c79dc9Sjmcneill
143d4c79dc9Sjmcneill struct crmfb_dma sc_dma;
144d4c79dc9Sjmcneill struct crmfb_dma sc_dmai;
145d4c79dc9Sjmcneill
146d4c79dc9Sjmcneill int sc_width;
147d4c79dc9Sjmcneill int sc_height;
148d4c79dc9Sjmcneill int sc_depth;
149fa88ee42Smacallan int sc_console_depth;
150c5904c10Smacallan int sc_tiles_x, sc_tiles_y;
151d4c79dc9Sjmcneill uint32_t sc_fbsize;
152dca5aa4eSmacallan int sc_mte_direction;
153fa88ee42Smacallan int sc_mte_x_shift;
154fa88ee42Smacallan uint32_t sc_mte_mode;
15571305eb6Smacallan uint32_t sc_de_mode;
156a2db4fbdSmacallan uint32_t sc_src_mode;
157a2db4fbdSmacallan uint32_t sc_dst_mode;
158a2db4fbdSmacallan int sc_needs_sync;
159a2db4fbdSmacallan uint8_t *sc_lptr;
1604750dcc2Smacallan paddr_t sc_linear;
16171305eb6Smacallan uint32_t sc_vtflags;
16271305eb6Smacallan int sc_wsmode, sc_video_on;
16371305eb6Smacallan uint8_t sc_edid_data[128];
164713b73c8Smacallan struct edid_info sc_edid_info;
165d2924302Smacallan
166d2924302Smacallan /* cursor stuff */
167d2924302Smacallan int sc_cur_x;
168d2924302Smacallan int sc_cur_y;
169d2924302Smacallan int sc_hot_x;
170d2924302Smacallan int sc_hot_y;
171d2924302Smacallan
172d4c79dc9Sjmcneill u_char sc_cmap_red[256];
173d4c79dc9Sjmcneill u_char sc_cmap_green[256];
174d4c79dc9Sjmcneill u_char sc_cmap_blue[256];
175d4c79dc9Sjmcneill };
176d4c79dc9Sjmcneill
177d4c79dc9Sjmcneill static int crmfb_putcmap(struct crmfb_softc *, struct wsdisplay_cmap *);
178d4c79dc9Sjmcneill static int crmfb_getcmap(struct crmfb_softc *, struct wsdisplay_cmap *);
179d4c79dc9Sjmcneill static void crmfb_set_palette(struct crmfb_softc *,
180d4c79dc9Sjmcneill int, uint8_t, uint8_t, uint8_t);
181d2924302Smacallan static int crmfb_set_curpos(struct crmfb_softc *, int, int);
182d2924302Smacallan static int crmfb_gcursor(struct crmfb_softc *, struct wsdisplay_cursor *);
183d2924302Smacallan static int crmfb_scursor(struct crmfb_softc *, struct wsdisplay_cursor *);
1840904724eSmacallan static inline void crmfb_write_reg(struct crmfb_softc *, int, uint32_t);
185c5904c10Smacallan static inline uint32_t crmfb_read_reg(struct crmfb_softc *, int);
186c5904c10Smacallan static int crmfb_wait_dma_idle(struct crmfb_softc *);
1870904724eSmacallan
1880904724eSmacallan /* setup video hw in given colour depth */
1890904724eSmacallan static int crmfb_setup_video(struct crmfb_softc *, int);
1900904724eSmacallan static void crmfb_setup_palette(struct crmfb_softc *);
191d4c79dc9Sjmcneill
192c5904c10Smacallan static void crmfb_fill_rect(struct crmfb_softc *, int, int, int, int, uint32_t);
193c5904c10Smacallan static void crmfb_bitblt(struct crmfb_softc *, int, int, int, int, int, int,
194c5904c10Smacallan uint32_t);
195eceb35ecSmacallan static void crmfb_scroll(struct crmfb_softc *, int, int, int, int, int, int);
196c5904c10Smacallan
197c5904c10Smacallan static void crmfb_copycols(void *, int, int, int, int);
198c5904c10Smacallan static void crmfb_erasecols(void *, int, int, int, long);
199c5904c10Smacallan static void crmfb_copyrows(void *, int, int, int);
200c5904c10Smacallan static void crmfb_eraserows(void *, int, int, long);
201c5904c10Smacallan static void crmfb_cursor(void *, int, int, int);
202c5904c10Smacallan static void crmfb_putchar(void *, int, int, u_int, long);
203a2db4fbdSmacallan static void crmfb_putchar_aa(void *, int, int, u_int, long);
204c5904c10Smacallan
2059b94525aSmacallan /* I2C glue */
2069b94525aSmacallan static int crmfb_i2c_send_start(void *, int);
2079b94525aSmacallan static int crmfb_i2c_send_stop(void *, int);
2089b94525aSmacallan static int crmfb_i2c_initiate_xfer(void *, i2c_addr_t, int);
2099b94525aSmacallan static int crmfb_i2c_read_byte(void *, uint8_t *, int);
2109b94525aSmacallan static int crmfb_i2c_write_byte(void *, uint8_t, int);
2119b94525aSmacallan
2129b94525aSmacallan /* I2C bitbang glue */
2139b94525aSmacallan static void crmfb_i2cbb_set_bits(void *, uint32_t);
2149b94525aSmacallan static void crmfb_i2cbb_set_dir(void *, uint32_t);
2159b94525aSmacallan static uint32_t crmfb_i2cbb_read(void *);
2169b94525aSmacallan
2179b94525aSmacallan static const struct i2c_bitbang_ops crmfb_i2cbb_ops = {
2189b94525aSmacallan crmfb_i2cbb_set_bits,
2199b94525aSmacallan crmfb_i2cbb_set_dir,
2209b94525aSmacallan crmfb_i2cbb_read,
2219b94525aSmacallan {
2229b94525aSmacallan CRMFB_I2C_SDA,
2239b94525aSmacallan CRMFB_I2C_SCL,
2249b94525aSmacallan 0,
2259b94525aSmacallan 1
2269b94525aSmacallan }
2279b94525aSmacallan };
2289b94525aSmacallan static void crmfb_setup_ddc(struct crmfb_softc *);
2299b94525aSmacallan
230713b73c8Smacallan /* mode setting stuff */
231713b73c8Smacallan static uint32_t calc_pll(int); /* frequency in kHz */
232713b73c8Smacallan static int crmfb_set_mode(struct crmfb_softc *, const struct videomode *);
23395923c6fSjmcneill static int crmfb_parse_mode(const char *, struct videomode *);
234713b73c8Smacallan
235e313f620Smacallan CFATTACH_DECL_NEW(crmfb, sizeof(struct crmfb_softc),
236d4c79dc9Sjmcneill crmfb_match, crmfb_attach, NULL, NULL);
237d4c79dc9Sjmcneill
238d4c79dc9Sjmcneill static int
crmfb_match(device_t parent,struct cfdata * cf,void * opaque)239e313f620Smacallan crmfb_match(device_t parent, struct cfdata *cf, void *opaque)
240d4c79dc9Sjmcneill {
241d4c79dc9Sjmcneill return crmfb_probe();
242d4c79dc9Sjmcneill }
243d4c79dc9Sjmcneill
244d4c79dc9Sjmcneill static void
crmfb_attach(device_t parent,device_t self,void * opaque)245e313f620Smacallan crmfb_attach(device_t parent, device_t self, void *opaque)
246d4c79dc9Sjmcneill {
247d4c79dc9Sjmcneill struct mainbus_attach_args *ma;
248d4c79dc9Sjmcneill struct crmfb_softc *sc;
249d4c79dc9Sjmcneill struct rasops_info *ri;
250d4c79dc9Sjmcneill struct wsemuldisplaydev_attach_args aa;
251d4c79dc9Sjmcneill uint32_t d, h;
252d4c79dc9Sjmcneill uint16_t *p;
253d4c79dc9Sjmcneill unsigned long v;
254d4c79dc9Sjmcneill long defattr;
2557abea6b5Sjmcneill const char *consdev;
25695923c6fSjmcneill const char *modestr;
25795923c6fSjmcneill struct videomode mode, *pmode;
258c5904c10Smacallan int rv, i;
259d4c79dc9Sjmcneill
260e313f620Smacallan sc = device_private(self);
261e313f620Smacallan sc->sc_dev = self;
262e313f620Smacallan
263d4c79dc9Sjmcneill ma = (struct mainbus_attach_args *)opaque;
264d4c79dc9Sjmcneill
265eb488f67Smacallan sc->sc_iot = normal_memt;
266d4c79dc9Sjmcneill sc->sc_dmat = &sgimips_default_bus_dma_tag;
267d4c79dc9Sjmcneill sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
268d4c79dc9Sjmcneill
269d4c79dc9Sjmcneill aprint_normal(": SGI CRIME Graphics Display Engine\n");
270d4c79dc9Sjmcneill rv = bus_space_map(sc->sc_iot, ma->ma_addr, 0 /* XXX */,
271d4c79dc9Sjmcneill BUS_SPACE_MAP_LINEAR, &sc->sc_ioh);
272d4c79dc9Sjmcneill if (rv)
273d4c79dc9Sjmcneill panic("crmfb_attach: can't map I/O space");
274c5904c10Smacallan rv = bus_space_map(sc->sc_iot, 0x15000000, 0x6000, 0, &sc->sc_reh);
275c5904c10Smacallan if (rv)
276c5904c10Smacallan panic("crmfb_attach: can't map rendering engine");
277d4c79dc9Sjmcneill
278d4c79dc9Sjmcneill /* determine mode configured by firmware */
279d4c79dc9Sjmcneill d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP);
280479b0a08Sjmcneill sc->sc_width = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff;
281479b0a08Sjmcneill d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_VCMAP);
282479b0a08Sjmcneill sc->sc_height = (d >> CRMFB_VT_VCMAP_ON_SHIFT) & 0xfff;
283d4c79dc9Sjmcneill d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE);
284d4c79dc9Sjmcneill h = (d >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 0x3;
285d4c79dc9Sjmcneill if (h == 0)
286d4c79dc9Sjmcneill sc->sc_depth = 8;
287d4c79dc9Sjmcneill else if (h == 1)
288d4c79dc9Sjmcneill sc->sc_depth = 16;
289d4c79dc9Sjmcneill else
290d4c79dc9Sjmcneill sc->sc_depth = 32;
291d4c79dc9Sjmcneill
29266684959Smartin if (sc->sc_width == 0 || sc->sc_height == 0) {
29371305eb6Smacallan /*
29471305eb6Smacallan * XXX
29571305eb6Smacallan * actually, these days we probably could
29671305eb6Smacallan */
297e313f620Smacallan aprint_error_dev(sc->sc_dev,
298e313f620Smacallan "device unusable if not setup by firmware\n");
29966684959Smartin bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0 /* XXX */);
30066684959Smartin return;
30166684959Smartin }
30266684959Smartin
303e313f620Smacallan aprint_normal_dev(sc->sc_dev, "initial resolution %dx%d\n",
304e313f620Smacallan sc->sc_width, sc->sc_height);
305d4c79dc9Sjmcneill
306fa88ee42Smacallan sc->sc_console_depth = 8;
307fa88ee42Smacallan
308713b73c8Smacallan crmfb_setup_ddc(sc);
30995923c6fSjmcneill pmode = sc->sc_edid_info.edid_preferred_mode;
31095923c6fSjmcneill
31195923c6fSjmcneill modestr = arcbios_GetEnvironmentVariable("crmfb_mode");
31295923c6fSjmcneill if (crmfb_parse_mode(modestr, &mode) == 0)
31395923c6fSjmcneill pmode = &mode;
31495923c6fSjmcneill
31595923c6fSjmcneill if (pmode != NULL && crmfb_set_mode(sc, pmode))
316713b73c8Smacallan aprint_normal_dev(sc->sc_dev, "using %dx%d\n",
317713b73c8Smacallan sc->sc_width, sc->sc_height);
31895923c6fSjmcneill
3190904724eSmacallan /*
3200904724eSmacallan * first determine how many tiles we need
3210904724eSmacallan * in 32bit each tile is 128x128 pixels
3220904724eSmacallan */
323c5904c10Smacallan sc->sc_tiles_x = (sc->sc_width + 127) >> 7;
324c5904c10Smacallan sc->sc_tiles_y = (sc->sc_height + 127) >> 7;
325c5904c10Smacallan sc->sc_fbsize = 0x10000 * sc->sc_tiles_x * sc->sc_tiles_y;
326d4c79dc9Sjmcneill
3270904724eSmacallan sc->sc_dmai.size = 256 * sizeof(uint16_t);
328d4c79dc9Sjmcneill rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmai.size, 65536, 0,
329d4c79dc9Sjmcneill sc->sc_dmai.segs,
330d4c79dc9Sjmcneill sizeof(sc->sc_dmai.segs) / sizeof(sc->sc_dmai.segs[0]),
331d4c79dc9Sjmcneill &sc->sc_dmai.nsegs, BUS_DMA_NOWAIT);
332d4c79dc9Sjmcneill if (rv)
333d4c79dc9Sjmcneill panic("crmfb_attach: can't allocate DMA memory");
334d4c79dc9Sjmcneill rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dmai.segs, sc->sc_dmai.nsegs,
335d4c79dc9Sjmcneill sc->sc_dmai.size, &sc->sc_dmai.addr,
336d4c79dc9Sjmcneill BUS_DMA_NOWAIT);
337d4c79dc9Sjmcneill if (rv)
338d4c79dc9Sjmcneill panic("crmfb_attach: can't map DMA memory");
339d4c79dc9Sjmcneill rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dmai.size, 1,
340d4c79dc9Sjmcneill sc->sc_dmai.size, 0, BUS_DMA_NOWAIT, &sc->sc_dmai.map);
341d4c79dc9Sjmcneill if (rv)
342d4c79dc9Sjmcneill panic("crmfb_attach: can't create DMA map");
343d4c79dc9Sjmcneill rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmai.map, sc->sc_dmai.addr,
344d4c79dc9Sjmcneill sc->sc_dmai.size, NULL, BUS_DMA_NOWAIT);
345d4c79dc9Sjmcneill if (rv)
346d4c79dc9Sjmcneill panic("crmfb_attach: can't load DMA map");
347d4c79dc9Sjmcneill
348a2db4fbdSmacallan /* allocate an extra 128Kb for a linear buffer */
349a2db4fbdSmacallan sc->sc_dma.size = 0x10000 * (16 * sc->sc_tiles_x + 2);
350d4c79dc9Sjmcneill rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0,
351d4c79dc9Sjmcneill sc->sc_dma.segs,
352d4c79dc9Sjmcneill sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]),
353d4c79dc9Sjmcneill &sc->sc_dma.nsegs, BUS_DMA_NOWAIT);
354d4c79dc9Sjmcneill if (rv)
355d4c79dc9Sjmcneill panic("crmfb_attach: can't allocate DMA memory");
356d4c79dc9Sjmcneill rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dma.segs, sc->sc_dma.nsegs,
357d4c79dc9Sjmcneill sc->sc_dma.size, &sc->sc_dma.addr,
358d4c79dc9Sjmcneill BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
359d4c79dc9Sjmcneill if (rv)
360d4c79dc9Sjmcneill panic("crmfb_attach: can't map DMA memory");
361d4c79dc9Sjmcneill rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dma.size, 1,
362d4c79dc9Sjmcneill sc->sc_dma.size, 0, BUS_DMA_NOWAIT, &sc->sc_dma.map);
363d4c79dc9Sjmcneill if (rv)
364d4c79dc9Sjmcneill panic("crmfb_attach: can't create DMA map");
365733da76fSmacallan
366d4c79dc9Sjmcneill rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr,
367d4c79dc9Sjmcneill sc->sc_dma.size, NULL, BUS_DMA_NOWAIT);
368d4c79dc9Sjmcneill if (rv)
369d4c79dc9Sjmcneill panic("crmfb_attach: can't load DMA map");
370d4c79dc9Sjmcneill
371d4c79dc9Sjmcneill p = KERNADDR(sc->sc_dmai);
372d4c79dc9Sjmcneill v = (unsigned long)DMAADDR(sc->sc_dma);
373c5904c10Smacallan for (i = 0; i < (sc->sc_tiles_x * sc->sc_tiles_y); i++) {
374d4c79dc9Sjmcneill p[i] = ((uint32_t)v >> 16) + i;
375d4c79dc9Sjmcneill }
376733da76fSmacallan
377a8858674Stsutsui bus_dmamap_sync(sc->sc_dmat, sc->sc_dmai.map, 0, sc->sc_dmai.size,
378a8858674Stsutsui BUS_DMASYNC_PREWRITE);
379733da76fSmacallan
3804750dcc2Smacallan sc->sc_linear = (paddr_t)DMAADDR(sc->sc_dma) + 0x100000 * sc->sc_tiles_x;
381a2db4fbdSmacallan sc->sc_lptr = (char *)KERNADDR(sc->sc_dma) + (0x100000 * sc->sc_tiles_x);
382d4c79dc9Sjmcneill
383e313f620Smacallan aprint_normal_dev(sc->sc_dev, "allocated %d byte fb @ %p (%p)\n",
384d4c79dc9Sjmcneill sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma));
385d4c79dc9Sjmcneill
386fa88ee42Smacallan crmfb_setup_video(sc, sc->sc_console_depth);
387d4c79dc9Sjmcneill ri = &crmfb_console_screen.scr_ri;
388d4c79dc9Sjmcneill memset(ri, 0, sizeof(struct rasops_info));
38971305eb6Smacallan sc->sc_video_on = 1;
390d4c79dc9Sjmcneill
391d4c79dc9Sjmcneill vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops);
392d4c79dc9Sjmcneill sc->sc_vd.init_screen = crmfb_init_screen;
393d4c79dc9Sjmcneill crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
394d4c79dc9Sjmcneill vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr);
395d4c79dc9Sjmcneill
396d4c79dc9Sjmcneill crmfb_defaultscreen.ncols = ri->ri_cols;
397d4c79dc9Sjmcneill crmfb_defaultscreen.nrows = ri->ri_rows;
398d4c79dc9Sjmcneill crmfb_defaultscreen.textops = &ri->ri_ops;
399d4c79dc9Sjmcneill crmfb_defaultscreen.capabilities = ri->ri_caps;
400d4c79dc9Sjmcneill crmfb_defaultscreen.modecookie = NULL;
401d4c79dc9Sjmcneill
4020904724eSmacallan crmfb_setup_palette(sc);
4039a7aee14Smacallan crmfb_fill_rect(sc, 0, 0, sc->sc_width, sc->sc_height,
4044395e1ddSmacallan ri->ri_devcmap[(defattr >> 16) & 0xff]);
405d4c79dc9Sjmcneill
40623347d39Smatt consdev = arcbios_GetEnvironmentVariable("ConsoleOut");
4077abea6b5Sjmcneill if (consdev != NULL && strcmp(consdev, "video()") == 0) {
408d4c79dc9Sjmcneill wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr);
4095bf2d324Smacallan vcons_replay_msgbuf(&crmfb_console_screen);
410d4c79dc9Sjmcneill aa.console = 1;
4117abea6b5Sjmcneill } else
4127abea6b5Sjmcneill aa.console = 0;
413d4c79dc9Sjmcneill aa.scrdata = &crmfb_screenlist;
414d4c79dc9Sjmcneill aa.accessops = &crmfb_accessops;
415d4c79dc9Sjmcneill aa.accesscookie = &sc->sc_vd;
416d4c79dc9Sjmcneill
417c7fb772bSthorpej config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
418d4c79dc9Sjmcneill
419d2924302Smacallan sc->sc_cur_x = 0;
420d2924302Smacallan sc->sc_cur_y = 0;
421d2924302Smacallan sc->sc_hot_x = 0;
422d2924302Smacallan sc->sc_hot_y = 0;
423d2924302Smacallan
424d4c79dc9Sjmcneill return;
425d4c79dc9Sjmcneill }
426d4c79dc9Sjmcneill
427d4c79dc9Sjmcneill int
crmfb_probe(void)428d4c79dc9Sjmcneill crmfb_probe(void)
429d4c79dc9Sjmcneill {
430d4c79dc9Sjmcneill
431d4c79dc9Sjmcneill if (mach_type != MACH_SGI_IP32)
432d4c79dc9Sjmcneill return 0;
433d4c79dc9Sjmcneill
434d4c79dc9Sjmcneill return 1;
435d4c79dc9Sjmcneill }
436d4c79dc9Sjmcneill
437d4c79dc9Sjmcneill static int
crmfb_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)438d4c79dc9Sjmcneill crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
439d4c79dc9Sjmcneill {
440d4c79dc9Sjmcneill struct vcons_data *vd;
441d4c79dc9Sjmcneill struct crmfb_softc *sc;
442d4c79dc9Sjmcneill struct wsdisplay_fbinfo *wdf;
443d4c79dc9Sjmcneill int nmode;
444d4c79dc9Sjmcneill
445d4c79dc9Sjmcneill vd = (struct vcons_data *)v;
446d4c79dc9Sjmcneill sc = (struct crmfb_softc *)vd->cookie;
447d4c79dc9Sjmcneill
448d4c79dc9Sjmcneill switch (cmd) {
449d4c79dc9Sjmcneill case WSDISPLAYIO_GTYPE:
450d4c79dc9Sjmcneill /* not really, but who cares? */
45171305eb6Smacallan /* xf86-video-crime does */
4520904724eSmacallan *(u_int *)data = WSDISPLAY_TYPE_CRIME;
453d4c79dc9Sjmcneill return 0;
454d4c79dc9Sjmcneill case WSDISPLAYIO_GINFO:
455d4c79dc9Sjmcneill if (vd->active != NULL) {
456d4c79dc9Sjmcneill wdf = (void *)data;
457d4c79dc9Sjmcneill wdf->height = sc->sc_height;
458d4c79dc9Sjmcneill wdf->width = sc->sc_width;
4590904724eSmacallan wdf->depth = 32;
460d4c79dc9Sjmcneill wdf->cmsize = 256;
461d4c79dc9Sjmcneill return 0;
462d4c79dc9Sjmcneill } else
463d4c79dc9Sjmcneill return ENODEV;
464d4c79dc9Sjmcneill case WSDISPLAYIO_GETCMAP:
465d4c79dc9Sjmcneill if (sc->sc_depth == 8)
466d4c79dc9Sjmcneill return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data);
467d4c79dc9Sjmcneill else
468d4c79dc9Sjmcneill return EINVAL;
469d4c79dc9Sjmcneill case WSDISPLAYIO_PUTCMAP:
470d4c79dc9Sjmcneill if (sc->sc_depth == 8)
471d4c79dc9Sjmcneill return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data);
472d4c79dc9Sjmcneill else
473d4c79dc9Sjmcneill return EINVAL;
474d4c79dc9Sjmcneill case WSDISPLAYIO_LINEBYTES:
475d4c79dc9Sjmcneill *(u_int *)data = sc->sc_width * sc->sc_depth / 8;
476d4c79dc9Sjmcneill return 0;
477d4c79dc9Sjmcneill case WSDISPLAYIO_SMODE:
478d4c79dc9Sjmcneill nmode = *(int *)data;
479d4c79dc9Sjmcneill if (nmode != sc->sc_wsmode) {
480d4c79dc9Sjmcneill sc->sc_wsmode = nmode;
4810904724eSmacallan if (nmode == WSDISPLAYIO_MODE_EMUL) {
482fa88ee42Smacallan crmfb_setup_video(sc, sc->sc_console_depth);
4830904724eSmacallan crmfb_setup_palette(sc);
484d4c79dc9Sjmcneill vcons_redraw_screen(vd->active);
4850904724eSmacallan } else {
4860904724eSmacallan crmfb_setup_video(sc, 32);
4870904724eSmacallan }
488d4c79dc9Sjmcneill }
489d4c79dc9Sjmcneill return 0;
490c1ee0b42Sjmcneill case WSDISPLAYIO_SVIDEO:
49171305eb6Smacallan {
49271305eb6Smacallan int d = *(int *)data;
49371305eb6Smacallan if (d == sc->sc_video_on)
49471305eb6Smacallan return 0;
49571305eb6Smacallan sc->sc_video_on = d;
49671305eb6Smacallan if (d == WSDISPLAYIO_VIDEO_ON) {
49771305eb6Smacallan crmfb_write_reg(sc,
49871305eb6Smacallan CRMFB_VT_FLAGS, sc->sc_vtflags);
49971305eb6Smacallan } else {
50071305eb6Smacallan /* turn all SYNCs off */
50171305eb6Smacallan crmfb_write_reg(sc, CRMFB_VT_FLAGS,
50271305eb6Smacallan sc->sc_vtflags | CRMFB_VT_FLAGS_VDRV_LOW |
50371305eb6Smacallan CRMFB_VT_FLAGS_HDRV_LOW |
50471305eb6Smacallan CRMFB_VT_FLAGS_SYNC_LOW);
50571305eb6Smacallan }
50671305eb6Smacallan }
50771305eb6Smacallan return 0;
50871305eb6Smacallan
509c1ee0b42Sjmcneill case WSDISPLAYIO_GVIDEO:
51071305eb6Smacallan *(int *)data = sc->sc_video_on;
51171305eb6Smacallan return 0;
512d4c79dc9Sjmcneill
513d2924302Smacallan case WSDISPLAYIO_GCURPOS:
514d2924302Smacallan {
515d2924302Smacallan struct wsdisplay_curpos *pos;
516d2924302Smacallan
517d2924302Smacallan pos = (struct wsdisplay_curpos *)data;
518d2924302Smacallan pos->x = sc->sc_cur_x;
519d2924302Smacallan pos->y = sc->sc_cur_y;
520d2924302Smacallan }
521d2924302Smacallan return 0;
522d2924302Smacallan case WSDISPLAYIO_SCURPOS:
523d2924302Smacallan {
524d2924302Smacallan struct wsdisplay_curpos *pos;
525d2924302Smacallan
526d2924302Smacallan pos = (struct wsdisplay_curpos *)data;
527d2924302Smacallan crmfb_set_curpos(sc, pos->x, pos->y);
528d2924302Smacallan }
529d2924302Smacallan return 0;
530d2924302Smacallan case WSDISPLAYIO_GCURMAX:
531d2924302Smacallan {
532d2924302Smacallan struct wsdisplay_curpos *pos;
533d2924302Smacallan
534d2924302Smacallan pos = (struct wsdisplay_curpos *)data;
535d2924302Smacallan pos->x = 32;
536d2924302Smacallan pos->y = 32;
537d2924302Smacallan }
538d2924302Smacallan return 0;
539d2924302Smacallan case WSDISPLAYIO_GCURSOR:
540d2924302Smacallan {
541d2924302Smacallan struct wsdisplay_cursor *cu;
542d2924302Smacallan
543d2924302Smacallan cu = (struct wsdisplay_cursor *)data;
544d2924302Smacallan return crmfb_gcursor(sc, cu);
545d2924302Smacallan }
546d2924302Smacallan case WSDISPLAYIO_SCURSOR:
547d2924302Smacallan {
548d2924302Smacallan struct wsdisplay_cursor *cu;
549d2924302Smacallan
550d2924302Smacallan cu = (struct wsdisplay_cursor *)data;
551d2924302Smacallan return crmfb_scursor(sc, cu);
552d2924302Smacallan }
55371305eb6Smacallan case WSDISPLAYIO_GET_EDID: {
55471305eb6Smacallan struct wsdisplayio_edid_info *d = data;
55571305eb6Smacallan
55671305eb6Smacallan d->data_size = 128;
55771305eb6Smacallan if (d->buffer_size < 128)
55871305eb6Smacallan return EAGAIN;
55971305eb6Smacallan if (sc->sc_edid_data[1] == 0)
56071305eb6Smacallan return ENODATA;
56171305eb6Smacallan return copyout(sc->sc_edid_data, d->edid_data, 128);
56271305eb6Smacallan }
563d2924302Smacallan }
564d4c79dc9Sjmcneill return EPASSTHROUGH;
565d4c79dc9Sjmcneill }
566d4c79dc9Sjmcneill
567d4c79dc9Sjmcneill static paddr_t
crmfb_mmap(void * v,void * vs,off_t offset,int prot)568d4c79dc9Sjmcneill crmfb_mmap(void *v, void *vs, off_t offset, int prot)
569d4c79dc9Sjmcneill {
570d4c79dc9Sjmcneill struct vcons_data *vd;
571d4c79dc9Sjmcneill struct crmfb_softc *sc;
572d4c79dc9Sjmcneill paddr_t pa;
573d4c79dc9Sjmcneill
574d4c79dc9Sjmcneill vd = (struct vcons_data *)v;
575d4c79dc9Sjmcneill sc = (struct crmfb_softc *)vd->cookie;
576d4c79dc9Sjmcneill
5779a7aee14Smacallan /* we probably shouldn't let anyone mmap the framebuffer */
5780904724eSmacallan #if 1
579b14b0cafSmacallan if (offset >= 0 && offset < (0x100000 * sc->sc_tiles_x)) {
580d4c79dc9Sjmcneill pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs,
581d4c79dc9Sjmcneill sc->sc_dma.nsegs, offset, prot,
582eb488f67Smacallan BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE);
583d4c79dc9Sjmcneill return pa;
584d4c79dc9Sjmcneill }
5850904724eSmacallan #endif
5869a7aee14Smacallan /*
5879a7aee14Smacallan * here would the TLBs be but we don't want to show them to userland
5889a7aee14Smacallan * so we return the page containing the status register
5899a7aee14Smacallan */
5909a7aee14Smacallan if ((offset >= 0x15000000) && (offset < 0x15002000))
5919a7aee14Smacallan return bus_space_mmap(sc->sc_iot, 0x15004000, 0, prot, 0);
5929a7aee14Smacallan /* now the actual engine registers */
5939a7aee14Smacallan if ((offset >= 0x15002000) && (offset < 0x15005000))
5949a7aee14Smacallan return bus_space_mmap(sc->sc_iot, offset, 0, prot, 0);
595a2db4fbdSmacallan /* and now the linear area */
596a2db4fbdSmacallan if ((offset >= 0x15010000) && (offset < 0x15030000))
5979a7aee14Smacallan return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs,
5984750dcc2Smacallan sc->sc_dma.nsegs,
599eb488f67Smacallan offset + (0x100000 * sc->sc_tiles_x) - 0x15010000, prot,
600eb488f67Smacallan BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE);
601d4c79dc9Sjmcneill return -1;
602d4c79dc9Sjmcneill }
603d4c79dc9Sjmcneill
604d4c79dc9Sjmcneill static void
crmfb_init_screen(void * c,struct vcons_screen * scr,int existing,long * defattr)605d4c79dc9Sjmcneill crmfb_init_screen(void *c, struct vcons_screen *scr, int existing,
606d4c79dc9Sjmcneill long *defattr)
607d4c79dc9Sjmcneill {
608d4c79dc9Sjmcneill struct crmfb_softc *sc;
609d4c79dc9Sjmcneill struct rasops_info *ri;
610d4c79dc9Sjmcneill
611d4c79dc9Sjmcneill sc = (struct crmfb_softc *)c;
612d4c79dc9Sjmcneill ri = &scr->scr_ri;
613d4c79dc9Sjmcneill
614733da76fSmacallan scr->scr_flags |= VCONS_LOADFONT;
615733da76fSmacallan
616733da76fSmacallan ri->ri_flg = RI_CENTER | RI_FULLCLEAR |
617733da76fSmacallan RI_ENABLE_ALPHA | RI_PREFER_ALPHA;
618fa88ee42Smacallan ri->ri_depth = sc->sc_console_depth;
619d4c79dc9Sjmcneill ri->ri_width = sc->sc_width;
620d4c79dc9Sjmcneill ri->ri_height = sc->sc_height;
621d4c79dc9Sjmcneill ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
62271305eb6Smacallan
623d4c79dc9Sjmcneill switch (ri->ri_depth) {
62471305eb6Smacallan case 8:
62571305eb6Smacallan ri->ri_flg |= RI_8BIT_IS_RGB;
62671305eb6Smacallan break;
627d4c79dc9Sjmcneill case 16:
628d4c79dc9Sjmcneill ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5;
629fa88ee42Smacallan ri->ri_rpos = 11;
630fa88ee42Smacallan ri->ri_gpos = 6;
631fa88ee42Smacallan ri->ri_bpos = 1;
632d4c79dc9Sjmcneill break;
633d4c79dc9Sjmcneill case 32:
634d4c79dc9Sjmcneill ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
635d4c79dc9Sjmcneill ri->ri_rpos = 8;
636d4c79dc9Sjmcneill ri->ri_gpos = 16;
637d4c79dc9Sjmcneill ri->ri_bpos = 24;
638d4c79dc9Sjmcneill break;
639d4c79dc9Sjmcneill }
64071305eb6Smacallan
641e71a84eaSmacallan ri->ri_bits = NULL;
642d4c79dc9Sjmcneill
643d6837d19Smacallan rasops_init(ri, 0, 0);
644733da76fSmacallan ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_RESIZE;
645d4c79dc9Sjmcneill rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
646d4c79dc9Sjmcneill ri->ri_width / ri->ri_font->fontwidth);
647d4c79dc9Sjmcneill ri->ri_hw = scr;
648d4c79dc9Sjmcneill
649c5904c10Smacallan ri->ri_ops.cursor = crmfb_cursor;
650c5904c10Smacallan ri->ri_ops.copyrows = crmfb_copyrows;
651c5904c10Smacallan ri->ri_ops.eraserows = crmfb_eraserows;
652c5904c10Smacallan ri->ri_ops.copycols = crmfb_copycols;
653c5904c10Smacallan ri->ri_ops.erasecols = crmfb_erasecols;
654a2db4fbdSmacallan if (FONT_IS_ALPHA(ri->ri_font)) {
655a2db4fbdSmacallan ri->ri_ops.putchar = crmfb_putchar_aa;
656a2db4fbdSmacallan } else {
657c5904c10Smacallan ri->ri_ops.putchar = crmfb_putchar;
658a2db4fbdSmacallan }
659d4c79dc9Sjmcneill return;
660d4c79dc9Sjmcneill }
661d4c79dc9Sjmcneill
662d4c79dc9Sjmcneill static int
crmfb_putcmap(struct crmfb_softc * sc,struct wsdisplay_cmap * cm)663d4c79dc9Sjmcneill crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm)
664d4c79dc9Sjmcneill {
665d4c79dc9Sjmcneill u_int idx, cnt;
666d4c79dc9Sjmcneill u_char r[256], g[256], b[256];
667d4c79dc9Sjmcneill u_char *rp, *gp, *bp;
668d4c79dc9Sjmcneill int rv, i;
669d4c79dc9Sjmcneill
670d4c79dc9Sjmcneill idx = cm->index;
671d4c79dc9Sjmcneill cnt = cm->count;
672d4c79dc9Sjmcneill
673d4c79dc9Sjmcneill if (idx >= 255 || cnt > 256 || idx + cnt > 256)
674d4c79dc9Sjmcneill return EINVAL;
675d4c79dc9Sjmcneill
676d4c79dc9Sjmcneill rv = copyin(cm->red, &r[idx], cnt);
677d4c79dc9Sjmcneill if (rv)
678d4c79dc9Sjmcneill return rv;
679d4c79dc9Sjmcneill rv = copyin(cm->green, &g[idx], cnt);
680d4c79dc9Sjmcneill if (rv)
681d4c79dc9Sjmcneill return rv;
682d4c79dc9Sjmcneill rv = copyin(cm->blue, &b[idx], cnt);
683d4c79dc9Sjmcneill if (rv)
684d4c79dc9Sjmcneill return rv;
685d4c79dc9Sjmcneill
686d4c79dc9Sjmcneill memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt);
687d4c79dc9Sjmcneill memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt);
688d4c79dc9Sjmcneill memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt);
689d4c79dc9Sjmcneill
690d4c79dc9Sjmcneill rp = &sc->sc_cmap_red[idx];
691d4c79dc9Sjmcneill gp = &sc->sc_cmap_green[idx];
692d4c79dc9Sjmcneill bp = &sc->sc_cmap_blue[idx];
693d4c79dc9Sjmcneill
694d4c79dc9Sjmcneill for (i = 0; i < cnt; i++) {
695d4c79dc9Sjmcneill crmfb_set_palette(sc, idx, *rp, *gp, *bp);
696d4c79dc9Sjmcneill idx++;
697d4c79dc9Sjmcneill rp++, gp++, bp++;
698d4c79dc9Sjmcneill }
699d4c79dc9Sjmcneill
700d4c79dc9Sjmcneill return 0;
701d4c79dc9Sjmcneill }
702d4c79dc9Sjmcneill
703d4c79dc9Sjmcneill static int
crmfb_getcmap(struct crmfb_softc * sc,struct wsdisplay_cmap * cm)704d4c79dc9Sjmcneill crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm)
705d4c79dc9Sjmcneill {
706d4c79dc9Sjmcneill u_int idx, cnt;
707d4c79dc9Sjmcneill int rv;
708d4c79dc9Sjmcneill
709d4c79dc9Sjmcneill idx = cm->index;
710d4c79dc9Sjmcneill cnt = cm->count;
711d4c79dc9Sjmcneill
712d4c79dc9Sjmcneill if (idx >= 255 || cnt > 256 || idx + cnt > 256)
713d4c79dc9Sjmcneill return EINVAL;
714d4c79dc9Sjmcneill
715d4c79dc9Sjmcneill rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt);
716d4c79dc9Sjmcneill if (rv)
717d4c79dc9Sjmcneill return rv;
718d4c79dc9Sjmcneill rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt);
719d4c79dc9Sjmcneill if (rv)
720d4c79dc9Sjmcneill return rv;
721d4c79dc9Sjmcneill rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt);
722d4c79dc9Sjmcneill if (rv)
723d4c79dc9Sjmcneill return rv;
724d4c79dc9Sjmcneill
725d4c79dc9Sjmcneill return 0;
726d4c79dc9Sjmcneill }
727d4c79dc9Sjmcneill
728d4c79dc9Sjmcneill static void
crmfb_set_palette(struct crmfb_softc * sc,int reg,uint8_t r,uint8_t g,uint8_t b)729d4c79dc9Sjmcneill crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g,
730d4c79dc9Sjmcneill uint8_t b)
731d4c79dc9Sjmcneill {
732d4c79dc9Sjmcneill uint32_t val;
733d4c79dc9Sjmcneill
734d4c79dc9Sjmcneill if (reg > 255 || sc->sc_depth != 8)
735d4c79dc9Sjmcneill return;
736d4c79dc9Sjmcneill
737d4c79dc9Sjmcneill while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63)
738d4c79dc9Sjmcneill DELAY(10);
739d4c79dc9Sjmcneill
7405f170d1cSjmcneill val = (r << 8) | (g << 16) | (b << 24);
7410904724eSmacallan crmfb_write_reg(sc, CRMFB_CMAP + (reg * 4), val);
742d4c79dc9Sjmcneill
743d4c79dc9Sjmcneill return;
744d4c79dc9Sjmcneill }
745d2924302Smacallan
746d2924302Smacallan static int
crmfb_set_curpos(struct crmfb_softc * sc,int x,int y)747d2924302Smacallan crmfb_set_curpos(struct crmfb_softc *sc, int x, int y)
748d2924302Smacallan {
749d2924302Smacallan uint32_t val;
750d2924302Smacallan
751d2924302Smacallan sc->sc_cur_x = x;
752d2924302Smacallan sc->sc_cur_y = y;
753d2924302Smacallan
754d2924302Smacallan val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16);
7550904724eSmacallan crmfb_write_reg(sc, CRMFB_CURSOR_POS, val);
756d2924302Smacallan
757d2924302Smacallan return 0;
758d2924302Smacallan }
759d2924302Smacallan
760d2924302Smacallan static int
crmfb_gcursor(struct crmfb_softc * sc,struct wsdisplay_cursor * cur)761d2924302Smacallan crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur)
762d2924302Smacallan {
763d2924302Smacallan /* do nothing for now */
764d2924302Smacallan return 0;
765d2924302Smacallan }
766d2924302Smacallan
767d2924302Smacallan static int
crmfb_scursor(struct crmfb_softc * sc,struct wsdisplay_cursor * cur)768d2924302Smacallan crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur)
769d2924302Smacallan {
770d2924302Smacallan if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
771d2924302Smacallan
7720904724eSmacallan crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, cur->enable ? 1 : 0);
773d2924302Smacallan }
774d2924302Smacallan if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
775d2924302Smacallan
776d2924302Smacallan sc->sc_hot_x = cur->hot.x;
777d2924302Smacallan sc->sc_hot_y = cur->hot.y;
778d2924302Smacallan }
779d2924302Smacallan if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
780d2924302Smacallan
781d2924302Smacallan crmfb_set_curpos(sc, cur->pos.x, cur->pos.y);
782d2924302Smacallan }
783d2924302Smacallan if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
784d2924302Smacallan int i;
785d2924302Smacallan uint32_t val;
786d2924302Smacallan
787d2924302Smacallan for (i = 0; i < cur->cmap.count; i++) {
788d2924302Smacallan val = (cur->cmap.red[i] << 24) |
789d2924302Smacallan (cur->cmap.green[i] << 16) |
790d2924302Smacallan (cur->cmap.blue[i] << 8);
7910904724eSmacallan crmfb_write_reg(sc, CRMFB_CURSOR_CMAP0 +
7920904724eSmacallan ((i + cur->cmap.index) << 2), val);
793d2924302Smacallan }
794d2924302Smacallan }
795d2924302Smacallan if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
796d2924302Smacallan
797d2924302Smacallan int i, j, cnt = 0;
798d2924302Smacallan uint32_t latch = 0, omask;
799d2924302Smacallan uint8_t imask;
800d2924302Smacallan for (i = 0; i < 64; i++) {
801d2924302Smacallan omask = 0x80000000;
802d2924302Smacallan imask = 0x01;
803d2924302Smacallan cur->image[cnt] &= cur->mask[cnt];
804d2924302Smacallan for (j = 0; j < 8; j++) {
805d2924302Smacallan if (cur->image[cnt] & imask)
806d2924302Smacallan latch |= omask;
807d2924302Smacallan omask >>= 1;
808d2924302Smacallan if (cur->mask[cnt] & imask)
809d2924302Smacallan latch |= omask;
810d2924302Smacallan omask >>= 1;
811d2924302Smacallan imask <<= 1;
812d2924302Smacallan }
813d2924302Smacallan cnt++;
814d2924302Smacallan imask = 0x01;
815d2924302Smacallan cur->image[cnt] &= cur->mask[cnt];
816d2924302Smacallan for (j = 0; j < 8; j++) {
817d2924302Smacallan if (cur->image[cnt] & imask)
818d2924302Smacallan latch |= omask;
819d2924302Smacallan omask >>= 1;
820d2924302Smacallan if (cur->mask[cnt] & imask)
821d2924302Smacallan latch |= omask;
822d2924302Smacallan omask >>= 1;
823d2924302Smacallan imask <<= 1;
824d2924302Smacallan }
825d2924302Smacallan cnt++;
8260904724eSmacallan crmfb_write_reg(sc, CRMFB_CURSOR_BITMAP + (i << 2),
8270904724eSmacallan latch);
828d2924302Smacallan latch = 0;
829d2924302Smacallan }
830d2924302Smacallan }
831d2924302Smacallan return 0;
832d2924302Smacallan }
8330904724eSmacallan
8340904724eSmacallan static inline void
crmfb_write_reg(struct crmfb_softc * sc,int offset,uint32_t val)8350904724eSmacallan crmfb_write_reg(struct crmfb_softc *sc, int offset, uint32_t val)
8360904724eSmacallan {
8370904724eSmacallan
8380904724eSmacallan bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
8390904724eSmacallan wbflush();
8400904724eSmacallan }
8410904724eSmacallan
842c5904c10Smacallan static inline uint32_t
crmfb_read_reg(struct crmfb_softc * sc,int offset)843c5904c10Smacallan crmfb_read_reg(struct crmfb_softc *sc, int offset)
844c5904c10Smacallan {
845c5904c10Smacallan
846c5904c10Smacallan return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
847c5904c10Smacallan }
848c5904c10Smacallan
849a2db4fbdSmacallan static inline void
crmfb_wait_idle(struct crmfb_softc * sc)850a2db4fbdSmacallan crmfb_wait_idle(struct crmfb_softc *sc)
851a2db4fbdSmacallan {
852a2db4fbdSmacallan int i = 0;
853a2db4fbdSmacallan
854a2db4fbdSmacallan do {
855a2db4fbdSmacallan i++;
856a2db4fbdSmacallan } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) &
857a2db4fbdSmacallan CRIME_DE_IDLE) == 0) && (i < 100000000));
858a2db4fbdSmacallan if (i >= 100000000)
859a2db4fbdSmacallan aprint_error("crmfb_wait_idle() timed out\n");
860a2db4fbdSmacallan sc->sc_needs_sync = 0;
861a2db4fbdSmacallan }
862a2db4fbdSmacallan
863a2db4fbdSmacallan /* writes to CRIME_DE_MODE_* only take effect when the engine is idle */
864a2db4fbdSmacallan
865a2db4fbdSmacallan static inline void
crmfb_src_mode(struct crmfb_softc * sc,uint32_t mode)866a2db4fbdSmacallan crmfb_src_mode(struct crmfb_softc *sc, uint32_t mode)
867a2db4fbdSmacallan {
868a2db4fbdSmacallan if (mode == sc->sc_src_mode)
869a2db4fbdSmacallan return;
870a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, mode);
871a2db4fbdSmacallan sc->sc_needs_sync = 1;
872a2db4fbdSmacallan sc->sc_src_mode = mode;
873a2db4fbdSmacallan }
874a2db4fbdSmacallan
875a2db4fbdSmacallan static inline void
crmfb_dst_mode(struct crmfb_softc * sc,uint32_t mode)876a2db4fbdSmacallan crmfb_dst_mode(struct crmfb_softc *sc, uint32_t mode)
877a2db4fbdSmacallan {
878a2db4fbdSmacallan if (mode == sc->sc_dst_mode)
879a2db4fbdSmacallan return;
880a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST, mode);
881a2db4fbdSmacallan sc->sc_needs_sync = 1;
882a2db4fbdSmacallan sc->sc_dst_mode = mode;
883a2db4fbdSmacallan }
884a2db4fbdSmacallan
885a2db4fbdSmacallan static inline void
crmfb_make_room(struct crmfb_softc * sc,int num)886a2db4fbdSmacallan crmfb_make_room(struct crmfb_softc *sc, int num)
887a2db4fbdSmacallan {
888a2db4fbdSmacallan int i = 0, slots;
889a2db4fbdSmacallan uint32_t status;
890a2db4fbdSmacallan
891a2db4fbdSmacallan if (sc->sc_needs_sync != 0) {
892a2db4fbdSmacallan crmfb_wait_idle(sc);
893a2db4fbdSmacallan return;
894a2db4fbdSmacallan }
895a2db4fbdSmacallan
896a2db4fbdSmacallan do {
897a2db4fbdSmacallan i++;
898a2db4fbdSmacallan status = bus_space_read_4(sc->sc_iot, sc->sc_reh,
899a2db4fbdSmacallan CRIME_DE_STATUS);
900a2db4fbdSmacallan slots = 60 - CRIME_PIPE_LEVEL(status);
901a2db4fbdSmacallan } while (slots <= num);
902a2db4fbdSmacallan }
903a2db4fbdSmacallan
904c5904c10Smacallan static int
crmfb_wait_dma_idle(struct crmfb_softc * sc)905c5904c10Smacallan crmfb_wait_dma_idle(struct crmfb_softc *sc)
906c5904c10Smacallan {
907c5904c10Smacallan int bail = 100000, idle;
908c5904c10Smacallan
909c5904c10Smacallan do {
910c5904c10Smacallan idle = ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
911c5904c10Smacallan CRMFB_OVR_CONTROL) & 1) == 0) &&
912c5904c10Smacallan ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
913c5904c10Smacallan CRMFB_FRM_CONTROL) & 1) == 0) &&
914c5904c10Smacallan ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
915c5904c10Smacallan CRMFB_DID_CONTROL) & 1) == 0);
916c5904c10Smacallan if (!idle)
917c5904c10Smacallan delay(10);
918c5904c10Smacallan bail--;
919c5904c10Smacallan } while ((!idle) && (bail > 0));
920c5904c10Smacallan return idle;
921c5904c10Smacallan }
922c5904c10Smacallan
9230904724eSmacallan static int
crmfb_setup_video(struct crmfb_softc * sc,int depth)9240904724eSmacallan crmfb_setup_video(struct crmfb_softc *sc, int depth)
9250904724eSmacallan {
926c5904c10Smacallan uint64_t reg;
92771305eb6Smacallan uint32_t d, h, page;
928713b73c8Smacallan int i, bail, tile_width, tlbptr, lptr, j, tx, shift, overhang;
929ab0a73e2Ssekiya const char *wantsync;
930c5904c10Smacallan uint16_t v;
9310904724eSmacallan
9320904724eSmacallan /* disable DMA */
9330904724eSmacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL);
9340904724eSmacallan d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT);
9350904724eSmacallan crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d);
9360904724eSmacallan DELAY(50000);
9370904724eSmacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
9380904724eSmacallan d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
9390904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
9400904724eSmacallan DELAY(50000);
941713b73c8Smacallan crmfb_write_reg(sc, CRMFB_DID_CONTROL, d);
9420904724eSmacallan DELAY(50000);
9430904724eSmacallan
944c5904c10Smacallan if (!crmfb_wait_dma_idle(sc))
945c5904c10Smacallan aprint_error("crmfb: crmfb_wait_dma_idle timed out\n");
946c5904c10Smacallan
9470904724eSmacallan /* ensure that CRM starts drawing at the top left of the screen
9480904724eSmacallan * when we re-enable DMA later
9490904724eSmacallan */
9500904724eSmacallan d = (1 << CRMFB_VT_XY_FREEZE_SHIFT);
9510904724eSmacallan crmfb_write_reg(sc, CRMFB_VT_XY, d);
9520904724eSmacallan delay(1000);
9530904724eSmacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
9540904724eSmacallan d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
9550904724eSmacallan crmfb_write_reg(sc, CRMFB_DOTCLOCK, d);
956c5904c10Smacallan
957c5904c10Smacallan /* wait for dotclock to turn off */
958c5904c10Smacallan bail = 10000;
959c5904c10Smacallan while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK) &
960c5904c10Smacallan (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT)) && (bail > 0)) {
961c5904c10Smacallan delay(10);
962c5904c10Smacallan bail--;
963c5904c10Smacallan }
9640904724eSmacallan
9650904724eSmacallan /* reset FIFO */
9660904724eSmacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE);
9670904724eSmacallan d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT);
9680904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d);
9690904724eSmacallan d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT);
9700904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d);
9710904724eSmacallan
9720904724eSmacallan /* setup colour mode */
9730904724eSmacallan switch (depth) {
9740904724eSmacallan case 8:
97571305eb6Smacallan h = CRMFB_MODE_TYP_RG3B2;
976c5904c10Smacallan tile_width = 512;
9770904724eSmacallan break;
9780904724eSmacallan case 16:
9790904724eSmacallan h = CRMFB_MODE_TYP_ARGB5;
980c5904c10Smacallan tile_width = 256;
9810904724eSmacallan break;
9820904724eSmacallan case 32:
9830904724eSmacallan h = CRMFB_MODE_TYP_RGB8;
984c5904c10Smacallan tile_width = 128;
9850904724eSmacallan break;
9860904724eSmacallan default:
9870904724eSmacallan panic("Unsupported depth");
9880904724eSmacallan }
9890904724eSmacallan d = h << CRMFB_MODE_TYP_SHIFT;
9900904724eSmacallan d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT;
9910904724eSmacallan for (i = 0; i < (32 * 4); i += 4)
9920904724eSmacallan bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d);
9930904724eSmacallan wbflush();
9940904724eSmacallan
9950904724eSmacallan /* setup tile pointer, but don't turn on DMA yet! */
9960904724eSmacallan h = DMAADDR(sc->sc_dmai);
9970904724eSmacallan d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT;
9980904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
9990904724eSmacallan
10000904724eSmacallan /* init framebuffer width and pixel size */
1001c5904c10Smacallan /*d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT);*/
1002c5904c10Smacallan
1003c5904c10Smacallan d = ((int)(sc->sc_width / tile_width)) <<
1004c5904c10Smacallan CRMFB_FRM_TILESIZE_WIDTH_SHIFT;
1005713b73c8Smacallan overhang = sc->sc_width % tile_width;
1006713b73c8Smacallan if (overhang != 0) {
1007713b73c8Smacallan uint32_t val;
1008713b73c8Smacallan DPRINTF("tile width: %d\n", tile_width);
1009713b73c8Smacallan DPRINTF("overhang: %d\n", overhang);
1010713b73c8Smacallan val = (overhang * (depth >> 3)) >> 5;
1011713b73c8Smacallan DPRINTF("reg: %08x\n", val);
1012713b73c8Smacallan d |= (val & 0x1f);
1013713b73c8Smacallan DPRINTF("d: %08x\n", d);
1014713b73c8Smacallan }
1015c5904c10Smacallan
10160904724eSmacallan switch (depth) {
10170904724eSmacallan case 8:
10180904724eSmacallan h = CRMFB_FRM_TILESIZE_DEPTH_8;
10190904724eSmacallan break;
10200904724eSmacallan case 16:
10210904724eSmacallan h = CRMFB_FRM_TILESIZE_DEPTH_16;
10220904724eSmacallan break;
10230904724eSmacallan case 32:
10240904724eSmacallan h = CRMFB_FRM_TILESIZE_DEPTH_32;
10250904724eSmacallan break;
10260904724eSmacallan default:
10270904724eSmacallan panic("Unsupported depth");
10280904724eSmacallan }
10290904724eSmacallan d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT);
10300904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d);
10310904724eSmacallan
1032c5904c10Smacallan /*h = sc->sc_width * sc->sc_height / (512 / (depth >> 3));*/
1033c5904c10Smacallan h = sc->sc_height;
10340904724eSmacallan d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT;
10350904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_PIXSIZE, d);
10360904724eSmacallan
10370904724eSmacallan /* turn off firmware overlay and hardware cursor */
10380904724eSmacallan crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0);
10390904724eSmacallan crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0);
10400904724eSmacallan
10410904724eSmacallan /* turn on DMA for the framebuffer */
10420904724eSmacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
10430904724eSmacallan d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
10440904724eSmacallan crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
10450904724eSmacallan
1046713b73c8Smacallan /* enable drawing again */
1047713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_XY, 0);
1048713b73c8Smacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
1049713b73c8Smacallan d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
1050713b73c8Smacallan crmfb_write_reg(sc, CRMFB_DOTCLOCK, d);
1051713b73c8Smacallan
1052ab0a73e2Ssekiya /* turn off sync-on-green */
1053ab0a73e2Ssekiya
105423347d39Smatt wantsync = arcbios_GetEnvironmentVariable("SyncOnGreen");
1055ab0a73e2Ssekiya if ( (wantsync != NULL) && (wantsync[0] == 'n') ) {
105671305eb6Smacallan sc->sc_vtflags |= CRMFB_VT_FLAGS_SYNC_LOW;
1057ab0a73e2Ssekiya crmfb_write_reg(sc, CRMFB_VT_FLAGS, d);
1058ab0a73e2Ssekiya }
1059ab0a73e2Ssekiya
10600904724eSmacallan sc->sc_depth = depth;
1061c5904c10Smacallan
1062c5904c10Smacallan /* finally set up the drawing engine's TLB A */
1063c5904c10Smacallan v = (DMAADDR(sc->sc_dma) >> 16) & 0xffff;
1064c5904c10Smacallan tlbptr = 0;
1065eceb35ecSmacallan tx = ((sc->sc_width + (tile_width - 1)) & ~(tile_width - 1)) /
1066eceb35ecSmacallan tile_width;
10679a7aee14Smacallan
1068713b73c8Smacallan DPRINTF("tx: %d\n", tx);
10694750dcc2Smacallan
10704750dcc2Smacallan for (i = 0; i < 16; i++) {
1071c5904c10Smacallan reg = 0;
1072c5904c10Smacallan shift = 64;
10734750dcc2Smacallan lptr = 0;
1074c5904c10Smacallan for (j = 0; j < tx; j++) {
1075c5904c10Smacallan shift -= 16;
1076c5904c10Smacallan reg |= (((uint64_t)(v | 0x8000)) << shift);
1077c5904c10Smacallan if (shift == 0) {
1078c5904c10Smacallan shift = 64;
1079c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh,
10804750dcc2Smacallan CRIME_RE_TLB_A + tlbptr + lptr,
1081eceb35ecSmacallan reg);
10827ed121adSplunky DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg);
10834750dcc2Smacallan reg = 0;
10844750dcc2Smacallan lptr += 8;
1085c5904c10Smacallan }
1086c5904c10Smacallan v++;
1087c5904c10Smacallan }
1088c5904c10Smacallan if (shift != 64) {
1089c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh,
10904750dcc2Smacallan CRIME_RE_TLB_A + tlbptr + lptr, reg);
10917ed121adSplunky DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg);
1092c5904c10Smacallan }
1093c5904c10Smacallan tlbptr += 32;
1094c5904c10Smacallan }
1095c5904c10Smacallan
1096a2db4fbdSmacallan /* now put the last 128kB into the 1st linear TLB */
10974750dcc2Smacallan page = (sc->sc_linear >> 12) | 0x80000000;
10984750dcc2Smacallan tlbptr = 0;
1099a2db4fbdSmacallan for (i = 0; i < 16; i++) {
11004750dcc2Smacallan reg = ((uint64_t)page << 32) | (page + 1);
11014750dcc2Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh,
11024750dcc2Smacallan CRIME_RE_LINEAR_A + tlbptr, reg);
11034750dcc2Smacallan page += 2;
11044750dcc2Smacallan tlbptr += 8;
11054750dcc2Smacallan }
1106c5904c10Smacallan wbflush();
1107c5904c10Smacallan
1108c5904c10Smacallan /* do some very basic engine setup */
1109c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_CLIPMODE, 0);
1110c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_SRC, 0);
1111c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_DST, 0);
1112eceb35ecSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PLANEMASK,
1113eceb35ecSmacallan 0xffffffff);
1114c5904c10Smacallan
1115c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x20, 0);
1116c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x28, 0);
1117c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x30, 0);
1118c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x38, 0);
1119c5904c10Smacallan bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x40, 0);
1120c5904c10Smacallan
1121c5904c10Smacallan switch (depth) {
1122c5904c10Smacallan case 8:
112371305eb6Smacallan sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 |
1124c5904c10Smacallan DE_MODE_TYPE_CI | DE_MODE_PIXDEPTH_8;
1125fa88ee42Smacallan sc->sc_mte_mode = MTE_MODE_DST_ECC |
1126fa88ee42Smacallan (MTE_TLB_A << MTE_DST_TLB_SHIFT) |
1127fa88ee42Smacallan (MTE_TLB_A << MTE_SRC_TLB_SHIFT) |
1128fa88ee42Smacallan (MTE_DEPTH_8 << MTE_DEPTH_SHIFT);
1129fa88ee42Smacallan sc->sc_mte_x_shift = 0;
1130c5904c10Smacallan break;
1131c5904c10Smacallan case 16:
113271305eb6Smacallan sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_16 |
1133fa88ee42Smacallan DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_16;
1134fa88ee42Smacallan sc->sc_mte_mode = MTE_MODE_DST_ECC |
1135fa88ee42Smacallan (MTE_TLB_A << MTE_DST_TLB_SHIFT) |
1136fa88ee42Smacallan (MTE_TLB_A << MTE_SRC_TLB_SHIFT) |
1137fa88ee42Smacallan (MTE_DEPTH_16 << MTE_DEPTH_SHIFT);
1138fa88ee42Smacallan sc->sc_mte_x_shift = 1;
11399a7aee14Smacallan break;
1140c5904c10Smacallan case 32:
114171305eb6Smacallan sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_32 |
1142c5904c10Smacallan DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_32;
1143fa88ee42Smacallan sc->sc_mte_mode = MTE_MODE_DST_ECC |
1144fa88ee42Smacallan (MTE_TLB_A << MTE_DST_TLB_SHIFT) |
1145fa88ee42Smacallan (MTE_TLB_A << MTE_SRC_TLB_SHIFT) |
1146fa88ee42Smacallan (MTE_DEPTH_32 << MTE_DEPTH_SHIFT);
1147fa88ee42Smacallan sc->sc_mte_x_shift = 2;
1148451f7eb5Schristos break;
1149c5904c10Smacallan default:
1150e9921331Smsaitoh panic("%s: unsupported colour depth %d\n", __func__,
1151c5904c10Smacallan depth);
1152c5904c10Smacallan }
1153a2db4fbdSmacallan sc->sc_needs_sync = 0;
1154a2db4fbdSmacallan sc->sc_src_mode = 0xffffffff;
1155a2db4fbdSmacallan sc->sc_dst_mode = 0xffffffff;
1156a2db4fbdSmacallan
1157a2db4fbdSmacallan crmfb_src_mode(sc, sc->sc_de_mode);
1158a2db4fbdSmacallan crmfb_dst_mode(sc, sc->sc_de_mode);
1159a2db4fbdSmacallan
1160c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_X, 1);
1161c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_Y, 1);
1162eceb35ecSmacallan
1163eceb35ecSmacallan /* initialize memory transfer engine */
1164eceb35ecSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
1165fa88ee42Smacallan sc->sc_mte_mode | MTE_MODE_COPY);
1166dca5aa4eSmacallan sc->sc_mte_direction = 1;
1167d1dee129Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, 1);
1168d1dee129Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, 1);
1169eceb35ecSmacallan
11700904724eSmacallan return 0;
11710904724eSmacallan }
11720904724eSmacallan
1173104b3395Smacallan static void
crmfb_set_mte_direction(struct crmfb_softc * sc,int dir)1174dca5aa4eSmacallan crmfb_set_mte_direction(struct crmfb_softc *sc, int dir)
1175dca5aa4eSmacallan {
1176dca5aa4eSmacallan if (dir == sc->sc_mte_direction)
1177dca5aa4eSmacallan return;
1178dca5aa4eSmacallan
1179a2db4fbdSmacallan crmfb_make_room(sc, 2);
1180dca5aa4eSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, dir);
1181dca5aa4eSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, dir);
1182864b6f1cSmacallan sc->sc_mte_direction = dir;
1183dca5aa4eSmacallan }
1184dca5aa4eSmacallan
11850904724eSmacallan static void
crmfb_setup_palette(struct crmfb_softc * sc)11860904724eSmacallan crmfb_setup_palette(struct crmfb_softc *sc)
11870904724eSmacallan {
1188a2db4fbdSmacallan int i, j, x;
1189a2db4fbdSmacallan uint32_t col;
1190a2db4fbdSmacallan struct rasops_info *ri = &crmfb_console_screen.scr_ri;
11910904724eSmacallan
11920904724eSmacallan for (i = 0; i < 256; i++) {
11930904724eSmacallan crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2],
11940904724eSmacallan rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]);
11950904724eSmacallan sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2];
11960904724eSmacallan sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1];
11970904724eSmacallan sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0];
11980904724eSmacallan }
1199a2db4fbdSmacallan
1200a2db4fbdSmacallan if (FONT_IS_ALPHA(ri->ri_font)) {
1201a2db4fbdSmacallan sc->sc_de_mode =
1202a2db4fbdSmacallan (sc->sc_de_mode & ~DE_MODE_TYPE_MASK) | DE_MODE_TYPE_RGB;
12030904724eSmacallan }
1204c5904c10Smacallan
1205a2db4fbdSmacallan /* draw 16 character cells in 32bit RGBA for alpha blending */
1206a2db4fbdSmacallan crmfb_make_room(sc, 3);
1207a2db4fbdSmacallan crmfb_dst_mode(sc,
1208a2db4fbdSmacallan DE_MODE_TLB_A |
1209a2db4fbdSmacallan DE_MODE_BUFDEPTH_32 |
1210a2db4fbdSmacallan DE_MODE_TYPE_RGBA |
1211a2db4fbdSmacallan DE_MODE_PIXDEPTH_32);
1212a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1213a2db4fbdSmacallan DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK);
1214a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1215a2db4fbdSmacallan DE_PRIM_RECTANGLE | DE_PRIM_TB);
1216a2db4fbdSmacallan j = 0;
1217a2db4fbdSmacallan x = 0;
1218a2db4fbdSmacallan for (i = 0; i < 16; i++) {
1219a2db4fbdSmacallan crmfb_make_room(sc, 2);
1220a2db4fbdSmacallan col = (rasops_cmap[j] << 24) |
1221a2db4fbdSmacallan (rasops_cmap[j + 1] << 16) |
1222a2db4fbdSmacallan (rasops_cmap[j + 2] << 8);
1223a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, col);
1224a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1225a2db4fbdSmacallan (x << 16) | ((sc->sc_height - 500) & 0xffff));
1226a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
1227a2db4fbdSmacallan CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1228a2db4fbdSmacallan ((x + ri->ri_font->fontwidth - 1) << 16) |
1229a2db4fbdSmacallan ((sc->sc_height + ri->ri_font->fontheight - 1) & 0xffff));
1230a2db4fbdSmacallan j += 3;
1231a2db4fbdSmacallan x += ri->ri_font->fontwidth;
1232a2db4fbdSmacallan }
1233a2db4fbdSmacallan crmfb_dst_mode(sc, sc->sc_de_mode);
1234c5904c10Smacallan }
1235c5904c10Smacallan
1236c5904c10Smacallan static void
crmfb_fill_rect(struct crmfb_softc * sc,int x,int y,int width,int height,uint32_t colour)1237c5904c10Smacallan crmfb_fill_rect(struct crmfb_softc *sc, int x, int y, int width, int height,
1238c5904c10Smacallan uint32_t colour)
1239c5904c10Smacallan {
1240fa88ee42Smacallan int rxa, rxe;
1241fa88ee42Smacallan
1242fa88ee42Smacallan rxa = x << sc->sc_mte_x_shift;
1243fa88ee42Smacallan rxe = ((x + width) << sc->sc_mte_x_shift) - 1;
1244dca5aa4eSmacallan crmfb_set_mte_direction(sc, 1);
1245a2db4fbdSmacallan crmfb_make_room(sc, 4);
12464395e1ddSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
1247fa88ee42Smacallan sc->sc_mte_mode | 0);
12484395e1ddSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, colour);
12494395e1ddSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST0,
1250fa88ee42Smacallan (rxa << 16) | (y & 0xffff));
1251c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
12524395e1ddSmacallan CRIME_MTE_DST1 | CRIME_DE_START,
1253fa88ee42Smacallan (rxe << 16) | ((y + height - 1) & 0xffff));
1254c5904c10Smacallan }
1255c5904c10Smacallan
1256c5904c10Smacallan static void
crmfb_bitblt(struct crmfb_softc * sc,int xs,int ys,int xd,int yd,int wi,int he,uint32_t rop)1257c5904c10Smacallan crmfb_bitblt(struct crmfb_softc *sc, int xs, int ys, int xd, int yd,
1258c5904c10Smacallan int wi, int he, uint32_t rop)
1259c5904c10Smacallan {
1260c5904c10Smacallan uint32_t prim = DE_PRIM_RECTANGLE;
1261c5904c10Smacallan int rxa, rya, rxe, rye, rxs, rys;
1262a2db4fbdSmacallan crmfb_make_room(sc, 2);
1263a2db4fbdSmacallan crmfb_src_mode(sc, sc->sc_de_mode);
1264a2db4fbdSmacallan crmfb_make_room(sc, 6);
1265c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1266c5904c10Smacallan DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP |
1267c5904c10Smacallan DE_DRAWMODE_XFER_EN);
1268c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, rop);
1269c5904c10Smacallan if (xs < xd) {
1270c5904c10Smacallan prim |= DE_PRIM_RL;
1271c5904c10Smacallan rxe = xd;
1272c5904c10Smacallan rxa = xd + wi - 1;
1273c5904c10Smacallan rxs = xs + wi - 1;
1274c5904c10Smacallan } else {
1275c5904c10Smacallan prim |= DE_PRIM_LR;
1276c5904c10Smacallan rxe = xd + wi - 1;
1277c5904c10Smacallan rxa = xd;
1278c5904c10Smacallan rxs = xs;
1279c5904c10Smacallan }
1280c5904c10Smacallan if (ys < yd) {
1281c5904c10Smacallan prim |= DE_PRIM_BT;
1282c5904c10Smacallan rye = yd;
1283c5904c10Smacallan rya = yd + he - 1;
1284c5904c10Smacallan rys = ys + he - 1;
1285c5904c10Smacallan } else {
1286c5904c10Smacallan prim |= DE_PRIM_TB;
1287c5904c10Smacallan rye = yd + he - 1;
1288c5904c10Smacallan rya = yd;
1289c5904c10Smacallan rys = ys;
1290c5904c10Smacallan }
1291c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, prim);
1292c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC,
1293c5904c10Smacallan (rxs << 16) | (rys & 0xffff));
1294c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1295c5904c10Smacallan (rxa << 16) | (rya & 0xffff));
1296c5904c10Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
1297c5904c10Smacallan CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1298c5904c10Smacallan (rxe << 16) | (rye & 0xffff));
1299c5904c10Smacallan }
1300c5904c10Smacallan
1301eceb35ecSmacallan static void
crmfb_scroll(struct crmfb_softc * sc,int xs,int ys,int xd,int yd,int wi,int he)1302eceb35ecSmacallan crmfb_scroll(struct crmfb_softc *sc, int xs, int ys, int xd, int yd,
1303eceb35ecSmacallan int wi, int he)
1304eceb35ecSmacallan {
1305eceb35ecSmacallan int rxa, rya, rxe, rye, rxd, ryd, rxde, ryde;
1306eceb35ecSmacallan
1307fa88ee42Smacallan rxa = xs << sc->sc_mte_x_shift;
1308fa88ee42Smacallan rxd = xd << sc->sc_mte_x_shift;
1309fa88ee42Smacallan rxe = ((xs + wi) << sc->sc_mte_x_shift) - 1;
1310fa88ee42Smacallan rxde = ((xd + wi) << sc->sc_mte_x_shift) - 1;
1311d1dee129Smacallan
1312a2db4fbdSmacallan crmfb_make_room(sc, 1);
1313d1dee129Smacallan
13144395e1ddSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
1315fa88ee42Smacallan sc->sc_mte_mode | MTE_MODE_COPY);
13164395e1ddSmacallan
1317eceb35ecSmacallan if (ys < yd) {
1318eceb35ecSmacallan /* bottom to top */
1319eceb35ecSmacallan rye = ys;
1320eceb35ecSmacallan rya = ys + he - 1;
1321eceb35ecSmacallan ryd = yd + he - 1;
1322eceb35ecSmacallan ryde = yd;
1323dca5aa4eSmacallan crmfb_set_mte_direction(sc, -1);
1324eceb35ecSmacallan } else {
1325eceb35ecSmacallan /* top to bottom */
1326eceb35ecSmacallan rye = ys + he - 1;
1327eceb35ecSmacallan rya = ys;
1328eceb35ecSmacallan ryd = yd;
1329eceb35ecSmacallan ryde = yd + he - 1;
1330dca5aa4eSmacallan crmfb_set_mte_direction(sc, 1);
1331eceb35ecSmacallan }
1332a2db4fbdSmacallan crmfb_make_room(sc, 4);
1333eceb35ecSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0,
1334eceb35ecSmacallan (rxa << 16) | rya);
1335eceb35ecSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1,
1336eceb35ecSmacallan (rxe << 16) | rye);
1337eceb35ecSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
1338eceb35ecSmacallan CRIME_MTE_DST0,
1339eceb35ecSmacallan (rxd << 16) | ryd);
1340eceb35ecSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST1 |
1341eceb35ecSmacallan CRIME_DE_START,
1342eceb35ecSmacallan (rxde << 16) | ryde);
1343eceb35ecSmacallan }
1344eceb35ecSmacallan
1345c5904c10Smacallan static void
crmfb_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)1346c5904c10Smacallan crmfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1347c5904c10Smacallan {
1348c5904c10Smacallan struct rasops_info *ri = cookie;
1349c5904c10Smacallan struct vcons_screen *scr = ri->ri_hw;
1350c5904c10Smacallan int32_t xs, xd, y, width, height;
1351c5904c10Smacallan
1352c5904c10Smacallan xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1353c5904c10Smacallan xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1354c5904c10Smacallan y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1355c5904c10Smacallan width = ri->ri_font->fontwidth * ncols;
1356c5904c10Smacallan height = ri->ri_font->fontheight;
1357c5904c10Smacallan crmfb_bitblt(scr->scr_cookie, xs, y, xd, y, width, height, 3);
1358c5904c10Smacallan }
1359c5904c10Smacallan
1360c5904c10Smacallan static void
crmfb_erasecols(void * cookie,int row,int startcol,int ncols,long fillattr)1361c5904c10Smacallan crmfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1362c5904c10Smacallan {
1363c5904c10Smacallan struct rasops_info *ri = cookie;
1364c5904c10Smacallan struct vcons_screen *scr = ri->ri_hw;
1365c5904c10Smacallan int32_t x, y, width, height, bg;
1366c5904c10Smacallan
1367c5904c10Smacallan x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1368c5904c10Smacallan y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1369c5904c10Smacallan width = ri->ri_font->fontwidth * ncols;
1370c5904c10Smacallan height = ri->ri_font->fontheight;
1371c5904c10Smacallan bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
1372c5904c10Smacallan crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg);
1373c5904c10Smacallan }
1374c5904c10Smacallan
1375c5904c10Smacallan static void
crmfb_copyrows(void * cookie,int srcrow,int dstrow,int nrows)1376c5904c10Smacallan crmfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1377c5904c10Smacallan {
1378c5904c10Smacallan struct rasops_info *ri = cookie;
1379c5904c10Smacallan struct vcons_screen *scr = ri->ri_hw;
1380c5904c10Smacallan int32_t x, ys, yd, width, height;
1381c5904c10Smacallan
1382c5904c10Smacallan x = ri->ri_xorigin;
1383c5904c10Smacallan ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1384c5904c10Smacallan yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1385c5904c10Smacallan width = ri->ri_emuwidth;
1386c5904c10Smacallan height = ri->ri_font->fontheight * nrows;
1387eceb35ecSmacallan
1388eceb35ecSmacallan crmfb_scroll(scr->scr_cookie, x, ys, x, yd, width, height);
1389eceb35ecSmacallan }
1390c5904c10Smacallan
1391c5904c10Smacallan static void
crmfb_eraserows(void * cookie,int row,int nrows,long fillattr)1392c5904c10Smacallan crmfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1393c5904c10Smacallan {
1394c5904c10Smacallan struct rasops_info *ri = cookie;
1395c5904c10Smacallan struct vcons_screen *scr = ri->ri_hw;
1396c5904c10Smacallan int32_t x, y, width, height, bg;
1397c5904c10Smacallan
1398c5904c10Smacallan if ((row == 0) && (nrows == ri->ri_rows)) {
1399c5904c10Smacallan x = y = 0;
1400c5904c10Smacallan width = ri->ri_width;
1401c5904c10Smacallan height = ri->ri_height;
1402c5904c10Smacallan } else {
1403c5904c10Smacallan x = ri->ri_xorigin;
1404c5904c10Smacallan y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1405c5904c10Smacallan width = ri->ri_emuwidth;
1406c5904c10Smacallan height = ri->ri_font->fontheight * nrows;
1407c5904c10Smacallan }
1408c5904c10Smacallan bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
1409c5904c10Smacallan crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg);
1410c5904c10Smacallan }
1411c5904c10Smacallan
1412c5904c10Smacallan static void
crmfb_cursor(void * cookie,int on,int row,int col)1413c5904c10Smacallan crmfb_cursor(void *cookie, int on, int row, int col)
1414c5904c10Smacallan {
1415c5904c10Smacallan struct rasops_info *ri = cookie;
1416c5904c10Smacallan struct vcons_screen *scr = ri->ri_hw;
1417c5904c10Smacallan struct crmfb_softc *sc = scr->scr_cookie;
1418c5904c10Smacallan int x, y, wi,he;
1419c5904c10Smacallan
1420c5904c10Smacallan wi = ri->ri_font->fontwidth;
1421c5904c10Smacallan he = ri->ri_font->fontheight;
1422c5904c10Smacallan
1423c5904c10Smacallan if (ri->ri_flg & RI_CURSOR) {
1424c5904c10Smacallan x = ri->ri_ccol * wi + ri->ri_xorigin;
1425c5904c10Smacallan y = ri->ri_crow * he + ri->ri_yorigin;
1426c5904c10Smacallan crmfb_bitblt(sc, x, y, x, y, wi, he, 12);
1427c5904c10Smacallan ri->ri_flg &= ~RI_CURSOR;
1428c5904c10Smacallan }
1429c5904c10Smacallan
1430c5904c10Smacallan ri->ri_crow = row;
1431c5904c10Smacallan ri->ri_ccol = col;
1432c5904c10Smacallan
1433c5904c10Smacallan if (on)
1434c5904c10Smacallan {
1435c5904c10Smacallan x = ri->ri_ccol * wi + ri->ri_xorigin;
1436c5904c10Smacallan y = ri->ri_crow * he + ri->ri_yorigin;
1437c5904c10Smacallan crmfb_bitblt(sc, x, y, x, y, wi, he, 12);
1438c5904c10Smacallan ri->ri_flg |= RI_CURSOR;
1439c5904c10Smacallan }
1440c5904c10Smacallan }
1441c5904c10Smacallan
1442c5904c10Smacallan static void
crmfb_putchar(void * cookie,int row,int col,u_int c,long attr)1443c5904c10Smacallan crmfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1444c5904c10Smacallan {
1445c5904c10Smacallan struct rasops_info *ri = cookie;
1446c5904c10Smacallan struct vcons_screen *scr = ri->ri_hw;
1447c5904c10Smacallan struct crmfb_softc *sc = scr->scr_cookie;
14485bf2d324Smacallan struct wsdisplay_font *font = PICK_FONT(ri, c);
14495bf2d324Smacallan uint32_t bg, fg;
14505bf2d324Smacallan int x, y, wi, he, i, uc;
14515bf2d324Smacallan uint8_t *fd8;
14525bf2d324Smacallan uint16_t *fd16;
14535bf2d324Smacallan void *fd;
1454c5904c10Smacallan
14555bf2d324Smacallan wi = font->fontwidth;
14565bf2d324Smacallan he = font->fontheight;
1457c5904c10Smacallan
1458c5904c10Smacallan x = ri->ri_xorigin + col * wi;
1459c5904c10Smacallan y = ri->ri_yorigin + row * he;
1460c5904c10Smacallan
14614395e1ddSmacallan bg = ri->ri_devcmap[(attr >> 16) & 0xff];
14625bf2d324Smacallan fg = ri->ri_devcmap[(attr >> 24) & 0xff];
14635bf2d324Smacallan uc = c - font->firstchar;
14645bf2d324Smacallan fd = (uint8_t *)font->data + uc * ri->ri_fontscale;
1465c5904c10Smacallan if (c == 0x20) {
1466c5904c10Smacallan crmfb_fill_rect(sc, x, y, wi, he, bg);
1467c5904c10Smacallan } else {
1468a2db4fbdSmacallan crmfb_make_room(sc, 6);
14695bf2d324Smacallan /* setup */
14705bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
14715bf2d324Smacallan DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK |
14725bf2d324Smacallan DE_DRAWMODE_ROP |
14735bf2d324Smacallan DE_DRAWMODE_OPAQUE_STIP | DE_DRAWMODE_POLY_STIP);
1474fa88ee42Smacallan wbflush();
1475fa88ee42Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, 3);
1476fa88ee42Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, fg);
1477fa88ee42Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_BG, bg);
14785bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
14795bf2d324Smacallan DE_PRIM_RECTANGLE | DE_PRIM_LR | DE_PRIM_TB);
14805bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STIPPLE_MODE,
14815bf2d324Smacallan 0x001f0000);
14825bf2d324Smacallan /* now let's feed the engine */
1483a2db4fbdSmacallan crmfb_make_room(sc, 30);
14845bf2d324Smacallan if (font->stride == 1) {
14855bf2d324Smacallan /* shovel in 8 bit quantities */
14865bf2d324Smacallan fd8 = fd;
14875bf2d324Smacallan for (i = 0; i < he; i++) {
1488a2db4fbdSmacallan if (i & 8)
1489a2db4fbdSmacallan crmfb_make_room(sc, 30);
14905bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
14915bf2d324Smacallan CRIME_DE_STIPPLE_PAT, *fd8 << 24);
14925bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
14935bf2d324Smacallan CRIME_DE_X_VERTEX_0, (x << 16) | y);
14945bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
14955bf2d324Smacallan CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
14965bf2d324Smacallan ((x + wi) << 16) | y);
14975bf2d324Smacallan y++;
14985bf2d324Smacallan fd8++;
14995bf2d324Smacallan }
15005bf2d324Smacallan } else if (font->stride == 2) {
15015bf2d324Smacallan /* shovel in 16 bit quantities */
15025bf2d324Smacallan fd16 = fd;
15035bf2d324Smacallan for (i = 0; i < he; i++) {
1504a2db4fbdSmacallan if (i & 8)
1505a2db4fbdSmacallan crmfb_make_room(sc, 30);
15065bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
15075bf2d324Smacallan CRIME_DE_STIPPLE_PAT, *fd16 << 16);
15085bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
15095bf2d324Smacallan CRIME_DE_X_VERTEX_0, (x << 16) | y);
15105bf2d324Smacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
15115bf2d324Smacallan CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
15125bf2d324Smacallan ((x + wi) << 16) | y);
15135bf2d324Smacallan y++;
15145bf2d324Smacallan fd16++;
15155bf2d324Smacallan }
15165bf2d324Smacallan }
1517c5904c10Smacallan }
1518c5904c10Smacallan }
15199b94525aSmacallan
15209b94525aSmacallan static void
crmfb_putchar_aa(void * cookie,int row,int col,u_int c,long attr)1521a2db4fbdSmacallan crmfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
1522a2db4fbdSmacallan {
1523a2db4fbdSmacallan struct rasops_info *ri = cookie;
1524a2db4fbdSmacallan struct vcons_screen *scr = ri->ri_hw;
1525a2db4fbdSmacallan struct crmfb_softc *sc = scr->scr_cookie;
1526a2db4fbdSmacallan struct wsdisplay_font *font = PICK_FONT(ri, c);
1527a2db4fbdSmacallan uint32_t bg, fg;
1528a2db4fbdSmacallan int x, y, wi, he, uc, xx;
1529a2db4fbdSmacallan void *fd;
1530a2db4fbdSmacallan
1531a2db4fbdSmacallan wi = font->fontwidth;
1532a2db4fbdSmacallan he = font->fontheight;
1533a2db4fbdSmacallan
1534a2db4fbdSmacallan x = ri->ri_xorigin + col * wi;
1535a2db4fbdSmacallan y = ri->ri_yorigin + row * he;
1536a2db4fbdSmacallan
1537a2db4fbdSmacallan bg = ri->ri_devcmap[(attr >> 16) & 0xff];
1538a2db4fbdSmacallan fg = (attr >> 24);
1539a2db4fbdSmacallan uc = c - font->firstchar;
1540a2db4fbdSmacallan fd = (uint8_t *)font->data + uc * ri->ri_fontscale;
1541a2db4fbdSmacallan
1542a2db4fbdSmacallan /* fill the cell with the background colour */
1543a2db4fbdSmacallan crmfb_fill_rect(sc, x, y, wi, he, bg);
1544a2db4fbdSmacallan
1545a2db4fbdSmacallan /* if all we draw is a space we're done */
1546a2db4fbdSmacallan if (c == 0x20)
1547a2db4fbdSmacallan return;
1548a2db4fbdSmacallan
1549a2db4fbdSmacallan /* copy the glyph into the linear buffer */
1550a2db4fbdSmacallan memcpy(sc->sc_lptr, fd, ri->ri_fontscale);
1551a2db4fbdSmacallan wbflush();
1552a2db4fbdSmacallan
1553a2db4fbdSmacallan /* now blit it on top of the requested fg colour cell */
1554a2db4fbdSmacallan xx = fg * wi;
1555a2db4fbdSmacallan crmfb_make_room(sc, 2);
1556a2db4fbdSmacallan crmfb_src_mode(sc,
1557a2db4fbdSmacallan DE_MODE_LIN_A |
1558a2db4fbdSmacallan DE_MODE_BUFDEPTH_8 |
1559a2db4fbdSmacallan DE_MODE_TYPE_CI |
1560a2db4fbdSmacallan DE_MODE_PIXDEPTH_8);
1561a2db4fbdSmacallan crmfb_dst_mode(sc,
1562a2db4fbdSmacallan DE_MODE_TLB_A |
1563a2db4fbdSmacallan DE_MODE_BUFDEPTH_32 |
1564a2db4fbdSmacallan DE_MODE_TYPE_CI |
1565a2db4fbdSmacallan DE_MODE_PIXDEPTH_8);
1566a2db4fbdSmacallan
1567a2db4fbdSmacallan crmfb_make_room(sc, 6);
1568a2db4fbdSmacallan /* only write into the alpha channel */
1569a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1570a2db4fbdSmacallan DE_DRAWMODE_PLANEMASK | 0x08 |
1571a2db4fbdSmacallan DE_DRAWMODE_XFER_EN);
1572a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1573a2db4fbdSmacallan DE_PRIM_RECTANGLE | DE_PRIM_TB);
1574a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1);
1575a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 0);
1576a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1577a2db4fbdSmacallan (xx << 16) | (sc->sc_height & 0xffff));
1578a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
1579a2db4fbdSmacallan CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1580a2db4fbdSmacallan ((xx + wi - 1) << 16) | ((sc->sc_height + he - 1) & 0xffff));
1581a2db4fbdSmacallan
1582a2db4fbdSmacallan /* now draw the actual character */
1583a2db4fbdSmacallan crmfb_make_room(sc, 2);
1584a2db4fbdSmacallan crmfb_src_mode(sc,
1585a2db4fbdSmacallan DE_MODE_TLB_A |
1586a2db4fbdSmacallan DE_MODE_BUFDEPTH_32 |
1587a2db4fbdSmacallan DE_MODE_TYPE_RGBA |
1588a2db4fbdSmacallan DE_MODE_PIXDEPTH_32);
1589a2db4fbdSmacallan crmfb_dst_mode(sc, sc->sc_de_mode);
1590a2db4fbdSmacallan
1591a2db4fbdSmacallan crmfb_make_room(sc, 6);
1592a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1593a2db4fbdSmacallan DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK |
1594a2db4fbdSmacallan DE_DRAWMODE_ALPHA_BLEND |
1595a2db4fbdSmacallan DE_DRAWMODE_XFER_EN);
1596a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ALPHA_FUNC,
1597a2db4fbdSmacallan DE_ALPHA_ADD |
1598a2db4fbdSmacallan (DE_ALPHA_OP_SRC_ALPHA << DE_ALPHA_OP_SRC_SHIFT) |
1599a2db4fbdSmacallan (DE_ALPHA_OP_1_MINUS_SRC_ALPHA << DE_ALPHA_OP_DST_SHIFT));
1600a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1601a2db4fbdSmacallan DE_PRIM_RECTANGLE | DE_PRIM_TB);
1602a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC,
1603a2db4fbdSmacallan (xx << 16) | (sc->sc_height & 0xffff));
1604a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1605a2db4fbdSmacallan (x << 16) | (y & 0xffff));
1606a2db4fbdSmacallan bus_space_write_4(sc->sc_iot, sc->sc_reh,
1607a2db4fbdSmacallan CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1608a2db4fbdSmacallan ((x + wi - 1) << 16) | ((y + he - 1) & 0xffff));
1609a2db4fbdSmacallan }
1610a2db4fbdSmacallan
1611a2db4fbdSmacallan static void
crmfb_setup_ddc(struct crmfb_softc * sc)16129b94525aSmacallan crmfb_setup_ddc(struct crmfb_softc *sc)
16139b94525aSmacallan {
16149b94525aSmacallan int i;
16159b94525aSmacallan
161671305eb6Smacallan memset(sc->sc_edid_data, 0, 128);
1617601e1783Sthorpej iic_tag_init(&sc->sc_i2c);
16189b94525aSmacallan sc->sc_i2c.ic_cookie = sc;
16199b94525aSmacallan sc->sc_i2c.ic_send_start = crmfb_i2c_send_start;
16209b94525aSmacallan sc->sc_i2c.ic_send_stop = crmfb_i2c_send_stop;
16219b94525aSmacallan sc->sc_i2c.ic_initiate_xfer = crmfb_i2c_initiate_xfer;
16229b94525aSmacallan sc->sc_i2c.ic_read_byte = crmfb_i2c_read_byte;
16239b94525aSmacallan sc->sc_i2c.ic_write_byte = crmfb_i2c_write_byte;
16249b94525aSmacallan i = 0;
162571305eb6Smacallan while (sc->sc_edid_data[1] == 0 && i++ < 10)
162671305eb6Smacallan ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128);
16279b94525aSmacallan if (i > 1)
16289b94525aSmacallan aprint_debug_dev(sc->sc_dev,
16299b94525aSmacallan "had to try %d times to get EDID data\n", i);
16309b94525aSmacallan if (i < 11) {
163171305eb6Smacallan edid_parse(sc->sc_edid_data, &sc->sc_edid_info);
1632713b73c8Smacallan edid_print(&sc->sc_edid_info);
16339b94525aSmacallan }
16349b94525aSmacallan }
16359b94525aSmacallan
16369b94525aSmacallan /* I2C bitbanging */
16379b94525aSmacallan static void
crmfb_i2cbb_set_bits(void * cookie,uint32_t bits)16389b94525aSmacallan crmfb_i2cbb_set_bits(void *cookie, uint32_t bits)
16399b94525aSmacallan {
16409b94525aSmacallan struct crmfb_softc *sc = cookie;
16419b94525aSmacallan
16429b94525aSmacallan bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA, bits ^ 3);
16439b94525aSmacallan }
16449b94525aSmacallan
16459b94525aSmacallan static void
crmfb_i2cbb_set_dir(void * cookie,uint32_t dir)16469b94525aSmacallan crmfb_i2cbb_set_dir(void *cookie, uint32_t dir)
16479b94525aSmacallan {
16489b94525aSmacallan
16499b94525aSmacallan /* Nothing to do */
16509b94525aSmacallan }
16519b94525aSmacallan
16529b94525aSmacallan static uint32_t
crmfb_i2cbb_read(void * cookie)16539b94525aSmacallan crmfb_i2cbb_read(void *cookie)
16549b94525aSmacallan {
16559b94525aSmacallan struct crmfb_softc *sc = cookie;
16569b94525aSmacallan
16579b94525aSmacallan return bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA) ^ 3;
16589b94525aSmacallan }
16599b94525aSmacallan
16609b94525aSmacallan static int
crmfb_i2c_send_start(void * cookie,int flags)16619b94525aSmacallan crmfb_i2c_send_start(void *cookie, int flags)
16629b94525aSmacallan {
16639b94525aSmacallan
16649b94525aSmacallan return i2c_bitbang_send_start(cookie, flags, &crmfb_i2cbb_ops);
16659b94525aSmacallan }
16669b94525aSmacallan
16679b94525aSmacallan static int
crmfb_i2c_send_stop(void * cookie,int flags)16689b94525aSmacallan crmfb_i2c_send_stop(void *cookie, int flags)
16699b94525aSmacallan {
16709b94525aSmacallan
16719b94525aSmacallan return i2c_bitbang_send_stop(cookie, flags, &crmfb_i2cbb_ops);
16729b94525aSmacallan }
16739b94525aSmacallan
16749b94525aSmacallan static int
crmfb_i2c_initiate_xfer(void * cookie,i2c_addr_t addr,int flags)16759b94525aSmacallan crmfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
16769b94525aSmacallan {
16779b94525aSmacallan
16789b94525aSmacallan return i2c_bitbang_initiate_xfer(cookie, addr, flags,
16799b94525aSmacallan &crmfb_i2cbb_ops);
16809b94525aSmacallan }
16819b94525aSmacallan
16829b94525aSmacallan static int
crmfb_i2c_read_byte(void * cookie,uint8_t * valp,int flags)16839b94525aSmacallan crmfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
16849b94525aSmacallan {
16859b94525aSmacallan
16869b94525aSmacallan return i2c_bitbang_read_byte(cookie, valp, flags, &crmfb_i2cbb_ops);
16879b94525aSmacallan }
16889b94525aSmacallan
16899b94525aSmacallan static int
crmfb_i2c_write_byte(void * cookie,uint8_t val,int flags)16909b94525aSmacallan crmfb_i2c_write_byte(void *cookie, uint8_t val, int flags)
16919b94525aSmacallan {
16929b94525aSmacallan
16939b94525aSmacallan return i2c_bitbang_write_byte(cookie, val, flags, &crmfb_i2cbb_ops);
16949b94525aSmacallan }
1695713b73c8Smacallan
1696713b73c8Smacallan /* mode setting stuff */
1697713b73c8Smacallan static uint32_t
calc_pll(int f_out)1698713b73c8Smacallan calc_pll(int f_out)
1699713b73c8Smacallan {
1700713b73c8Smacallan uint32_t ret;
1701713b73c8Smacallan int f_in = 20000; /* 20MHz in */
1702713b73c8Smacallan int M, N, P;
1703713b73c8Smacallan int error, div, best = 9999999;
1704713b73c8Smacallan int ff1, ff2;
1705713b73c8Smacallan int MM = 0, NN = 0, PP = 0, ff = 0;
1706713b73c8Smacallan
1707713b73c8Smacallan /* f_out = M * f_in / (N * (1 << P) */
1708713b73c8Smacallan
1709713b73c8Smacallan for (P = 0; P < 4; P++) {
1710713b73c8Smacallan for (N = 64; N > 0; N--) {
1711713b73c8Smacallan div = N * (1 << P);
1712713b73c8Smacallan M = f_out * div / f_in;
1713713b73c8Smacallan if ((M < 257) && (M > 100)) {
1714713b73c8Smacallan ff1 = M * f_in / div;
1715713b73c8Smacallan ff2 = (M + 1) * f_in / div;
1716713b73c8Smacallan error = abs(ff1 - f_out);
1717713b73c8Smacallan if (error < best) {
1718713b73c8Smacallan MM = M;
1719713b73c8Smacallan NN = N;
1720713b73c8Smacallan PP = P;
1721713b73c8Smacallan ff = ff1;
1722713b73c8Smacallan best = error;
1723713b73c8Smacallan }
1724713b73c8Smacallan error = abs(ff2 - f_out);
1725713b73c8Smacallan if ((error < best) && ( M < 256)){
1726713b73c8Smacallan MM = M + 1;
1727713b73c8Smacallan NN = N;
1728713b73c8Smacallan PP = P;
1729713b73c8Smacallan ff = ff2;
1730713b73c8Smacallan best = error;
1731713b73c8Smacallan }
1732713b73c8Smacallan }
1733713b73c8Smacallan }
1734713b73c8Smacallan }
1735713b73c8Smacallan DPRINTF("%d: M %d N %d P %d -> %d\n", f_out, MM, NN, PP, ff);
1736713b73c8Smacallan /* now shove the parameters into the register's format */
1737713b73c8Smacallan ret = (MM - 1) | ((NN - 1) << 8) | (P << 14);
1738713b73c8Smacallan return ret;
1739713b73c8Smacallan }
1740713b73c8Smacallan
1741713b73c8Smacallan static int
crmfb_set_mode(struct crmfb_softc * sc,const struct videomode * mode)1742713b73c8Smacallan crmfb_set_mode(struct crmfb_softc *sc, const struct videomode *mode)
1743713b73c8Smacallan {
1744713b73c8Smacallan uint32_t d, dc;
1745713b73c8Smacallan int tmp, diff;
1746713b73c8Smacallan
1747fa88ee42Smacallan switch (mode->hdisplay % 32) {
1748fa88ee42Smacallan case 0:
1749fa88ee42Smacallan sc->sc_console_depth = 8;
1750fa88ee42Smacallan break;
1751fa88ee42Smacallan case 16:
1752fa88ee42Smacallan sc->sc_console_depth = 16;
1753fa88ee42Smacallan break;
1754fa88ee42Smacallan case 8:
1755fa88ee42Smacallan case 24:
1756fa88ee42Smacallan sc->sc_console_depth = 32;
1757fa88ee42Smacallan break;
1758fa88ee42Smacallan default:
1759fa88ee42Smacallan aprint_error_dev(sc->sc_dev,
1760fa88ee42Smacallan "hdisplay (%d) is not a multiple of 32\n",
1761fa88ee42Smacallan mode->hdisplay);
1762713b73c8Smacallan return FALSE;
1763713b73c8Smacallan }
1764fa88ee42Smacallan if (mode->dot_clock > 150000) {
1765fa88ee42Smacallan aprint_error_dev(sc->sc_dev,
1766fa88ee42Smacallan "requested dot clock is too high ( %d MHz )\n",
1767fa88ee42Smacallan mode->dot_clock / 1000);
1768713b73c8Smacallan return FALSE;
1769713b73c8Smacallan }
1770713b73c8Smacallan
1771713b73c8Smacallan /* disable DMA */
1772713b73c8Smacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL);
1773713b73c8Smacallan d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT);
1774713b73c8Smacallan crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d);
1775713b73c8Smacallan DELAY(50000);
1776713b73c8Smacallan d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
1777713b73c8Smacallan d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
1778713b73c8Smacallan crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
1779713b73c8Smacallan DELAY(50000);
1780713b73c8Smacallan crmfb_write_reg(sc, CRMFB_DID_CONTROL, d);
1781713b73c8Smacallan DELAY(50000);
1782713b73c8Smacallan
1783713b73c8Smacallan if (!crmfb_wait_dma_idle(sc))
1784713b73c8Smacallan aprint_error("crmfb: crmfb_wait_dma_idle timed out\n");
1785713b73c8Smacallan
1786713b73c8Smacallan /* ok, now we're good to go */
1787713b73c8Smacallan dc = calc_pll(mode->dot_clock);
1788713b73c8Smacallan
1789713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_XY, 1 << CRMFB_VT_XY_FREEZE_SHIFT);
1790713b73c8Smacallan delay(1000);
1791713b73c8Smacallan
1792713b73c8Smacallan /* set the dot clock pll but don't start it yet */
1793713b73c8Smacallan crmfb_write_reg(sc, CRMFB_DOTCLOCK, dc);
1794713b73c8Smacallan delay(10000);
1795713b73c8Smacallan
1796713b73c8Smacallan /* pixel counter */
1797713b73c8Smacallan d = mode->htotal | (mode->vtotal << 12);
1798713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_XYMAX, d);
1799713b73c8Smacallan
1800713b73c8Smacallan /* video timings */
1801713b73c8Smacallan d = mode->vsync_end | (mode->vsync_start << 12);
1802713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_VSYNC, d);
1803713b73c8Smacallan
1804713b73c8Smacallan d = mode->hsync_end | (mode->hsync_start << 12);
1805713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_HSYNC, d);
1806713b73c8Smacallan
1807713b73c8Smacallan d = mode->vtotal | (mode->vdisplay << 12);
1808713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_VBLANK, d);
1809713b73c8Smacallan
1810713b73c8Smacallan d = (mode->htotal - 5) | ((mode->hdisplay - 5) << 12);
1811713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_HBLANK, d);
1812713b73c8Smacallan
1813713b73c8Smacallan d = mode->vtotal | (mode->vdisplay << 12);
1814713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_VCMAP, d);
1815713b73c8Smacallan d = mode->htotal | (mode->hdisplay << 12);
1816713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_HCMAP, d);
1817713b73c8Smacallan
1818713b73c8Smacallan d = 0;
1819713b73c8Smacallan if (mode->flags & VID_NHSYNC) d |= CRMFB_VT_FLAGS_HDRV_INVERT;
1820713b73c8Smacallan if (mode->flags & VID_NVSYNC) d |= CRMFB_VT_FLAGS_VDRV_INVERT;
1821713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_FLAGS, d);
182271305eb6Smacallan sc->sc_vtflags = d;
1823713b73c8Smacallan
1824713b73c8Smacallan diff = -abs(mode->vtotal - mode->vdisplay - 1);
1825713b73c8Smacallan d = ((uint32_t)diff << 12) & 0x00fff000;
1826713b73c8Smacallan d |= (mode->htotal - 20);
1827713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_DID_STARTXY, d);
1828713b73c8Smacallan
1829713b73c8Smacallan d = ((uint32_t)(diff + 1) << 12) & 0x00fff000;
1830713b73c8Smacallan d |= (mode->htotal - 54);
1831713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_CRS_STARTXY, d);
1832713b73c8Smacallan
1833713b73c8Smacallan d = ((uint32_t)diff << 12) & 0x00fff000;
1834713b73c8Smacallan d |= (mode->htotal - 4);
1835713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_VC_STARTXY, d);
1836713b73c8Smacallan
1837713b73c8Smacallan tmp = mode->htotal - 19;
1838713b73c8Smacallan d = tmp << 12;
1839713b73c8Smacallan d |= ((tmp + mode->hdisplay - 2) % mode->htotal);
1840713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_HPIX_EN, d);
1841713b73c8Smacallan
1842713b73c8Smacallan d = mode->vdisplay | (mode->vtotal << 12);
1843713b73c8Smacallan crmfb_write_reg(sc, CRMFB_VT_VPIX_EN, d);
1844713b73c8Smacallan
1845713b73c8Smacallan sc->sc_width = mode->hdisplay;
1846713b73c8Smacallan sc->sc_height = mode->vdisplay;
1847713b73c8Smacallan
1848713b73c8Smacallan return TRUE;
1849713b73c8Smacallan }
185095923c6fSjmcneill
185195923c6fSjmcneill /*
185295923c6fSjmcneill * Parse a mode string in the form WIDTHxHEIGHT[@REFRESH] and return
185395923c6fSjmcneill * monitor timings generated using the VESA GTF formula.
185495923c6fSjmcneill */
185595923c6fSjmcneill static int
crmfb_parse_mode(const char * modestr,struct videomode * mode)185695923c6fSjmcneill crmfb_parse_mode(const char *modestr, struct videomode *mode)
185795923c6fSjmcneill {
185895923c6fSjmcneill char *x, *at;
185995923c6fSjmcneill int width, height, refresh;
186095923c6fSjmcneill
186195923c6fSjmcneill if (modestr == NULL)
186295923c6fSjmcneill return EINVAL;
186395923c6fSjmcneill
186495923c6fSjmcneill x = strchr(modestr, 'x');
186595923c6fSjmcneill at = strchr(modestr, '@');
186695923c6fSjmcneill
186795923c6fSjmcneill if (x == NULL || (at != NULL && at < x))
186895923c6fSjmcneill return EINVAL;
186995923c6fSjmcneill
187095923c6fSjmcneill width = strtoul(modestr, NULL, 10);
187195923c6fSjmcneill height = strtoul(x + 1, NULL, 10);
187295923c6fSjmcneill refresh = at ? strtoul(at + 1, NULL, 10) : 60;
187395923c6fSjmcneill
187495923c6fSjmcneill if (width == 0 || height == 0 || refresh == 0)
187595923c6fSjmcneill return EINVAL;
187695923c6fSjmcneill
187795923c6fSjmcneill vesagtf_mode(width, height, refresh, mode);
187895923c6fSjmcneill
187995923c6fSjmcneill return 0;
188095923c6fSjmcneill }
1881