1 /* $NetBSD: crmfb.c,v 1.50 2023/12/20 15:29:07 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
5 * 2008 Michael Lorenz <macallan@netbsd.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * SGI-CRM (O2) Framebuffer driver
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.50 2023/12/20 15:29:07 thorpej Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40
41 #include <machine/autoconf.h>
42 #include <sys/bus.h>
43 #include <machine/machtype.h>
44 #include <machine/vmparam.h>
45
46 #include <dev/arcbios/arcbios.h>
47 #include <dev/arcbios/arcbiosvar.h>
48
49 #include <dev/wscons/wsdisplayvar.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wsfont/wsfont.h>
52 #include <dev/rasops/rasops.h>
53 #include <dev/wscons/wsdisplay_vconsvar.h>
54
55 #include <dev/i2c/i2cvar.h>
56 #include <dev/i2c/i2c_bitbang.h>
57 #include <dev/i2c/ddcvar.h>
58 #include <dev/videomode/videomode.h>
59 #include <dev/videomode/vesagtf.h>
60 #include <dev/videomode/edidvar.h>
61
62 #include <arch/sgimips/dev/crmfbreg.h>
63
64 #include "opt_crmfb.h"
65
66 #ifdef CRMFB_DEBUG
67 #define DPRINTF printf
68 #else
69 #define DPRINTF while (0) printf
70 #endif
71
72 struct wsscreen_descr crmfb_defaultscreen = {
73 "default",
74 0, 0,
75 NULL,
76 8, 16,
77 WSSCREEN_WSCOLORS | WSSCREEN_RESIZE,
78 NULL,
79 };
80
81 const struct wsscreen_descr *_crmfb_scrlist[] = {
82 &crmfb_defaultscreen,
83 };
84
85 struct wsscreen_list crmfb_screenlist = {
86 sizeof(_crmfb_scrlist) / sizeof(struct wsscreen_descr *),
87 _crmfb_scrlist
88 };
89
90 static struct vcons_screen crmfb_console_screen;
91
92 static int crmfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
93 static paddr_t crmfb_mmap(void *, void *, off_t, int);
94 static void crmfb_init_screen(void *, struct vcons_screen *, int, long *);
95
96 struct wsdisplay_accessops crmfb_accessops = {
97 crmfb_ioctl,
98 crmfb_mmap,
99 NULL, /* alloc_screen */
100 NULL, /* free_screen */
101 NULL, /* show_screen */
102 NULL, /* load_font */
103 NULL, /* pollc */
104 NULL, /* scroll */
105 };
106
107 /* Memory to allocate to SGI-CRM -- remember, this is stolen from
108 * host memory!
109 */
110 #define CRMFB_TILESIZE (512*128)
111
112 static int crmfb_match(device_t, struct cfdata *, void *);
113 static void crmfb_attach(device_t, device_t, void *);
114 int crmfb_probe(void);
115
116 #define KERNADDR(p) ((void *)((p).addr))
117 #define DMAADDR(p) ((p).map->dm_segs[0].ds_addr)
118
119 #define CRMFB_REG_MASK(msb, lsb) \
120 ( (((uint32_t) 1 << ((msb)-(lsb)+1)) - 1) << (lsb) )
121
122
123 struct crmfb_dma {
124 bus_dmamap_t map;
125 void *addr;
126 bus_dma_segment_t segs[1];
127 int nsegs;
128 size_t size;
129 };
130
131 struct crmfb_softc {
132 device_t sc_dev;
133 struct vcons_data sc_vd;
134 struct i2c_controller sc_i2c;
135 int sc_dir;
136
137 bus_space_tag_t sc_iot;
138 bus_space_handle_t sc_ioh;
139 bus_space_handle_t sc_reh;
140
141 bus_dma_tag_t sc_dmat;
142
143 struct crmfb_dma sc_dma;
144 struct crmfb_dma sc_dmai;
145
146 int sc_width;
147 int sc_height;
148 int sc_depth;
149 int sc_console_depth;
150 int sc_tiles_x, sc_tiles_y;
151 uint32_t sc_fbsize;
152 int sc_mte_direction;
153 int sc_mte_x_shift;
154 uint32_t sc_mte_mode;
155 uint32_t sc_de_mode;
156 uint32_t sc_src_mode;
157 uint32_t sc_dst_mode;
158 int sc_needs_sync;
159 uint8_t *sc_lptr;
160 paddr_t sc_linear;
161 uint32_t sc_vtflags;
162 int sc_wsmode, sc_video_on;
163 uint8_t sc_edid_data[128];
164 struct edid_info sc_edid_info;
165
166 /* cursor stuff */
167 int sc_cur_x;
168 int sc_cur_y;
169 int sc_hot_x;
170 int sc_hot_y;
171
172 u_char sc_cmap_red[256];
173 u_char sc_cmap_green[256];
174 u_char sc_cmap_blue[256];
175 };
176
177 static int crmfb_putcmap(struct crmfb_softc *, struct wsdisplay_cmap *);
178 static int crmfb_getcmap(struct crmfb_softc *, struct wsdisplay_cmap *);
179 static void crmfb_set_palette(struct crmfb_softc *,
180 int, uint8_t, uint8_t, uint8_t);
181 static int crmfb_set_curpos(struct crmfb_softc *, int, int);
182 static int crmfb_gcursor(struct crmfb_softc *, struct wsdisplay_cursor *);
183 static int crmfb_scursor(struct crmfb_softc *, struct wsdisplay_cursor *);
184 static inline void crmfb_write_reg(struct crmfb_softc *, int, uint32_t);
185 static inline uint32_t crmfb_read_reg(struct crmfb_softc *, int);
186 static int crmfb_wait_dma_idle(struct crmfb_softc *);
187
188 /* setup video hw in given colour depth */
189 static int crmfb_setup_video(struct crmfb_softc *, int);
190 static void crmfb_setup_palette(struct crmfb_softc *);
191
192 static void crmfb_fill_rect(struct crmfb_softc *, int, int, int, int, uint32_t);
193 static void crmfb_bitblt(struct crmfb_softc *, int, int, int, int, int, int,
194 uint32_t);
195 static void crmfb_scroll(struct crmfb_softc *, int, int, int, int, int, int);
196
197 static void crmfb_copycols(void *, int, int, int, int);
198 static void crmfb_erasecols(void *, int, int, int, long);
199 static void crmfb_copyrows(void *, int, int, int);
200 static void crmfb_eraserows(void *, int, int, long);
201 static void crmfb_cursor(void *, int, int, int);
202 static void crmfb_putchar(void *, int, int, u_int, long);
203 static void crmfb_putchar_aa(void *, int, int, u_int, long);
204
205 /* I2C glue */
206 static int crmfb_i2c_send_start(void *, int);
207 static int crmfb_i2c_send_stop(void *, int);
208 static int crmfb_i2c_initiate_xfer(void *, i2c_addr_t, int);
209 static int crmfb_i2c_read_byte(void *, uint8_t *, int);
210 static int crmfb_i2c_write_byte(void *, uint8_t, int);
211
212 /* I2C bitbang glue */
213 static void crmfb_i2cbb_set_bits(void *, uint32_t);
214 static void crmfb_i2cbb_set_dir(void *, uint32_t);
215 static uint32_t crmfb_i2cbb_read(void *);
216
217 static const struct i2c_bitbang_ops crmfb_i2cbb_ops = {
218 crmfb_i2cbb_set_bits,
219 crmfb_i2cbb_set_dir,
220 crmfb_i2cbb_read,
221 {
222 CRMFB_I2C_SDA,
223 CRMFB_I2C_SCL,
224 0,
225 1
226 }
227 };
228 static void crmfb_setup_ddc(struct crmfb_softc *);
229
230 /* mode setting stuff */
231 static uint32_t calc_pll(int); /* frequency in kHz */
232 static int crmfb_set_mode(struct crmfb_softc *, const struct videomode *);
233 static int crmfb_parse_mode(const char *, struct videomode *);
234
235 CFATTACH_DECL_NEW(crmfb, sizeof(struct crmfb_softc),
236 crmfb_match, crmfb_attach, NULL, NULL);
237
238 static int
crmfb_match(device_t parent,struct cfdata * cf,void * opaque)239 crmfb_match(device_t parent, struct cfdata *cf, void *opaque)
240 {
241 return crmfb_probe();
242 }
243
244 static void
crmfb_attach(device_t parent,device_t self,void * opaque)245 crmfb_attach(device_t parent, device_t self, void *opaque)
246 {
247 struct mainbus_attach_args *ma;
248 struct crmfb_softc *sc;
249 struct rasops_info *ri;
250 struct wsemuldisplaydev_attach_args aa;
251 uint32_t d, h;
252 uint16_t *p;
253 unsigned long v;
254 long defattr;
255 const char *consdev;
256 const char *modestr;
257 struct videomode mode, *pmode;
258 int rv, i;
259
260 sc = device_private(self);
261 sc->sc_dev = self;
262
263 ma = (struct mainbus_attach_args *)opaque;
264
265 sc->sc_iot = normal_memt;
266 sc->sc_dmat = &sgimips_default_bus_dma_tag;
267 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
268
269 aprint_normal(": SGI CRIME Graphics Display Engine\n");
270 rv = bus_space_map(sc->sc_iot, ma->ma_addr, 0 /* XXX */,
271 BUS_SPACE_MAP_LINEAR, &sc->sc_ioh);
272 if (rv)
273 panic("crmfb_attach: can't map I/O space");
274 rv = bus_space_map(sc->sc_iot, 0x15000000, 0x6000, 0, &sc->sc_reh);
275 if (rv)
276 panic("crmfb_attach: can't map rendering engine");
277
278 /* determine mode configured by firmware */
279 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP);
280 sc->sc_width = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff;
281 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_VCMAP);
282 sc->sc_height = (d >> CRMFB_VT_VCMAP_ON_SHIFT) & 0xfff;
283 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE);
284 h = (d >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 0x3;
285 if (h == 0)
286 sc->sc_depth = 8;
287 else if (h == 1)
288 sc->sc_depth = 16;
289 else
290 sc->sc_depth = 32;
291
292 if (sc->sc_width == 0 || sc->sc_height == 0) {
293 /*
294 * XXX
295 * actually, these days we probably could
296 */
297 aprint_error_dev(sc->sc_dev,
298 "device unusable if not setup by firmware\n");
299 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0 /* XXX */);
300 return;
301 }
302
303 aprint_normal_dev(sc->sc_dev, "initial resolution %dx%d\n",
304 sc->sc_width, sc->sc_height);
305
306 sc->sc_console_depth = 8;
307
308 crmfb_setup_ddc(sc);
309 pmode = sc->sc_edid_info.edid_preferred_mode;
310
311 modestr = arcbios_GetEnvironmentVariable("crmfb_mode");
312 if (crmfb_parse_mode(modestr, &mode) == 0)
313 pmode = &mode;
314
315 if (pmode != NULL && crmfb_set_mode(sc, pmode))
316 aprint_normal_dev(sc->sc_dev, "using %dx%d\n",
317 sc->sc_width, sc->sc_height);
318
319 /*
320 * first determine how many tiles we need
321 * in 32bit each tile is 128x128 pixels
322 */
323 sc->sc_tiles_x = (sc->sc_width + 127) >> 7;
324 sc->sc_tiles_y = (sc->sc_height + 127) >> 7;
325 sc->sc_fbsize = 0x10000 * sc->sc_tiles_x * sc->sc_tiles_y;
326
327 sc->sc_dmai.size = 256 * sizeof(uint16_t);
328 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmai.size, 65536, 0,
329 sc->sc_dmai.segs,
330 sizeof(sc->sc_dmai.segs) / sizeof(sc->sc_dmai.segs[0]),
331 &sc->sc_dmai.nsegs, BUS_DMA_NOWAIT);
332 if (rv)
333 panic("crmfb_attach: can't allocate DMA memory");
334 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dmai.segs, sc->sc_dmai.nsegs,
335 sc->sc_dmai.size, &sc->sc_dmai.addr,
336 BUS_DMA_NOWAIT);
337 if (rv)
338 panic("crmfb_attach: can't map DMA memory");
339 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dmai.size, 1,
340 sc->sc_dmai.size, 0, BUS_DMA_NOWAIT, &sc->sc_dmai.map);
341 if (rv)
342 panic("crmfb_attach: can't create DMA map");
343 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmai.map, sc->sc_dmai.addr,
344 sc->sc_dmai.size, NULL, BUS_DMA_NOWAIT);
345 if (rv)
346 panic("crmfb_attach: can't load DMA map");
347
348 /* allocate an extra 128Kb for a linear buffer */
349 sc->sc_dma.size = 0x10000 * (16 * sc->sc_tiles_x + 2);
350 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0,
351 sc->sc_dma.segs,
352 sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]),
353 &sc->sc_dma.nsegs, BUS_DMA_NOWAIT);
354 if (rv)
355 panic("crmfb_attach: can't allocate DMA memory");
356 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dma.segs, sc->sc_dma.nsegs,
357 sc->sc_dma.size, &sc->sc_dma.addr,
358 BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
359 if (rv)
360 panic("crmfb_attach: can't map DMA memory");
361 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dma.size, 1,
362 sc->sc_dma.size, 0, BUS_DMA_NOWAIT, &sc->sc_dma.map);
363 if (rv)
364 panic("crmfb_attach: can't create DMA map");
365
366 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr,
367 sc->sc_dma.size, NULL, BUS_DMA_NOWAIT);
368 if (rv)
369 panic("crmfb_attach: can't load DMA map");
370
371 p = KERNADDR(sc->sc_dmai);
372 v = (unsigned long)DMAADDR(sc->sc_dma);
373 for (i = 0; i < (sc->sc_tiles_x * sc->sc_tiles_y); i++) {
374 p[i] = ((uint32_t)v >> 16) + i;
375 }
376
377 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmai.map, 0, sc->sc_dmai.size,
378 BUS_DMASYNC_PREWRITE);
379
380 sc->sc_linear = (paddr_t)DMAADDR(sc->sc_dma) + 0x100000 * sc->sc_tiles_x;
381 sc->sc_lptr = (char *)KERNADDR(sc->sc_dma) + (0x100000 * sc->sc_tiles_x);
382
383 aprint_normal_dev(sc->sc_dev, "allocated %d byte fb @ %p (%p)\n",
384 sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma));
385
386 crmfb_setup_video(sc, sc->sc_console_depth);
387 ri = &crmfb_console_screen.scr_ri;
388 memset(ri, 0, sizeof(struct rasops_info));
389 sc->sc_video_on = 1;
390
391 vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops);
392 sc->sc_vd.init_screen = crmfb_init_screen;
393 crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
394 vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr);
395
396 crmfb_defaultscreen.ncols = ri->ri_cols;
397 crmfb_defaultscreen.nrows = ri->ri_rows;
398 crmfb_defaultscreen.textops = &ri->ri_ops;
399 crmfb_defaultscreen.capabilities = ri->ri_caps;
400 crmfb_defaultscreen.modecookie = NULL;
401
402 crmfb_setup_palette(sc);
403 crmfb_fill_rect(sc, 0, 0, sc->sc_width, sc->sc_height,
404 ri->ri_devcmap[(defattr >> 16) & 0xff]);
405
406 consdev = arcbios_GetEnvironmentVariable("ConsoleOut");
407 if (consdev != NULL && strcmp(consdev, "video()") == 0) {
408 wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr);
409 vcons_replay_msgbuf(&crmfb_console_screen);
410 aa.console = 1;
411 } else
412 aa.console = 0;
413 aa.scrdata = &crmfb_screenlist;
414 aa.accessops = &crmfb_accessops;
415 aa.accesscookie = &sc->sc_vd;
416
417 config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
418
419 sc->sc_cur_x = 0;
420 sc->sc_cur_y = 0;
421 sc->sc_hot_x = 0;
422 sc->sc_hot_y = 0;
423
424 return;
425 }
426
427 int
crmfb_probe(void)428 crmfb_probe(void)
429 {
430
431 if (mach_type != MACH_SGI_IP32)
432 return 0;
433
434 return 1;
435 }
436
437 static int
crmfb_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)438 crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
439 {
440 struct vcons_data *vd;
441 struct crmfb_softc *sc;
442 struct wsdisplay_fbinfo *wdf;
443 int nmode;
444
445 vd = (struct vcons_data *)v;
446 sc = (struct crmfb_softc *)vd->cookie;
447
448 switch (cmd) {
449 case WSDISPLAYIO_GTYPE:
450 /* not really, but who cares? */
451 /* xf86-video-crime does */
452 *(u_int *)data = WSDISPLAY_TYPE_CRIME;
453 return 0;
454 case WSDISPLAYIO_GINFO:
455 if (vd->active != NULL) {
456 wdf = (void *)data;
457 wdf->height = sc->sc_height;
458 wdf->width = sc->sc_width;
459 wdf->depth = 32;
460 wdf->cmsize = 256;
461 return 0;
462 } else
463 return ENODEV;
464 case WSDISPLAYIO_GETCMAP:
465 if (sc->sc_depth == 8)
466 return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data);
467 else
468 return EINVAL;
469 case WSDISPLAYIO_PUTCMAP:
470 if (sc->sc_depth == 8)
471 return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data);
472 else
473 return EINVAL;
474 case WSDISPLAYIO_LINEBYTES:
475 *(u_int *)data = sc->sc_width * sc->sc_depth / 8;
476 return 0;
477 case WSDISPLAYIO_SMODE:
478 nmode = *(int *)data;
479 if (nmode != sc->sc_wsmode) {
480 sc->sc_wsmode = nmode;
481 if (nmode == WSDISPLAYIO_MODE_EMUL) {
482 crmfb_setup_video(sc, sc->sc_console_depth);
483 crmfb_setup_palette(sc);
484 vcons_redraw_screen(vd->active);
485 } else {
486 crmfb_setup_video(sc, 32);
487 }
488 }
489 return 0;
490 case WSDISPLAYIO_SVIDEO:
491 {
492 int d = *(int *)data;
493 if (d == sc->sc_video_on)
494 return 0;
495 sc->sc_video_on = d;
496 if (d == WSDISPLAYIO_VIDEO_ON) {
497 crmfb_write_reg(sc,
498 CRMFB_VT_FLAGS, sc->sc_vtflags);
499 } else {
500 /* turn all SYNCs off */
501 crmfb_write_reg(sc, CRMFB_VT_FLAGS,
502 sc->sc_vtflags | CRMFB_VT_FLAGS_VDRV_LOW |
503 CRMFB_VT_FLAGS_HDRV_LOW |
504 CRMFB_VT_FLAGS_SYNC_LOW);
505 }
506 }
507 return 0;
508
509 case WSDISPLAYIO_GVIDEO:
510 *(int *)data = sc->sc_video_on;
511 return 0;
512
513 case WSDISPLAYIO_GCURPOS:
514 {
515 struct wsdisplay_curpos *pos;
516
517 pos = (struct wsdisplay_curpos *)data;
518 pos->x = sc->sc_cur_x;
519 pos->y = sc->sc_cur_y;
520 }
521 return 0;
522 case WSDISPLAYIO_SCURPOS:
523 {
524 struct wsdisplay_curpos *pos;
525
526 pos = (struct wsdisplay_curpos *)data;
527 crmfb_set_curpos(sc, pos->x, pos->y);
528 }
529 return 0;
530 case WSDISPLAYIO_GCURMAX:
531 {
532 struct wsdisplay_curpos *pos;
533
534 pos = (struct wsdisplay_curpos *)data;
535 pos->x = 32;
536 pos->y = 32;
537 }
538 return 0;
539 case WSDISPLAYIO_GCURSOR:
540 {
541 struct wsdisplay_cursor *cu;
542
543 cu = (struct wsdisplay_cursor *)data;
544 return crmfb_gcursor(sc, cu);
545 }
546 case WSDISPLAYIO_SCURSOR:
547 {
548 struct wsdisplay_cursor *cu;
549
550 cu = (struct wsdisplay_cursor *)data;
551 return crmfb_scursor(sc, cu);
552 }
553 case WSDISPLAYIO_GET_EDID: {
554 struct wsdisplayio_edid_info *d = data;
555
556 d->data_size = 128;
557 if (d->buffer_size < 128)
558 return EAGAIN;
559 if (sc->sc_edid_data[1] == 0)
560 return ENODATA;
561 return copyout(sc->sc_edid_data, d->edid_data, 128);
562 }
563 }
564 return EPASSTHROUGH;
565 }
566
567 static paddr_t
crmfb_mmap(void * v,void * vs,off_t offset,int prot)568 crmfb_mmap(void *v, void *vs, off_t offset, int prot)
569 {
570 struct vcons_data *vd;
571 struct crmfb_softc *sc;
572 paddr_t pa;
573
574 vd = (struct vcons_data *)v;
575 sc = (struct crmfb_softc *)vd->cookie;
576
577 /* we probably shouldn't let anyone mmap the framebuffer */
578 #if 1
579 if (offset >= 0 && offset < (0x100000 * sc->sc_tiles_x)) {
580 pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs,
581 sc->sc_dma.nsegs, offset, prot,
582 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE);
583 return pa;
584 }
585 #endif
586 /*
587 * here would the TLBs be but we don't want to show them to userland
588 * so we return the page containing the status register
589 */
590 if ((offset >= 0x15000000) && (offset < 0x15002000))
591 return bus_space_mmap(sc->sc_iot, 0x15004000, 0, prot, 0);
592 /* now the actual engine registers */
593 if ((offset >= 0x15002000) && (offset < 0x15005000))
594 return bus_space_mmap(sc->sc_iot, offset, 0, prot, 0);
595 /* and now the linear area */
596 if ((offset >= 0x15010000) && (offset < 0x15030000))
597 return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs,
598 sc->sc_dma.nsegs,
599 offset + (0x100000 * sc->sc_tiles_x) - 0x15010000, prot,
600 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_PREFETCHABLE);
601 return -1;
602 }
603
604 static void
crmfb_init_screen(void * c,struct vcons_screen * scr,int existing,long * defattr)605 crmfb_init_screen(void *c, struct vcons_screen *scr, int existing,
606 long *defattr)
607 {
608 struct crmfb_softc *sc;
609 struct rasops_info *ri;
610
611 sc = (struct crmfb_softc *)c;
612 ri = &scr->scr_ri;
613
614 scr->scr_flags |= VCONS_LOADFONT;
615
616 ri->ri_flg = RI_CENTER | RI_FULLCLEAR |
617 RI_ENABLE_ALPHA | RI_PREFER_ALPHA;
618 ri->ri_depth = sc->sc_console_depth;
619 ri->ri_width = sc->sc_width;
620 ri->ri_height = sc->sc_height;
621 ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
622
623 switch (ri->ri_depth) {
624 case 8:
625 ri->ri_flg |= RI_8BIT_IS_RGB;
626 break;
627 case 16:
628 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5;
629 ri->ri_rpos = 11;
630 ri->ri_gpos = 6;
631 ri->ri_bpos = 1;
632 break;
633 case 32:
634 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
635 ri->ri_rpos = 8;
636 ri->ri_gpos = 16;
637 ri->ri_bpos = 24;
638 break;
639 }
640
641 ri->ri_bits = NULL;
642
643 rasops_init(ri, 0, 0);
644 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_RESIZE;
645 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
646 ri->ri_width / ri->ri_font->fontwidth);
647 ri->ri_hw = scr;
648
649 ri->ri_ops.cursor = crmfb_cursor;
650 ri->ri_ops.copyrows = crmfb_copyrows;
651 ri->ri_ops.eraserows = crmfb_eraserows;
652 ri->ri_ops.copycols = crmfb_copycols;
653 ri->ri_ops.erasecols = crmfb_erasecols;
654 if (FONT_IS_ALPHA(ri->ri_font)) {
655 ri->ri_ops.putchar = crmfb_putchar_aa;
656 } else {
657 ri->ri_ops.putchar = crmfb_putchar;
658 }
659 return;
660 }
661
662 static int
crmfb_putcmap(struct crmfb_softc * sc,struct wsdisplay_cmap * cm)663 crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm)
664 {
665 u_int idx, cnt;
666 u_char r[256], g[256], b[256];
667 u_char *rp, *gp, *bp;
668 int rv, i;
669
670 idx = cm->index;
671 cnt = cm->count;
672
673 if (idx >= 255 || cnt > 256 || idx + cnt > 256)
674 return EINVAL;
675
676 rv = copyin(cm->red, &r[idx], cnt);
677 if (rv)
678 return rv;
679 rv = copyin(cm->green, &g[idx], cnt);
680 if (rv)
681 return rv;
682 rv = copyin(cm->blue, &b[idx], cnt);
683 if (rv)
684 return rv;
685
686 memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt);
687 memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt);
688 memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt);
689
690 rp = &sc->sc_cmap_red[idx];
691 gp = &sc->sc_cmap_green[idx];
692 bp = &sc->sc_cmap_blue[idx];
693
694 for (i = 0; i < cnt; i++) {
695 crmfb_set_palette(sc, idx, *rp, *gp, *bp);
696 idx++;
697 rp++, gp++, bp++;
698 }
699
700 return 0;
701 }
702
703 static int
crmfb_getcmap(struct crmfb_softc * sc,struct wsdisplay_cmap * cm)704 crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm)
705 {
706 u_int idx, cnt;
707 int rv;
708
709 idx = cm->index;
710 cnt = cm->count;
711
712 if (idx >= 255 || cnt > 256 || idx + cnt > 256)
713 return EINVAL;
714
715 rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt);
716 if (rv)
717 return rv;
718 rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt);
719 if (rv)
720 return rv;
721 rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt);
722 if (rv)
723 return rv;
724
725 return 0;
726 }
727
728 static void
crmfb_set_palette(struct crmfb_softc * sc,int reg,uint8_t r,uint8_t g,uint8_t b)729 crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g,
730 uint8_t b)
731 {
732 uint32_t val;
733
734 if (reg > 255 || sc->sc_depth != 8)
735 return;
736
737 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63)
738 DELAY(10);
739
740 val = (r << 8) | (g << 16) | (b << 24);
741 crmfb_write_reg(sc, CRMFB_CMAP + (reg * 4), val);
742
743 return;
744 }
745
746 static int
crmfb_set_curpos(struct crmfb_softc * sc,int x,int y)747 crmfb_set_curpos(struct crmfb_softc *sc, int x, int y)
748 {
749 uint32_t val;
750
751 sc->sc_cur_x = x;
752 sc->sc_cur_y = y;
753
754 val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16);
755 crmfb_write_reg(sc, CRMFB_CURSOR_POS, val);
756
757 return 0;
758 }
759
760 static int
crmfb_gcursor(struct crmfb_softc * sc,struct wsdisplay_cursor * cur)761 crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur)
762 {
763 /* do nothing for now */
764 return 0;
765 }
766
767 static int
crmfb_scursor(struct crmfb_softc * sc,struct wsdisplay_cursor * cur)768 crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur)
769 {
770 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
771
772 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, cur->enable ? 1 : 0);
773 }
774 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
775
776 sc->sc_hot_x = cur->hot.x;
777 sc->sc_hot_y = cur->hot.y;
778 }
779 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
780
781 crmfb_set_curpos(sc, cur->pos.x, cur->pos.y);
782 }
783 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
784 int i;
785 uint32_t val;
786
787 for (i = 0; i < cur->cmap.count; i++) {
788 val = (cur->cmap.red[i] << 24) |
789 (cur->cmap.green[i] << 16) |
790 (cur->cmap.blue[i] << 8);
791 crmfb_write_reg(sc, CRMFB_CURSOR_CMAP0 +
792 ((i + cur->cmap.index) << 2), val);
793 }
794 }
795 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
796
797 int i, j, cnt = 0;
798 uint32_t latch = 0, omask;
799 uint8_t imask;
800 for (i = 0; i < 64; i++) {
801 omask = 0x80000000;
802 imask = 0x01;
803 cur->image[cnt] &= cur->mask[cnt];
804 for (j = 0; j < 8; j++) {
805 if (cur->image[cnt] & imask)
806 latch |= omask;
807 omask >>= 1;
808 if (cur->mask[cnt] & imask)
809 latch |= omask;
810 omask >>= 1;
811 imask <<= 1;
812 }
813 cnt++;
814 imask = 0x01;
815 cur->image[cnt] &= cur->mask[cnt];
816 for (j = 0; j < 8; j++) {
817 if (cur->image[cnt] & imask)
818 latch |= omask;
819 omask >>= 1;
820 if (cur->mask[cnt] & imask)
821 latch |= omask;
822 omask >>= 1;
823 imask <<= 1;
824 }
825 cnt++;
826 crmfb_write_reg(sc, CRMFB_CURSOR_BITMAP + (i << 2),
827 latch);
828 latch = 0;
829 }
830 }
831 return 0;
832 }
833
834 static inline void
crmfb_write_reg(struct crmfb_softc * sc,int offset,uint32_t val)835 crmfb_write_reg(struct crmfb_softc *sc, int offset, uint32_t val)
836 {
837
838 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
839 wbflush();
840 }
841
842 static inline uint32_t
crmfb_read_reg(struct crmfb_softc * sc,int offset)843 crmfb_read_reg(struct crmfb_softc *sc, int offset)
844 {
845
846 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
847 }
848
849 static inline void
crmfb_wait_idle(struct crmfb_softc * sc)850 crmfb_wait_idle(struct crmfb_softc *sc)
851 {
852 int i = 0;
853
854 do {
855 i++;
856 } while (((bus_space_read_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STATUS) &
857 CRIME_DE_IDLE) == 0) && (i < 100000000));
858 if (i >= 100000000)
859 aprint_error("crmfb_wait_idle() timed out\n");
860 sc->sc_needs_sync = 0;
861 }
862
863 /* writes to CRIME_DE_MODE_* only take effect when the engine is idle */
864
865 static inline void
crmfb_src_mode(struct crmfb_softc * sc,uint32_t mode)866 crmfb_src_mode(struct crmfb_softc *sc, uint32_t mode)
867 {
868 if (mode == sc->sc_src_mode)
869 return;
870 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_SRC, mode);
871 sc->sc_needs_sync = 1;
872 sc->sc_src_mode = mode;
873 }
874
875 static inline void
crmfb_dst_mode(struct crmfb_softc * sc,uint32_t mode)876 crmfb_dst_mode(struct crmfb_softc *sc, uint32_t mode)
877 {
878 if (mode == sc->sc_dst_mode)
879 return;
880 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_MODE_DST, mode);
881 sc->sc_needs_sync = 1;
882 sc->sc_dst_mode = mode;
883 }
884
885 static inline void
crmfb_make_room(struct crmfb_softc * sc,int num)886 crmfb_make_room(struct crmfb_softc *sc, int num)
887 {
888 int i = 0, slots;
889 uint32_t status;
890
891 if (sc->sc_needs_sync != 0) {
892 crmfb_wait_idle(sc);
893 return;
894 }
895
896 do {
897 i++;
898 status = bus_space_read_4(sc->sc_iot, sc->sc_reh,
899 CRIME_DE_STATUS);
900 slots = 60 - CRIME_PIPE_LEVEL(status);
901 } while (slots <= num);
902 }
903
904 static int
crmfb_wait_dma_idle(struct crmfb_softc * sc)905 crmfb_wait_dma_idle(struct crmfb_softc *sc)
906 {
907 int bail = 100000, idle;
908
909 do {
910 idle = ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
911 CRMFB_OVR_CONTROL) & 1) == 0) &&
912 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
913 CRMFB_FRM_CONTROL) & 1) == 0) &&
914 ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
915 CRMFB_DID_CONTROL) & 1) == 0);
916 if (!idle)
917 delay(10);
918 bail--;
919 } while ((!idle) && (bail > 0));
920 return idle;
921 }
922
923 static int
crmfb_setup_video(struct crmfb_softc * sc,int depth)924 crmfb_setup_video(struct crmfb_softc *sc, int depth)
925 {
926 uint64_t reg;
927 uint32_t d, h, page;
928 int i, bail, tile_width, tlbptr, lptr, j, tx, shift, overhang;
929 const char *wantsync;
930 uint16_t v;
931
932 /* disable DMA */
933 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL);
934 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT);
935 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d);
936 DELAY(50000);
937 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
938 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
939 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
940 DELAY(50000);
941 crmfb_write_reg(sc, CRMFB_DID_CONTROL, d);
942 DELAY(50000);
943
944 if (!crmfb_wait_dma_idle(sc))
945 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n");
946
947 /* ensure that CRM starts drawing at the top left of the screen
948 * when we re-enable DMA later
949 */
950 d = (1 << CRMFB_VT_XY_FREEZE_SHIFT);
951 crmfb_write_reg(sc, CRMFB_VT_XY, d);
952 delay(1000);
953 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
954 d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
955 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d);
956
957 /* wait for dotclock to turn off */
958 bail = 10000;
959 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK) &
960 (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT)) && (bail > 0)) {
961 delay(10);
962 bail--;
963 }
964
965 /* reset FIFO */
966 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE);
967 d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT);
968 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d);
969 d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT);
970 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d);
971
972 /* setup colour mode */
973 switch (depth) {
974 case 8:
975 h = CRMFB_MODE_TYP_RG3B2;
976 tile_width = 512;
977 break;
978 case 16:
979 h = CRMFB_MODE_TYP_ARGB5;
980 tile_width = 256;
981 break;
982 case 32:
983 h = CRMFB_MODE_TYP_RGB8;
984 tile_width = 128;
985 break;
986 default:
987 panic("Unsupported depth");
988 }
989 d = h << CRMFB_MODE_TYP_SHIFT;
990 d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT;
991 for (i = 0; i < (32 * 4); i += 4)
992 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d);
993 wbflush();
994
995 /* setup tile pointer, but don't turn on DMA yet! */
996 h = DMAADDR(sc->sc_dmai);
997 d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT;
998 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
999
1000 /* init framebuffer width and pixel size */
1001 /*d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT);*/
1002
1003 d = ((int)(sc->sc_width / tile_width)) <<
1004 CRMFB_FRM_TILESIZE_WIDTH_SHIFT;
1005 overhang = sc->sc_width % tile_width;
1006 if (overhang != 0) {
1007 uint32_t val;
1008 DPRINTF("tile width: %d\n", tile_width);
1009 DPRINTF("overhang: %d\n", overhang);
1010 val = (overhang * (depth >> 3)) >> 5;
1011 DPRINTF("reg: %08x\n", val);
1012 d |= (val & 0x1f);
1013 DPRINTF("d: %08x\n", d);
1014 }
1015
1016 switch (depth) {
1017 case 8:
1018 h = CRMFB_FRM_TILESIZE_DEPTH_8;
1019 break;
1020 case 16:
1021 h = CRMFB_FRM_TILESIZE_DEPTH_16;
1022 break;
1023 case 32:
1024 h = CRMFB_FRM_TILESIZE_DEPTH_32;
1025 break;
1026 default:
1027 panic("Unsupported depth");
1028 }
1029 d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT);
1030 crmfb_write_reg(sc, CRMFB_FRM_TILESIZE, d);
1031
1032 /*h = sc->sc_width * sc->sc_height / (512 / (depth >> 3));*/
1033 h = sc->sc_height;
1034 d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT;
1035 crmfb_write_reg(sc, CRMFB_FRM_PIXSIZE, d);
1036
1037 /* turn off firmware overlay and hardware cursor */
1038 crmfb_write_reg(sc, CRMFB_OVR_WIDTH_TILE, 0);
1039 crmfb_write_reg(sc, CRMFB_CURSOR_CONTROL, 0);
1040
1041 /* turn on DMA for the framebuffer */
1042 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
1043 d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
1044 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
1045
1046 /* enable drawing again */
1047 crmfb_write_reg(sc, CRMFB_VT_XY, 0);
1048 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
1049 d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
1050 crmfb_write_reg(sc, CRMFB_DOTCLOCK, d);
1051
1052 /* turn off sync-on-green */
1053
1054 wantsync = arcbios_GetEnvironmentVariable("SyncOnGreen");
1055 if ( (wantsync != NULL) && (wantsync[0] == 'n') ) {
1056 sc->sc_vtflags |= CRMFB_VT_FLAGS_SYNC_LOW;
1057 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d);
1058 }
1059
1060 sc->sc_depth = depth;
1061
1062 /* finally set up the drawing engine's TLB A */
1063 v = (DMAADDR(sc->sc_dma) >> 16) & 0xffff;
1064 tlbptr = 0;
1065 tx = ((sc->sc_width + (tile_width - 1)) & ~(tile_width - 1)) /
1066 tile_width;
1067
1068 DPRINTF("tx: %d\n", tx);
1069
1070 for (i = 0; i < 16; i++) {
1071 reg = 0;
1072 shift = 64;
1073 lptr = 0;
1074 for (j = 0; j < tx; j++) {
1075 shift -= 16;
1076 reg |= (((uint64_t)(v | 0x8000)) << shift);
1077 if (shift == 0) {
1078 shift = 64;
1079 bus_space_write_8(sc->sc_iot, sc->sc_reh,
1080 CRIME_RE_TLB_A + tlbptr + lptr,
1081 reg);
1082 DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg);
1083 reg = 0;
1084 lptr += 8;
1085 }
1086 v++;
1087 }
1088 if (shift != 64) {
1089 bus_space_write_8(sc->sc_iot, sc->sc_reh,
1090 CRIME_RE_TLB_A + tlbptr + lptr, reg);
1091 DPRINTF("%04x: %016"PRIx64"\n", tlbptr + lptr, reg);
1092 }
1093 tlbptr += 32;
1094 }
1095
1096 /* now put the last 128kB into the 1st linear TLB */
1097 page = (sc->sc_linear >> 12) | 0x80000000;
1098 tlbptr = 0;
1099 for (i = 0; i < 16; i++) {
1100 reg = ((uint64_t)page << 32) | (page + 1);
1101 bus_space_write_8(sc->sc_iot, sc->sc_reh,
1102 CRIME_RE_LINEAR_A + tlbptr, reg);
1103 page += 2;
1104 tlbptr += 8;
1105 }
1106 wbflush();
1107
1108 /* do some very basic engine setup */
1109 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_CLIPMODE, 0);
1110 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_SRC, 0);
1111 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_WINOFFSET_DST, 0);
1112 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PLANEMASK,
1113 0xffffffff);
1114
1115 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x20, 0);
1116 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x28, 0);
1117 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x30, 0);
1118 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x38, 0);
1119 bus_space_write_8(sc->sc_iot, sc->sc_reh, 0x40, 0);
1120
1121 switch (depth) {
1122 case 8:
1123 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_8 |
1124 DE_MODE_TYPE_CI | DE_MODE_PIXDEPTH_8;
1125 sc->sc_mte_mode = MTE_MODE_DST_ECC |
1126 (MTE_TLB_A << MTE_DST_TLB_SHIFT) |
1127 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) |
1128 (MTE_DEPTH_8 << MTE_DEPTH_SHIFT);
1129 sc->sc_mte_x_shift = 0;
1130 break;
1131 case 16:
1132 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_16 |
1133 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_16;
1134 sc->sc_mte_mode = MTE_MODE_DST_ECC |
1135 (MTE_TLB_A << MTE_DST_TLB_SHIFT) |
1136 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) |
1137 (MTE_DEPTH_16 << MTE_DEPTH_SHIFT);
1138 sc->sc_mte_x_shift = 1;
1139 break;
1140 case 32:
1141 sc->sc_de_mode = DE_MODE_TLB_A | DE_MODE_BUFDEPTH_32 |
1142 DE_MODE_TYPE_RGBA | DE_MODE_PIXDEPTH_32;
1143 sc->sc_mte_mode = MTE_MODE_DST_ECC |
1144 (MTE_TLB_A << MTE_DST_TLB_SHIFT) |
1145 (MTE_TLB_A << MTE_SRC_TLB_SHIFT) |
1146 (MTE_DEPTH_32 << MTE_DEPTH_SHIFT);
1147 sc->sc_mte_x_shift = 2;
1148 break;
1149 default:
1150 panic("%s: unsupported colour depth %d\n", __func__,
1151 depth);
1152 }
1153 sc->sc_needs_sync = 0;
1154 sc->sc_src_mode = 0xffffffff;
1155 sc->sc_dst_mode = 0xffffffff;
1156
1157 crmfb_src_mode(sc, sc->sc_de_mode);
1158 crmfb_dst_mode(sc, sc->sc_de_mode);
1159
1160 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_X, 1);
1161 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STEP_Y, 1);
1162
1163 /* initialize memory transfer engine */
1164 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
1165 sc->sc_mte_mode | MTE_MODE_COPY);
1166 sc->sc_mte_direction = 1;
1167 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, 1);
1168 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, 1);
1169
1170 return 0;
1171 }
1172
1173 static void
crmfb_set_mte_direction(struct crmfb_softc * sc,int dir)1174 crmfb_set_mte_direction(struct crmfb_softc *sc, int dir)
1175 {
1176 if (dir == sc->sc_mte_direction)
1177 return;
1178
1179 crmfb_make_room(sc, 2);
1180 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST_Y_STEP, dir);
1181 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC_Y_STEP, dir);
1182 sc->sc_mte_direction = dir;
1183 }
1184
1185 static void
crmfb_setup_palette(struct crmfb_softc * sc)1186 crmfb_setup_palette(struct crmfb_softc *sc)
1187 {
1188 int i, j, x;
1189 uint32_t col;
1190 struct rasops_info *ri = &crmfb_console_screen.scr_ri;
1191
1192 for (i = 0; i < 256; i++) {
1193 crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2],
1194 rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]);
1195 sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2];
1196 sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1];
1197 sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0];
1198 }
1199
1200 if (FONT_IS_ALPHA(ri->ri_font)) {
1201 sc->sc_de_mode =
1202 (sc->sc_de_mode & ~DE_MODE_TYPE_MASK) | DE_MODE_TYPE_RGB;
1203 }
1204
1205 /* draw 16 character cells in 32bit RGBA for alpha blending */
1206 crmfb_make_room(sc, 3);
1207 crmfb_dst_mode(sc,
1208 DE_MODE_TLB_A |
1209 DE_MODE_BUFDEPTH_32 |
1210 DE_MODE_TYPE_RGBA |
1211 DE_MODE_PIXDEPTH_32);
1212 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1213 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK);
1214 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1215 DE_PRIM_RECTANGLE | DE_PRIM_TB);
1216 j = 0;
1217 x = 0;
1218 for (i = 0; i < 16; i++) {
1219 crmfb_make_room(sc, 2);
1220 col = (rasops_cmap[j] << 24) |
1221 (rasops_cmap[j + 1] << 16) |
1222 (rasops_cmap[j + 2] << 8);
1223 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, col);
1224 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1225 (x << 16) | ((sc->sc_height - 500) & 0xffff));
1226 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1227 CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1228 ((x + ri->ri_font->fontwidth - 1) << 16) |
1229 ((sc->sc_height + ri->ri_font->fontheight - 1) & 0xffff));
1230 j += 3;
1231 x += ri->ri_font->fontwidth;
1232 }
1233 crmfb_dst_mode(sc, sc->sc_de_mode);
1234 }
1235
1236 static void
crmfb_fill_rect(struct crmfb_softc * sc,int x,int y,int width,int height,uint32_t colour)1237 crmfb_fill_rect(struct crmfb_softc *sc, int x, int y, int width, int height,
1238 uint32_t colour)
1239 {
1240 int rxa, rxe;
1241
1242 rxa = x << sc->sc_mte_x_shift;
1243 rxe = ((x + width) << sc->sc_mte_x_shift) - 1;
1244 crmfb_set_mte_direction(sc, 1);
1245 crmfb_make_room(sc, 4);
1246 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
1247 sc->sc_mte_mode | 0);
1248 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_BG, colour);
1249 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST0,
1250 (rxa << 16) | (y & 0xffff));
1251 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1252 CRIME_MTE_DST1 | CRIME_DE_START,
1253 (rxe << 16) | ((y + height - 1) & 0xffff));
1254 }
1255
1256 static void
crmfb_bitblt(struct crmfb_softc * sc,int xs,int ys,int xd,int yd,int wi,int he,uint32_t rop)1257 crmfb_bitblt(struct crmfb_softc *sc, int xs, int ys, int xd, int yd,
1258 int wi, int he, uint32_t rop)
1259 {
1260 uint32_t prim = DE_PRIM_RECTANGLE;
1261 int rxa, rya, rxe, rye, rxs, rys;
1262 crmfb_make_room(sc, 2);
1263 crmfb_src_mode(sc, sc->sc_de_mode);
1264 crmfb_make_room(sc, 6);
1265 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1266 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK | DE_DRAWMODE_ROP |
1267 DE_DRAWMODE_XFER_EN);
1268 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, rop);
1269 if (xs < xd) {
1270 prim |= DE_PRIM_RL;
1271 rxe = xd;
1272 rxa = xd + wi - 1;
1273 rxs = xs + wi - 1;
1274 } else {
1275 prim |= DE_PRIM_LR;
1276 rxe = xd + wi - 1;
1277 rxa = xd;
1278 rxs = xs;
1279 }
1280 if (ys < yd) {
1281 prim |= DE_PRIM_BT;
1282 rye = yd;
1283 rya = yd + he - 1;
1284 rys = ys + he - 1;
1285 } else {
1286 prim |= DE_PRIM_TB;
1287 rye = yd + he - 1;
1288 rya = yd;
1289 rys = ys;
1290 }
1291 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE, prim);
1292 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC,
1293 (rxs << 16) | (rys & 0xffff));
1294 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1295 (rxa << 16) | (rya & 0xffff));
1296 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1297 CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1298 (rxe << 16) | (rye & 0xffff));
1299 }
1300
1301 static void
crmfb_scroll(struct crmfb_softc * sc,int xs,int ys,int xd,int yd,int wi,int he)1302 crmfb_scroll(struct crmfb_softc *sc, int xs, int ys, int xd, int yd,
1303 int wi, int he)
1304 {
1305 int rxa, rya, rxe, rye, rxd, ryd, rxde, ryde;
1306
1307 rxa = xs << sc->sc_mte_x_shift;
1308 rxd = xd << sc->sc_mte_x_shift;
1309 rxe = ((xs + wi) << sc->sc_mte_x_shift) - 1;
1310 rxde = ((xd + wi) << sc->sc_mte_x_shift) - 1;
1311
1312 crmfb_make_room(sc, 1);
1313
1314 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_MODE,
1315 sc->sc_mte_mode | MTE_MODE_COPY);
1316
1317 if (ys < yd) {
1318 /* bottom to top */
1319 rye = ys;
1320 rya = ys + he - 1;
1321 ryd = yd + he - 1;
1322 ryde = yd;
1323 crmfb_set_mte_direction(sc, -1);
1324 } else {
1325 /* top to bottom */
1326 rye = ys + he - 1;
1327 rya = ys;
1328 ryd = yd;
1329 ryde = yd + he - 1;
1330 crmfb_set_mte_direction(sc, 1);
1331 }
1332 crmfb_make_room(sc, 4);
1333 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC0,
1334 (rxa << 16) | rya);
1335 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_SRC1,
1336 (rxe << 16) | rye);
1337 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1338 CRIME_MTE_DST0,
1339 (rxd << 16) | ryd);
1340 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_MTE_DST1 |
1341 CRIME_DE_START,
1342 (rxde << 16) | ryde);
1343 }
1344
1345 static void
crmfb_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)1346 crmfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1347 {
1348 struct rasops_info *ri = cookie;
1349 struct vcons_screen *scr = ri->ri_hw;
1350 int32_t xs, xd, y, width, height;
1351
1352 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1353 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1354 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1355 width = ri->ri_font->fontwidth * ncols;
1356 height = ri->ri_font->fontheight;
1357 crmfb_bitblt(scr->scr_cookie, xs, y, xd, y, width, height, 3);
1358 }
1359
1360 static void
crmfb_erasecols(void * cookie,int row,int startcol,int ncols,long fillattr)1361 crmfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1362 {
1363 struct rasops_info *ri = cookie;
1364 struct vcons_screen *scr = ri->ri_hw;
1365 int32_t x, y, width, height, bg;
1366
1367 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1368 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1369 width = ri->ri_font->fontwidth * ncols;
1370 height = ri->ri_font->fontheight;
1371 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
1372 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg);
1373 }
1374
1375 static void
crmfb_copyrows(void * cookie,int srcrow,int dstrow,int nrows)1376 crmfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1377 {
1378 struct rasops_info *ri = cookie;
1379 struct vcons_screen *scr = ri->ri_hw;
1380 int32_t x, ys, yd, width, height;
1381
1382 x = ri->ri_xorigin;
1383 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1384 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1385 width = ri->ri_emuwidth;
1386 height = ri->ri_font->fontheight * nrows;
1387
1388 crmfb_scroll(scr->scr_cookie, x, ys, x, yd, width, height);
1389 }
1390
1391 static void
crmfb_eraserows(void * cookie,int row,int nrows,long fillattr)1392 crmfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1393 {
1394 struct rasops_info *ri = cookie;
1395 struct vcons_screen *scr = ri->ri_hw;
1396 int32_t x, y, width, height, bg;
1397
1398 if ((row == 0) && (nrows == ri->ri_rows)) {
1399 x = y = 0;
1400 width = ri->ri_width;
1401 height = ri->ri_height;
1402 } else {
1403 x = ri->ri_xorigin;
1404 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1405 width = ri->ri_emuwidth;
1406 height = ri->ri_font->fontheight * nrows;
1407 }
1408 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
1409 crmfb_fill_rect(scr->scr_cookie, x, y, width, height, bg);
1410 }
1411
1412 static void
crmfb_cursor(void * cookie,int on,int row,int col)1413 crmfb_cursor(void *cookie, int on, int row, int col)
1414 {
1415 struct rasops_info *ri = cookie;
1416 struct vcons_screen *scr = ri->ri_hw;
1417 struct crmfb_softc *sc = scr->scr_cookie;
1418 int x, y, wi,he;
1419
1420 wi = ri->ri_font->fontwidth;
1421 he = ri->ri_font->fontheight;
1422
1423 if (ri->ri_flg & RI_CURSOR) {
1424 x = ri->ri_ccol * wi + ri->ri_xorigin;
1425 y = ri->ri_crow * he + ri->ri_yorigin;
1426 crmfb_bitblt(sc, x, y, x, y, wi, he, 12);
1427 ri->ri_flg &= ~RI_CURSOR;
1428 }
1429
1430 ri->ri_crow = row;
1431 ri->ri_ccol = col;
1432
1433 if (on)
1434 {
1435 x = ri->ri_ccol * wi + ri->ri_xorigin;
1436 y = ri->ri_crow * he + ri->ri_yorigin;
1437 crmfb_bitblt(sc, x, y, x, y, wi, he, 12);
1438 ri->ri_flg |= RI_CURSOR;
1439 }
1440 }
1441
1442 static void
crmfb_putchar(void * cookie,int row,int col,u_int c,long attr)1443 crmfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1444 {
1445 struct rasops_info *ri = cookie;
1446 struct vcons_screen *scr = ri->ri_hw;
1447 struct crmfb_softc *sc = scr->scr_cookie;
1448 struct wsdisplay_font *font = PICK_FONT(ri, c);
1449 uint32_t bg, fg;
1450 int x, y, wi, he, i, uc;
1451 uint8_t *fd8;
1452 uint16_t *fd16;
1453 void *fd;
1454
1455 wi = font->fontwidth;
1456 he = font->fontheight;
1457
1458 x = ri->ri_xorigin + col * wi;
1459 y = ri->ri_yorigin + row * he;
1460
1461 bg = ri->ri_devcmap[(attr >> 16) & 0xff];
1462 fg = ri->ri_devcmap[(attr >> 24) & 0xff];
1463 uc = c - font->firstchar;
1464 fd = (uint8_t *)font->data + uc * ri->ri_fontscale;
1465 if (c == 0x20) {
1466 crmfb_fill_rect(sc, x, y, wi, he, bg);
1467 } else {
1468 crmfb_make_room(sc, 6);
1469 /* setup */
1470 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1471 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK |
1472 DE_DRAWMODE_ROP |
1473 DE_DRAWMODE_OPAQUE_STIP | DE_DRAWMODE_POLY_STIP);
1474 wbflush();
1475 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ROP, 3);
1476 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_FG, fg);
1477 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_BG, bg);
1478 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1479 DE_PRIM_RECTANGLE | DE_PRIM_LR | DE_PRIM_TB);
1480 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_STIPPLE_MODE,
1481 0x001f0000);
1482 /* now let's feed the engine */
1483 crmfb_make_room(sc, 30);
1484 if (font->stride == 1) {
1485 /* shovel in 8 bit quantities */
1486 fd8 = fd;
1487 for (i = 0; i < he; i++) {
1488 if (i & 8)
1489 crmfb_make_room(sc, 30);
1490 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1491 CRIME_DE_STIPPLE_PAT, *fd8 << 24);
1492 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1493 CRIME_DE_X_VERTEX_0, (x << 16) | y);
1494 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1495 CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1496 ((x + wi) << 16) | y);
1497 y++;
1498 fd8++;
1499 }
1500 } else if (font->stride == 2) {
1501 /* shovel in 16 bit quantities */
1502 fd16 = fd;
1503 for (i = 0; i < he; i++) {
1504 if (i & 8)
1505 crmfb_make_room(sc, 30);
1506 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1507 CRIME_DE_STIPPLE_PAT, *fd16 << 16);
1508 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1509 CRIME_DE_X_VERTEX_0, (x << 16) | y);
1510 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1511 CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1512 ((x + wi) << 16) | y);
1513 y++;
1514 fd16++;
1515 }
1516 }
1517 }
1518 }
1519
1520 static void
crmfb_putchar_aa(void * cookie,int row,int col,u_int c,long attr)1521 crmfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
1522 {
1523 struct rasops_info *ri = cookie;
1524 struct vcons_screen *scr = ri->ri_hw;
1525 struct crmfb_softc *sc = scr->scr_cookie;
1526 struct wsdisplay_font *font = PICK_FONT(ri, c);
1527 uint32_t bg, fg;
1528 int x, y, wi, he, uc, xx;
1529 void *fd;
1530
1531 wi = font->fontwidth;
1532 he = font->fontheight;
1533
1534 x = ri->ri_xorigin + col * wi;
1535 y = ri->ri_yorigin + row * he;
1536
1537 bg = ri->ri_devcmap[(attr >> 16) & 0xff];
1538 fg = (attr >> 24);
1539 uc = c - font->firstchar;
1540 fd = (uint8_t *)font->data + uc * ri->ri_fontscale;
1541
1542 /* fill the cell with the background colour */
1543 crmfb_fill_rect(sc, x, y, wi, he, bg);
1544
1545 /* if all we draw is a space we're done */
1546 if (c == 0x20)
1547 return;
1548
1549 /* copy the glyph into the linear buffer */
1550 memcpy(sc->sc_lptr, fd, ri->ri_fontscale);
1551 wbflush();
1552
1553 /* now blit it on top of the requested fg colour cell */
1554 xx = fg * wi;
1555 crmfb_make_room(sc, 2);
1556 crmfb_src_mode(sc,
1557 DE_MODE_LIN_A |
1558 DE_MODE_BUFDEPTH_8 |
1559 DE_MODE_TYPE_CI |
1560 DE_MODE_PIXDEPTH_8);
1561 crmfb_dst_mode(sc,
1562 DE_MODE_TLB_A |
1563 DE_MODE_BUFDEPTH_32 |
1564 DE_MODE_TYPE_CI |
1565 DE_MODE_PIXDEPTH_8);
1566
1567 crmfb_make_room(sc, 6);
1568 /* only write into the alpha channel */
1569 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1570 DE_DRAWMODE_PLANEMASK | 0x08 |
1571 DE_DRAWMODE_XFER_EN);
1572 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1573 DE_PRIM_RECTANGLE | DE_PRIM_TB);
1574 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_STRD_SRC, 1);
1575 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC, 0);
1576 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1577 (xx << 16) | (sc->sc_height & 0xffff));
1578 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1579 CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1580 ((xx + wi - 1) << 16) | ((sc->sc_height + he - 1) & 0xffff));
1581
1582 /* now draw the actual character */
1583 crmfb_make_room(sc, 2);
1584 crmfb_src_mode(sc,
1585 DE_MODE_TLB_A |
1586 DE_MODE_BUFDEPTH_32 |
1587 DE_MODE_TYPE_RGBA |
1588 DE_MODE_PIXDEPTH_32);
1589 crmfb_dst_mode(sc, sc->sc_de_mode);
1590
1591 crmfb_make_room(sc, 6);
1592 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_DRAWMODE,
1593 DE_DRAWMODE_PLANEMASK | DE_DRAWMODE_BYTEMASK |
1594 DE_DRAWMODE_ALPHA_BLEND |
1595 DE_DRAWMODE_XFER_EN);
1596 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_ALPHA_FUNC,
1597 DE_ALPHA_ADD |
1598 (DE_ALPHA_OP_SRC_ALPHA << DE_ALPHA_OP_SRC_SHIFT) |
1599 (DE_ALPHA_OP_1_MINUS_SRC_ALPHA << DE_ALPHA_OP_DST_SHIFT));
1600 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_PRIMITIVE,
1601 DE_PRIM_RECTANGLE | DE_PRIM_TB);
1602 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_XFER_ADDR_SRC,
1603 (xx << 16) | (sc->sc_height & 0xffff));
1604 bus_space_write_4(sc->sc_iot, sc->sc_reh, CRIME_DE_X_VERTEX_0,
1605 (x << 16) | (y & 0xffff));
1606 bus_space_write_4(sc->sc_iot, sc->sc_reh,
1607 CRIME_DE_X_VERTEX_1 | CRIME_DE_START,
1608 ((x + wi - 1) << 16) | ((y + he - 1) & 0xffff));
1609 }
1610
1611 static void
crmfb_setup_ddc(struct crmfb_softc * sc)1612 crmfb_setup_ddc(struct crmfb_softc *sc)
1613 {
1614 int i;
1615
1616 memset(sc->sc_edid_data, 0, 128);
1617 iic_tag_init(&sc->sc_i2c);
1618 sc->sc_i2c.ic_cookie = sc;
1619 sc->sc_i2c.ic_send_start = crmfb_i2c_send_start;
1620 sc->sc_i2c.ic_send_stop = crmfb_i2c_send_stop;
1621 sc->sc_i2c.ic_initiate_xfer = crmfb_i2c_initiate_xfer;
1622 sc->sc_i2c.ic_read_byte = crmfb_i2c_read_byte;
1623 sc->sc_i2c.ic_write_byte = crmfb_i2c_write_byte;
1624 i = 0;
1625 while (sc->sc_edid_data[1] == 0 && i++ < 10)
1626 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128);
1627 if (i > 1)
1628 aprint_debug_dev(sc->sc_dev,
1629 "had to try %d times to get EDID data\n", i);
1630 if (i < 11) {
1631 edid_parse(sc->sc_edid_data, &sc->sc_edid_info);
1632 edid_print(&sc->sc_edid_info);
1633 }
1634 }
1635
1636 /* I2C bitbanging */
1637 static void
crmfb_i2cbb_set_bits(void * cookie,uint32_t bits)1638 crmfb_i2cbb_set_bits(void *cookie, uint32_t bits)
1639 {
1640 struct crmfb_softc *sc = cookie;
1641
1642 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA, bits ^ 3);
1643 }
1644
1645 static void
crmfb_i2cbb_set_dir(void * cookie,uint32_t dir)1646 crmfb_i2cbb_set_dir(void *cookie, uint32_t dir)
1647 {
1648
1649 /* Nothing to do */
1650 }
1651
1652 static uint32_t
crmfb_i2cbb_read(void * cookie)1653 crmfb_i2cbb_read(void *cookie)
1654 {
1655 struct crmfb_softc *sc = cookie;
1656
1657 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_I2C_VGA) ^ 3;
1658 }
1659
1660 static int
crmfb_i2c_send_start(void * cookie,int flags)1661 crmfb_i2c_send_start(void *cookie, int flags)
1662 {
1663
1664 return i2c_bitbang_send_start(cookie, flags, &crmfb_i2cbb_ops);
1665 }
1666
1667 static int
crmfb_i2c_send_stop(void * cookie,int flags)1668 crmfb_i2c_send_stop(void *cookie, int flags)
1669 {
1670
1671 return i2c_bitbang_send_stop(cookie, flags, &crmfb_i2cbb_ops);
1672 }
1673
1674 static int
crmfb_i2c_initiate_xfer(void * cookie,i2c_addr_t addr,int flags)1675 crmfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
1676 {
1677
1678 return i2c_bitbang_initiate_xfer(cookie, addr, flags,
1679 &crmfb_i2cbb_ops);
1680 }
1681
1682 static int
crmfb_i2c_read_byte(void * cookie,uint8_t * valp,int flags)1683 crmfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
1684 {
1685
1686 return i2c_bitbang_read_byte(cookie, valp, flags, &crmfb_i2cbb_ops);
1687 }
1688
1689 static int
crmfb_i2c_write_byte(void * cookie,uint8_t val,int flags)1690 crmfb_i2c_write_byte(void *cookie, uint8_t val, int flags)
1691 {
1692
1693 return i2c_bitbang_write_byte(cookie, val, flags, &crmfb_i2cbb_ops);
1694 }
1695
1696 /* mode setting stuff */
1697 static uint32_t
calc_pll(int f_out)1698 calc_pll(int f_out)
1699 {
1700 uint32_t ret;
1701 int f_in = 20000; /* 20MHz in */
1702 int M, N, P;
1703 int error, div, best = 9999999;
1704 int ff1, ff2;
1705 int MM = 0, NN = 0, PP = 0, ff = 0;
1706
1707 /* f_out = M * f_in / (N * (1 << P) */
1708
1709 for (P = 0; P < 4; P++) {
1710 for (N = 64; N > 0; N--) {
1711 div = N * (1 << P);
1712 M = f_out * div / f_in;
1713 if ((M < 257) && (M > 100)) {
1714 ff1 = M * f_in / div;
1715 ff2 = (M + 1) * f_in / div;
1716 error = abs(ff1 - f_out);
1717 if (error < best) {
1718 MM = M;
1719 NN = N;
1720 PP = P;
1721 ff = ff1;
1722 best = error;
1723 }
1724 error = abs(ff2 - f_out);
1725 if ((error < best) && ( M < 256)){
1726 MM = M + 1;
1727 NN = N;
1728 PP = P;
1729 ff = ff2;
1730 best = error;
1731 }
1732 }
1733 }
1734 }
1735 DPRINTF("%d: M %d N %d P %d -> %d\n", f_out, MM, NN, PP, ff);
1736 /* now shove the parameters into the register's format */
1737 ret = (MM - 1) | ((NN - 1) << 8) | (P << 14);
1738 return ret;
1739 }
1740
1741 static int
crmfb_set_mode(struct crmfb_softc * sc,const struct videomode * mode)1742 crmfb_set_mode(struct crmfb_softc *sc, const struct videomode *mode)
1743 {
1744 uint32_t d, dc;
1745 int tmp, diff;
1746
1747 switch (mode->hdisplay % 32) {
1748 case 0:
1749 sc->sc_console_depth = 8;
1750 break;
1751 case 16:
1752 sc->sc_console_depth = 16;
1753 break;
1754 case 8:
1755 case 24:
1756 sc->sc_console_depth = 32;
1757 break;
1758 default:
1759 aprint_error_dev(sc->sc_dev,
1760 "hdisplay (%d) is not a multiple of 32\n",
1761 mode->hdisplay);
1762 return FALSE;
1763 }
1764 if (mode->dot_clock > 150000) {
1765 aprint_error_dev(sc->sc_dev,
1766 "requested dot clock is too high ( %d MHz )\n",
1767 mode->dot_clock / 1000);
1768 return FALSE;
1769 }
1770
1771 /* disable DMA */
1772 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL);
1773 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT);
1774 crmfb_write_reg(sc, CRMFB_OVR_CONTROL, d);
1775 DELAY(50000);
1776 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
1777 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
1778 crmfb_write_reg(sc, CRMFB_FRM_CONTROL, d);
1779 DELAY(50000);
1780 crmfb_write_reg(sc, CRMFB_DID_CONTROL, d);
1781 DELAY(50000);
1782
1783 if (!crmfb_wait_dma_idle(sc))
1784 aprint_error("crmfb: crmfb_wait_dma_idle timed out\n");
1785
1786 /* ok, now we're good to go */
1787 dc = calc_pll(mode->dot_clock);
1788
1789 crmfb_write_reg(sc, CRMFB_VT_XY, 1 << CRMFB_VT_XY_FREEZE_SHIFT);
1790 delay(1000);
1791
1792 /* set the dot clock pll but don't start it yet */
1793 crmfb_write_reg(sc, CRMFB_DOTCLOCK, dc);
1794 delay(10000);
1795
1796 /* pixel counter */
1797 d = mode->htotal | (mode->vtotal << 12);
1798 crmfb_write_reg(sc, CRMFB_VT_XYMAX, d);
1799
1800 /* video timings */
1801 d = mode->vsync_end | (mode->vsync_start << 12);
1802 crmfb_write_reg(sc, CRMFB_VT_VSYNC, d);
1803
1804 d = mode->hsync_end | (mode->hsync_start << 12);
1805 crmfb_write_reg(sc, CRMFB_VT_HSYNC, d);
1806
1807 d = mode->vtotal | (mode->vdisplay << 12);
1808 crmfb_write_reg(sc, CRMFB_VT_VBLANK, d);
1809
1810 d = (mode->htotal - 5) | ((mode->hdisplay - 5) << 12);
1811 crmfb_write_reg(sc, CRMFB_VT_HBLANK, d);
1812
1813 d = mode->vtotal | (mode->vdisplay << 12);
1814 crmfb_write_reg(sc, CRMFB_VT_VCMAP, d);
1815 d = mode->htotal | (mode->hdisplay << 12);
1816 crmfb_write_reg(sc, CRMFB_VT_HCMAP, d);
1817
1818 d = 0;
1819 if (mode->flags & VID_NHSYNC) d |= CRMFB_VT_FLAGS_HDRV_INVERT;
1820 if (mode->flags & VID_NVSYNC) d |= CRMFB_VT_FLAGS_VDRV_INVERT;
1821 crmfb_write_reg(sc, CRMFB_VT_FLAGS, d);
1822 sc->sc_vtflags = d;
1823
1824 diff = -abs(mode->vtotal - mode->vdisplay - 1);
1825 d = ((uint32_t)diff << 12) & 0x00fff000;
1826 d |= (mode->htotal - 20);
1827 crmfb_write_reg(sc, CRMFB_VT_DID_STARTXY, d);
1828
1829 d = ((uint32_t)(diff + 1) << 12) & 0x00fff000;
1830 d |= (mode->htotal - 54);
1831 crmfb_write_reg(sc, CRMFB_VT_CRS_STARTXY, d);
1832
1833 d = ((uint32_t)diff << 12) & 0x00fff000;
1834 d |= (mode->htotal - 4);
1835 crmfb_write_reg(sc, CRMFB_VT_VC_STARTXY, d);
1836
1837 tmp = mode->htotal - 19;
1838 d = tmp << 12;
1839 d |= ((tmp + mode->hdisplay - 2) % mode->htotal);
1840 crmfb_write_reg(sc, CRMFB_VT_HPIX_EN, d);
1841
1842 d = mode->vdisplay | (mode->vtotal << 12);
1843 crmfb_write_reg(sc, CRMFB_VT_VPIX_EN, d);
1844
1845 sc->sc_width = mode->hdisplay;
1846 sc->sc_height = mode->vdisplay;
1847
1848 return TRUE;
1849 }
1850
1851 /*
1852 * Parse a mode string in the form WIDTHxHEIGHT[@REFRESH] and return
1853 * monitor timings generated using the VESA GTF formula.
1854 */
1855 static int
crmfb_parse_mode(const char * modestr,struct videomode * mode)1856 crmfb_parse_mode(const char *modestr, struct videomode *mode)
1857 {
1858 char *x, *at;
1859 int width, height, refresh;
1860
1861 if (modestr == NULL)
1862 return EINVAL;
1863
1864 x = strchr(modestr, 'x');
1865 at = strchr(modestr, '@');
1866
1867 if (x == NULL || (at != NULL && at < x))
1868 return EINVAL;
1869
1870 width = strtoul(modestr, NULL, 10);
1871 height = strtoul(x + 1, NULL, 10);
1872 refresh = at ? strtoul(at + 1, NULL, 10) : 60;
1873
1874 if (width == 0 || height == 0 || refresh == 0)
1875 return EINVAL;
1876
1877 vesagtf_mode(width, height, refresh, mode);
1878
1879 return 0;
1880 }
1881