sti.c revision 1.35 1 /* $NetBSD: sti.c,v 1.35 2024/02/13 13:17:51 macallan Exp $ */
2
3 /* $OpenBSD: sti.c,v 1.61 2009/09/05 14:09:35 miod Exp $ */
4
5 /*
6 * Copyright (c) 2000-2003 Michael Shalayeff
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 /*
31 * TODO:
32 * call sti procs asynchronously;
33 * implement console scroll-back;
34 * X11 support on more models.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: sti.c,v 1.35 2024/02/13 13:17:51 macallan Exp $");
39
40 #include "wsdisplay.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46
47 #include <uvm/uvm_extern.h>
48
49 #include <sys/bus.h>
50
51 #include <dev/wscons/wsdisplayvar.h>
52 #include <dev/wscons/wsconsio.h>
53
54 #include <dev/ic/stireg.h>
55 #include <dev/ic/stivar.h>
56
57 #ifdef STIDEBUG
58
59 #define DPRINTF(s) do { \
60 if (stidebug) \
61 printf s; \
62 } while(0)
63
64 int stidebug = 1;
65 #else
66 #define DPRINTF(s) /* */
67 #endif
68
69 void sti_cursor(void *, int, int, int);
70 int sti_mapchar(void *, int, u_int *);
71 void sti_putchar(void *, int, int, u_int, long);
72 void sti_copycols(void *, int, int, int, int);
73 void sti_erasecols(void *, int, int, int, long);
74 void sti_copyrows(void *, int, int, int);
75 void sti_eraserows(void *, int, int, long);
76 int sti_alloc_attr(void *, int, int, int, long *);
77
78 /* pseudo attribute ops for sti ROM putchar function */
79 #define WSATTR_FG_SHIFT 24
80 #define WSATTR_BG_SHIFT 16
81 #define WSATTR_UNPACK_FG(attr) (((attr) >> WSATTR_FG_SHIFT) & 0xff)
82 #define WSATTR_UNPACK_BG(attr) (((attr) >> WSATTR_BG_SHIFT) & 0xff)
83 #define WSATTR_UNPACK_FLAG(attr) ((attr) & WSATTR_USERMASK)
84 #define WSATTR_PACK_FG(fg) ((fg) << WSATTR_FG_SHIFT)
85 #define WSATTR_PACK_BG(bg) ((bg) << WSATTR_BG_SHIFT)
86 #define WSATTR_PACK_FLAG(flag) ((flag))
87 #define WSATTR_PACK(fg, bg, flag) \
88 (WSATTR_PACK_FG(fg) | WSATTR_PACK_BG(bg) | WSATTR_PACK_FLAG(flag))
89
90 struct wsdisplay_emulops sti_emulops = {
91 .cursor = sti_cursor,
92 .mapchar = sti_mapchar,
93 .putchar = sti_putchar,
94 .copycols = sti_copycols,
95 .erasecols = sti_erasecols,
96 .copyrows = sti_copyrows,
97 .eraserows = sti_eraserows,
98 .allocattr = sti_alloc_attr
99 };
100
101 const struct wsdisplay_accessops sti_accessops = {
102 .ioctl = sti_ioctl,
103 .mmap = sti_mmap,
104 .alloc_screen = sti_alloc_screen,
105 .free_screen = sti_free_screen,
106 .show_screen = sti_show_screen,
107 .load_font = sti_load_font
108 };
109
110 enum sti_bmove_funcs {
111 bmf_clear, bmf_copy, bmf_invert, bmf_underline
112 };
113
114 void sti_bmove(struct sti_screen *, int, int, int, int, int, int,
115 enum sti_bmove_funcs);
116 int sti_inqcfg(struct sti_screen *, struct sti_inqconfout *);
117 int sti_setcment(struct sti_screen *, u_int, u_char, u_char, u_char);
118
119 struct sti_screen *sti_attach_screen(struct sti_softc *, int);
120 void sti_describe_screen(struct sti_softc *, struct sti_screen *);
121
122 int sti_fetchfonts(struct sti_screen *, struct sti_inqconfout *, uint32_t,
123 u_int);
124 void sti_region_setup(struct sti_screen *);
125 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
126 bus_space_handle_t, bus_addr_t *, u_int);
127 int sti_screen_setup(struct sti_screen *, int);
128
129 int ngle_default_putcmap(struct sti_screen *, u_int, u_int);
130
131 #ifndef SMALL_KERNEL
132 void ngle_artist_setupfb(struct sti_screen *);
133 void ngle_elk_setupfb(struct sti_screen *);
134 void ngle_timber_setupfb(struct sti_screen *);
135 int ngle_putcmap(struct sti_screen *, u_int, u_int);
136 #endif
137
138 #define STI_ENABLE_ROM(sc) \
139 do { \
140 if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \
141 (*(sc)->sc_enable_rom)(sc); \
142 } while (0)
143 #define STI_DISABLE_ROM(sc) \
144 do { \
145 if ((sc) != NULL && (sc)->sc_disable_rom != NULL) \
146 (*(sc)->sc_disable_rom)(sc); \
147 } while (0)
148
149 /* Macros to read larger than 8 bit values from byte roms */
150 #define parseshort(o) \
151 ((bus_space_read_1(memt, romh, (o) + 3) << 8) | \
152 (bus_space_read_1(memt, romh, (o) + 7)))
153 #define parseword(o) \
154 ((bus_space_read_1(memt, romh, (o) + 3) << 24) | \
155 (bus_space_read_1(memt, romh, (o) + 7) << 16) | \
156 (bus_space_read_1(memt, romh, (o) + 11) << 8) | \
157 (bus_space_read_1(memt, romh, (o) + 15)))
158
159 int
160 sti_attach_common(struct sti_softc *sc, bus_space_tag_t iot,
161 bus_space_tag_t memt, bus_space_handle_t romh, u_int codebase)
162 {
163 struct sti_rom *rom;
164 int rc;
165
166 rom = (struct sti_rom *)malloc(sizeof(*rom), M_DEVBUF,
167 M_WAITOK | M_ZERO);
168 rom->rom_softc = sc;
169 rc = sti_rom_setup(rom, iot, memt, romh, sc->bases, codebase);
170 if (rc != 0) {
171 free(rom, M_DEVBUF);
172 return rc;
173 }
174
175 sc->sc_rom = rom;
176
177 sti_describe(sc);
178
179 sc->sc_scr = sti_attach_screen(sc,
180 sc->sc_flags & STI_CONSOLE ? 0 : STI_CLEARSCR);
181 if (sc->sc_scr == NULL)
182 rc = ENOMEM;
183
184 return rc;
185 }
186
187 struct sti_screen *
188 sti_attach_screen(struct sti_softc *sc, int flags)
189 {
190 struct sti_screen *scr;
191 int rc;
192
193 scr = (struct sti_screen *)malloc(sizeof(*scr), M_DEVBUF,
194 M_WAITOK | M_ZERO);
195 scr->scr_rom = sc->sc_rom;
196 rc = sti_screen_setup(scr, flags);
197 if (rc != 0) {
198 free(scr, M_DEVBUF);
199 return NULL;
200 }
201
202 sti_describe_screen(sc, scr);
203
204 return scr;
205 }
206
207 int
208 sti_rom_setup(struct sti_rom *rom, bus_space_tag_t iot, bus_space_tag_t memt,
209 bus_space_handle_t romh, bus_addr_t *bases, u_int codebase)
210 {
211 struct sti_dd *dd;
212 int error, size, i;
213
214 KASSERT(rom != NULL);
215 STI_ENABLE_ROM(rom->rom_softc);
216
217 rom->iot = iot;
218 rom->memt = memt;
219 rom->romh = romh;
220 rom->bases = bases;
221
222 /*
223 * Get ROM header and code function pointers.
224 */
225
226 dd = &rom->rom_dd;
227 rom->rom_devtype = bus_space_read_1(memt, romh, 3);
228 if (rom->rom_devtype == STI_DEVTYPE1) {
229 dd->dd_type = bus_space_read_1(memt, romh, 0x03);
230 dd->dd_nmon = bus_space_read_1(memt, romh, 0x07);
231 dd->dd_grrev = bus_space_read_1(memt, romh, 0x0b);
232 dd->dd_lrrev = bus_space_read_1(memt, romh, 0x0f);
233 dd->dd_grid[0] = parseword(0x10);
234 dd->dd_grid[1] = parseword(0x20);
235 dd->dd_fntaddr = parseword(0x30) & ~3;
236 dd->dd_maxst = parseword(0x40);
237 dd->dd_romend = parseword(0x50) & ~3;
238 dd->dd_reglst = parseword(0x60) & ~3;
239 dd->dd_maxreent = parseshort(0x70);
240 dd->dd_maxtimo = parseshort(0x78);
241 dd->dd_montbl = parseword(0x80) & ~3;
242 dd->dd_udaddr = parseword(0x90) & ~3;
243 dd->dd_stimemreq = parseword(0xa0);
244 dd->dd_udsize = parseword(0xb0);
245 dd->dd_pwruse = parseshort(0xc0);
246 dd->dd_bussup = bus_space_read_1(memt, romh, 0xcb);
247 dd->dd_ebussup = bus_space_read_1(memt, romh, 0xcf);
248 dd->dd_altcodet = bus_space_read_1(memt, romh, 0xd3);
249 dd->dd_eddst[0] = bus_space_read_1(memt, romh, 0xd7);
250 dd->dd_eddst[1] = bus_space_read_1(memt, romh, 0xdb);
251 dd->dd_eddst[2] = bus_space_read_1(memt, romh, 0xdf);
252 dd->dd_cfbaddr = parseword(0xe0) & ~3;
253
254 codebase <<= 2;
255 dd->dd_pacode[0x0] = parseword(codebase + 0x000) & ~3;
256 dd->dd_pacode[0x1] = parseword(codebase + 0x010) & ~3;
257 dd->dd_pacode[0x2] = parseword(codebase + 0x020) & ~3;
258 dd->dd_pacode[0x3] = parseword(codebase + 0x030) & ~3;
259 dd->dd_pacode[0x4] = parseword(codebase + 0x040) & ~3;
260 dd->dd_pacode[0x5] = parseword(codebase + 0x050) & ~3;
261 dd->dd_pacode[0x6] = parseword(codebase + 0x060) & ~3;
262 dd->dd_pacode[0x7] = parseword(codebase + 0x070) & ~3;
263 dd->dd_pacode[0x8] = parseword(codebase + 0x080) & ~3;
264 dd->dd_pacode[0x9] = parseword(codebase + 0x090) & ~3;
265 dd->dd_pacode[0xa] = parseword(codebase + 0x0a0) & ~3;
266 dd->dd_pacode[0xb] = parseword(codebase + 0x0b0) & ~3;
267 dd->dd_pacode[0xc] = parseword(codebase + 0x0c0) & ~3;
268 dd->dd_pacode[0xd] = parseword(codebase + 0x0d0) & ~3;
269 dd->dd_pacode[0xe] = parseword(codebase + 0x0e0) & ~3;
270 dd->dd_pacode[0xf] = parseword(codebase + 0x0f0) & ~3;
271 } else { /* STI_DEVTYPE4 */
272 bus_space_read_region_stream_4(memt, romh, 0, (uint32_t *)dd,
273 sizeof(*dd) / 4);
274 /* fix pacode... */
275 bus_space_read_region_stream_4(memt, romh, codebase,
276 (uint32_t *)dd->dd_pacode, sizeof(dd->dd_pacode) / 4);
277 }
278
279 STI_DISABLE_ROM(rom->rom_softc);
280
281 DPRINTF(("dd:\n"
282 "devtype=%x, rev=%x;%d, altt=%x, gid=%08x%08x, font=%x, mss=%x\n"
283 "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n"
284 "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n"
285 "code=",
286 dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet,
287 dd->dd_grid[0], dd->dd_grid[1], dd->dd_fntaddr, dd->dd_maxst,
288 dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo,
289 dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq,
290 dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr));
291 DPRINTF(("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
292 dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2],
293 dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5],
294 dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8],
295 dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb],
296 dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe],
297 dd->dd_pacode[0xf]));
298
299 /*
300 * Figure out how many bytes we need for the STI code.
301 * Note there could be fewer than STI_END pointer entries
302 * populated, especially on older devices.
303 */
304 for (i = STI_END; dd->dd_pacode[i] == 0; i--)
305 ;
306
307 size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN];
308
309 if (rom->rom_devtype == STI_DEVTYPE1)
310 size = (size + 3) / 4;
311 if (size == 0) {
312 aprint_error(": no code for the requested platform\n");
313 return EINVAL;
314 }
315
316 if (!(rom->rom_code = uvm_km_alloc(kernel_map, round_page(size), 0,
317 UVM_KMF_WIRED))) {
318 aprint_error(": cannot allocate %u bytes for code\n", size);
319 return ENOMEM;
320 }
321 DPRINTF(("code=0x%lx[%x]\n", rom->rom_code, size));
322
323 /*
324 * Copy code into memory and make it executable.
325 */
326
327 STI_ENABLE_ROM(rom->rom_softc);
328
329 if (rom->rom_devtype == STI_DEVTYPE1) {
330 uint8_t *p;
331 uint32_t addr, eaddr;
332
333 p = (uint8_t *)rom->rom_code;
334
335 for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4;
336 addr < eaddr; addr += 4 ) {
337 *p++ = bus_space_read_4(memt, romh, addr) & 0xff;
338 }
339 } else { /* STI_DEVTYPE4 */
340 bus_space_read_region_stream_4(memt, romh,
341 dd->dd_pacode[STI_BEGIN], (uint32_t *)rom->rom_code,
342 size / 4);
343 }
344
345 STI_DISABLE_ROM(rom->rom_softc);
346
347 if ((error = uvm_map_protect(kernel_map, rom->rom_code,
348 rom->rom_code + round_page(size), UVM_PROT_RX, FALSE))) {
349 aprint_error(": uvm_map_protect failed (%d)\n", error);
350 uvm_km_free(kernel_map, rom->rom_code, round_page(size),
351 UVM_KMF_WIRED);
352 return error;
353 }
354
355 /*
356 * Setup code function pointers.
357 */
358
359 #define O(i) \
360 (dd->dd_pacode[(i)] == 0 ? 0 : \
361 (rom->rom_code + (dd->dd_pacode[(i)] - dd->dd_pacode[0]) / \
362 (rom->rom_devtype == STI_DEVTYPE1 ? 4 : 1)))
363
364 rom->init = (sti_init_t)O(STI_INIT_GRAPH);
365 rom->mgmt = (sti_mgmt_t)O(STI_STATE_MGMT);
366 rom->unpmv = (sti_unpmv_t)O(STI_FONT_UNPMV);
367 rom->blkmv = (sti_blkmv_t)O(STI_BLOCK_MOVE);
368 rom->test = (sti_test_t)O(STI_SELF_TEST);
369 rom->exhdl = (sti_exhdl_t)O(STI_EXCEP_HDLR);
370 rom->inqconf = (sti_inqconf_t)O(STI_INQ_CONF);
371 rom->scment = (sti_scment_t)O(STI_SCM_ENT);
372 rom->dmac = (sti_dmac_t)O(STI_DMA_CTRL);
373 rom->flowc = (sti_flowc_t)O(STI_FLOW_CTRL);
374 rom->utiming = (sti_utiming_t)O(STI_UTIMING);
375 rom->pmgr = (sti_pmgr_t)O(STI_PROC_MGR);
376 rom->util = (sti_util_t)O(STI_UTIL);
377
378 #undef O
379
380 /*
381 * Set colormap entry is not implemented until 8.04, so force
382 * a NULL pointer here.
383 */
384 if (dd->dd_grrev < STI_REVISION(8, 4)) {
385 rom->scment = NULL;
386 }
387
388 return 0;
389 }
390
391 /*
392 * Map all regions.
393 */
394 void
395 sti_region_setup(struct sti_screen *scr)
396 {
397 struct sti_rom *rom = scr->scr_rom;
398 bus_space_tag_t memt = rom->memt;
399 bus_space_handle_t romh = rom->romh;
400 bus_addr_t *bases = rom->bases;
401 struct sti_dd *dd = &rom->rom_dd;
402 struct sti_cfg *cc = &scr->scr_cfg;
403 struct sti_region regions[STI_REGION_MAX], *r;
404 u_int regno, regcnt;
405 bus_addr_t addr;
406
407 DPRINTF(("stiregions @ %x:\n", dd->dd_reglst));
408
409 /*
410 * Read the region information.
411 */
412
413 STI_ENABLE_ROM(rom->rom_softc);
414
415 if (rom->rom_devtype == STI_DEVTYPE1) {
416 for (regno = 0; regno < STI_REGION_MAX; regno++)
417 *(u_int *)(regions + regno) =
418 parseword(dd->dd_reglst + regno * 0x10);
419 } else {
420 bus_space_read_region_stream_4(memt, romh, dd->dd_reglst,
421 (uint32_t *)regions, sizeof(regions) / 4);
422 }
423
424 STI_DISABLE_ROM(rom->rom_softc);
425
426 /*
427 * Count them.
428 */
429
430 for (regcnt = 0, r = regions; regcnt < STI_REGION_MAX; regcnt++, r++)
431 if (r->last)
432 break;
433 regcnt++;
434
435 /*
436 * Map them.
437 */
438
439 for (regno = 0, r = regions; regno < regcnt; regno++, r++) {
440 if (r->length == 0)
441 continue;
442
443 /*
444 * Assume an existing mapping exists.
445 */
446 addr = bases[regno] + (r->offset << PGSHIFT);
447 DPRINTF(("%08x @ 0x%08x%s%s%s%s",
448 r->length << PGSHIFT, (int)addr, r->sys_only ? " sys" : "",
449 r->cache ? " cache" : "", r->btlb ? " btlb" : "",
450 r->last ? " last" : ""));
451
452 /*
453 * Region #0 is always the rom, and it should have been
454 * mapped already.
455 * XXX This expects a 1:1 mapping...
456 */
457 if (regno == 0 && romh == bases[0]) {
458 cc->regions[0] = addr;
459 DPRINTF(("\n"));
460 continue;
461 }
462
463 if (bus_space_map(memt, addr, r->length << PGSHIFT,
464 BUS_SPACE_MAP_LINEAR | (r->cache ?
465 BUS_SPACE_MAP_CACHEABLE : 0), &rom->regh[regno]) != 0) {
466 rom->regh[regno] = romh; /* XXX */
467 DPRINTF((" - already mapped region\n"));
468 } else {
469 addr = (bus_addr_t)
470 bus_space_vaddr(memt, rom->regh[regno]);
471 if (regno == 1) {
472 DPRINTF((" - fb"));
473 scr->fbaddr = addr;
474 scr->fblen = r->length << PGSHIFT;
475 }
476 DPRINTF(("\n"));
477 }
478
479 cc->regions[regno] = addr;
480 }
481
482 #ifdef STIDEBUG
483 /*
484 * Make sure we'll trap accessing unmapped regions
485 */
486 for (regno = 0; regno < STI_REGION_MAX; regno++)
487 if (cc->regions[regno] == 0)
488 cc->regions[regno] = 0x81234567;
489 #endif
490 }
491
492 int
493 sti_screen_setup(struct sti_screen *scr, int flags)
494 {
495 struct sti_rom *rom = scr->scr_rom;
496 bus_space_tag_t memt = rom->memt;
497 bus_space_handle_t romh = rom->romh;
498 struct sti_dd *dd = &rom->rom_dd;
499 struct sti_cfg *cc = &scr->scr_cfg;
500 struct sti_inqconfout cfg;
501 struct sti_einqconfout ecfg;
502 #ifdef STIDEBUG
503 char buf[256];
504 #endif
505 int error, i;
506 int geometry_kluge = 0;
507 u_int fontindex = 0;
508
509 KASSERT(scr != NULL);
510 memset(cc, 0, sizeof(*cc));
511 cc->ext_cfg = &scr->scr_ecfg;
512 memset(cc->ext_cfg, 0, sizeof(*cc->ext_cfg));
513
514 if (dd->dd_stimemreq) {
515 scr->scr_ecfg.addr =
516 malloc(dd->dd_stimemreq, M_DEVBUF, M_WAITOK);
517 }
518
519 sti_region_setup(scr);
520
521 if ((error = sti_init(scr, 0))) {
522 aprint_error(": cannot initialize (%d)\n", error);
523 goto fail;
524 }
525
526 memset(&cfg, 0, sizeof(cfg));
527 memset(&ecfg, 0, sizeof(ecfg));
528 cfg.ext = &ecfg;
529 if ((error = sti_inqcfg(scr, &cfg))) {
530 aprint_error(": error %d inquiring config\n", error);
531 goto fail;
532 }
533
534 /*
535 * Older (rev 8.02) boards report wrong offset values,
536 * similar to the displayable area size, at least in m68k mode.
537 * Attempt to detect this and adjust here.
538 */
539 if (cfg.owidth == cfg.width &&
540 cfg.oheight == cfg.height)
541 geometry_kluge = 1;
542
543 if (geometry_kluge) {
544 scr->scr_cfg.oscr_width = cfg.owidth =
545 cfg.fbwidth - cfg.width;
546 scr->scr_cfg.oscr_height = cfg.oheight =
547 cfg.fbheight - cfg.height;
548 }
549
550 /*
551 * Save a few fields for sti_describe_screen() later
552 */
553 scr->fbheight = cfg.fbheight;
554 scr->fbwidth = cfg.fbwidth;
555 scr->oheight = cfg.oheight;
556 scr->owidth = cfg.owidth;
557 memcpy(scr->name, cfg.name, sizeof(scr->name));
558
559 if (flags & STI_FBMODE) {
560 /* we're done here */
561 sti_init(scr, STI_FBMODE);
562 return 0;
563 }
564
565 if ((error = sti_init(scr, STI_TEXTMODE | flags))) {
566 aprint_error(": cannot initialize (%d)\n", error);
567 goto fail;
568 }
569 #ifdef STIDEBUG
570 snprintb(buf, sizeof(buf), STI_INQCONF_BITS, cfg.attributes);
571 DPRINTF(("conf: bpp=%d planes=%d attr=%s\n"
572 "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", cfg.bpp,
573 cfg.planes, buf,
574 ecfg.crt_config[0], ecfg.crt_config[1], ecfg.crt_config[2],
575 ecfg.crt_hw[0], ecfg.crt_hw[1], ecfg.crt_hw[2]));
576 #endif
577 scr->scr_bpp = cfg.bppu;
578
579 /*
580 * Although scr->scr_ecfg.current_monitor is not filled by
581 * sti_init() as expected, we can nevertheless walk the monitor
582 * list, if there is any, and if we find a mode matching our
583 * resolution, pick its font index.
584 */
585 if (dd->dd_montbl != 0) {
586 STI_ENABLE_ROM(rom->rom_softc);
587
588 for (i = 0; i < dd->dd_nmon; i++) {
589 u_int offs = dd->dd_montbl + 8 * i;
590 uint32_t m[2];
591 sti_mon_t mon = (void *)m;
592 if (rom->rom_devtype == STI_DEVTYPE1) {
593 m[0] = parseword(4 * offs);
594 m[1] = parseword(4 * (offs + 4));
595 } else {
596 bus_space_read_region_stream_4(memt, romh, offs,
597 (uint32_t *)mon, sizeof(*mon) / 4);
598 }
599
600 if (mon->width == scr->scr_cfg.scr_width &&
601 mon->height == scr->scr_cfg.scr_height) {
602 fontindex = mon->font;
603 break;
604 }
605 }
606
607 STI_DISABLE_ROM(rom->rom_softc);
608
609 DPRINTF(("font index: %d\n", fontindex));
610 }
611
612 if ((error = sti_fetchfonts(scr, &cfg, dd->dd_fntaddr, fontindex))) {
613 aprint_error(": cannot fetch fonts (%d)\n", error);
614 goto fail;
615 }
616
617 /*
618 * setup screen descriptions:
619 * figure number of fonts supported;
620 * allocate wscons structures;
621 * calculate dimensions.
622 */
623
624 scr->scr_wsd.name = "std";
625 scr->scr_wsd.ncols = cfg.width / scr->scr_curfont.width;
626 scr->scr_wsd.nrows = cfg.height / scr->scr_curfont.height;
627 scr->scr_wsd.textops = &sti_emulops;
628 scr->scr_wsd.fontwidth = scr->scr_curfont.width;
629 scr->scr_wsd.fontheight = scr->scr_curfont.height;
630 scr->scr_wsd.capabilities = WSSCREEN_REVERSE;
631
632 scr->scr_scrlist[0] = &scr->scr_wsd;
633 scr->scr_screenlist.nscreens = 1;
634 scr->scr_screenlist.screens = scr->scr_scrlist;
635
636 #ifndef SMALL_KERNEL
637 /*
638 * Decide which board-specific routines to use.
639 */
640
641 switch (dd->dd_grid[0]) {
642 case STI_DD_CRX:
643 scr->setupfb = ngle_elk_setupfb;
644 scr->putcmap = ngle_putcmap;
645
646 scr->reg10_value = 0x13601000;
647 if (scr->scr_bpp > 8)
648 scr->reg12_value = NGLE_BUFF1_CMAP3;
649 else
650 scr->reg12_value = NGLE_BUFF1_CMAP0;
651 scr->cmap_finish_register = NGLE_REG_1;
652 break;
653
654 case STI_DD_TIMBER:
655 scr->setupfb = ngle_timber_setupfb;
656 scr->putcmap = ngle_putcmap;
657
658 scr->reg10_value = 0x13602000;
659 scr->reg12_value = NGLE_BUFF1_CMAP0;
660 scr->cmap_finish_register = NGLE_REG_1;
661 break;
662
663 case STI_DD_ARTIST:
664 scr->setupfb = ngle_artist_setupfb;
665 scr->putcmap = ngle_putcmap;
666
667 scr->reg10_value = 0x13601000;
668 scr->reg12_value = NGLE_ARTIST_CMAP0;
669 scr->cmap_finish_register = NGLE_REG_26;
670 break;
671
672 case STI_DD_EG:
673 scr->setupfb = ngle_artist_setupfb;
674 scr->putcmap = ngle_putcmap;
675
676 scr->reg10_value = 0x13601000;
677 if (scr->scr_bpp > 8) {
678 scr->reg12_value = NGLE_BUFF1_CMAP3;
679 scr->cmap_finish_register = NGLE_REG_1;
680 } else {
681 scr->reg12_value = NGLE_ARTIST_CMAP0;
682 scr->cmap_finish_register = NGLE_REG_26;
683 }
684 break;
685
686 case STI_DD_GRX:
687 case STI_DD_CRX24:
688 case STI_DD_EVRX:
689 case STI_DD_3X2V:
690 case STI_DD_DUAL_CRX:
691 case STI_DD_HCRX:
692 case STI_DD_LEGO:
693 case STI_DD_SUMMIT:
694 case STI_DD_PINNACLE:
695 default:
696 scr->setupfb = NULL;
697 scr->putcmap =
698 rom->scment == NULL ? NULL : ngle_default_putcmap;
699 break;
700 }
701 #endif
702
703 return 0;
704
705 fail:
706 /* XXX free resources */
707 if (scr->scr_ecfg.addr != NULL) {
708 free(scr->scr_ecfg.addr, M_DEVBUF);
709 scr->scr_ecfg.addr = NULL;
710 }
711
712 return ENXIO;
713 }
714
715 void
716 sti_describe_screen(struct sti_softc *sc, struct sti_screen *scr)
717 {
718 struct sti_font *fp = &scr->scr_curfont;
719
720 aprint_normal("%s: %s, %dx%d frame buffer, %dx%dx%d display\n",
721 device_xname(sc->sc_dev), scr->name, scr->fbwidth, scr->fbheight,
722 scr->scr_cfg.scr_width, scr->scr_cfg.scr_height, scr->scr_bpp);
723
724 aprint_normal("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
725 device_xname(sc->sc_dev), fp->width, fp->height,
726 fp->type, fp->bpc, fp->first, fp->last);
727 }
728
729 void
730 sti_describe(struct sti_softc *sc)
731 {
732 struct sti_rom *rom = sc->sc_rom;
733 struct sti_dd *dd = &rom->rom_dd;
734
735 aprint_normal(": rev %d.%02d;%d, ID 0x%08X%08X\n",
736 dd->dd_grrev >> 4, dd->dd_grrev & 0xf,
737 dd->dd_lrrev, dd->dd_grid[0], dd->dd_grid[1]);
738
739 if (sc->sc_scr != NULL)
740 sti_describe_screen(sc, sc->sc_scr);
741 }
742
743 /*
744 * Final part of attachment. On hppa where we use the PDC console
745 * during autoconf, this has to be postponed until autoconf has
746 * completed.
747 */
748 void
749 sti_end_attach(struct sti_softc *sc)
750 {
751 struct sti_screen *scr = sc->sc_scr;
752
753 if (scr == NULL)
754 return;
755 #if NWSDISPLAY > 0
756 else {
757 struct wsemuldisplaydev_attach_args waa;
758 scr->scr_wsmode = WSDISPLAYIO_MODE_EMUL;
759
760 waa.console = sc->sc_flags & STI_CONSOLE ? 1 : 0;
761 waa.scrdata = &scr->scr_screenlist;
762 waa.accessops = &sti_accessops;
763 waa.accesscookie = scr;
764
765 /* attach as console if required */
766 if (waa.console && !ISSET(sc->sc_flags, STI_ATTACHED)) {
767 long defattr;
768
769 sti_alloc_attr(scr, 0, 0, 0, &defattr);
770 wsdisplay_cnattach(&scr->scr_wsd, scr,
771 0, scr->scr_wsd.nrows - 1, defattr);
772 sc->sc_flags |= STI_ATTACHED;
773 }
774
775 config_found(sc->sc_dev, &waa, wsemuldisplaydevprint,
776 CFARGS_NONE);
777 }
778 #endif
779 }
780
781 u_int
782 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh)
783 {
784 int devtype;
785 u_int romend;
786
787 devtype = bus_space_read_1(memt, romh, 3);
788 if (devtype == STI_DEVTYPE4) {
789 bus_space_read_region_stream_4(memt, romh, STI_DEV4_DD_ROMEND,
790 (uint32_t *)&romend, 1);
791 } else {
792 romend = parseword(STI_DEV1_DD_ROMEND);
793 }
794
795 DPRINTF(("%s: %08x (%08x)\n", __func__, romend, round_page(romend)));
796
797 return round_page(romend);
798 }
799
800 int
801 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *cfg,
802 uint32_t baseaddr, u_int fontindex)
803 {
804 struct sti_rom *rom = scr->scr_rom;
805 bus_space_tag_t memt = rom->memt;
806 bus_space_handle_t romh = rom->romh;
807 struct sti_font *fp = &scr->scr_curfont;
808 uint32_t addr;
809 int size;
810 #ifdef notyet
811 int uc;
812 struct {
813 struct sti_unpmvflags flags;
814 struct sti_unpmvin in;
815 struct sti_unpmvout out;
816 } a;
817 #endif
818
819 /*
820 * Get the first PROM font in memory
821 */
822
823 STI_ENABLE_ROM(rom->rom_softc);
824
825 rescan:
826 addr = baseaddr;
827 do {
828 if (rom->rom_devtype == STI_DEVTYPE1) {
829 fp->first = parseshort(addr + 0x00);
830 fp->last = parseshort(addr + 0x08);
831 fp->width = bus_space_read_1(memt, romh, addr + 0x13);
832 fp->height = bus_space_read_1(memt, romh, addr + 0x17);
833 fp->type = bus_space_read_1(memt, romh, addr + 0x1b);
834 fp->bpc = bus_space_read_1(memt, romh, addr + 0x1f);
835 fp->next = parseword(addr + 0x20);
836 fp->uheight= bus_space_read_1(memt, romh, addr + 0x33);
837 fp->uoffset= bus_space_read_1(memt, romh, addr + 0x37);
838 } else { /* STI_DEVTYPE4 */
839 bus_space_read_region_stream_4(memt, romh, addr,
840 (uint32_t *)fp, sizeof(struct sti_font) / 4);
841 }
842
843 #ifdef STIDEBUG
844 STI_DISABLE_ROM(rom->rom_softc);
845 DPRINTF(("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
846 device_xname(scr->scr_rom->rom_softc->sc_dev), fp->width,
847 fp->height, fp->type, fp->bpc, fp->first, fp->last));
848 STI_ENABLE_ROM(rom->rom_softc);
849 #endif
850
851 if (fontindex == 0) {
852 size = sizeof(struct sti_font) +
853 (fp->last - fp->first + 1) * fp->bpc;
854 if (rom->rom_devtype == STI_DEVTYPE1)
855 size *= 4;
856 scr->scr_romfont = malloc(size, M_DEVBUF, M_WAITOK);
857
858 bus_space_read_region_stream_4(memt, romh, addr,
859 (uint32_t *)scr->scr_romfont, size / 4);
860 break;
861 }
862
863 addr = baseaddr + fp->next;
864 fontindex--;
865 } while (fp->next != 0);
866
867 /*
868 * If our font index was bogus, we did not find the expected font.
869 * In this case, pick the first one and be done with it.
870 */
871 if (fp->next == 0 && scr->scr_romfont == NULL) {
872 fontindex = 0;
873 goto rescan;
874 }
875
876 STI_DISABLE_ROM(rom->rom_softc);
877
878 #ifdef notyet
879 /*
880 * If there is enough room in the off-screen framebuffer memory,
881 * display all the characters there in order to display them
882 * faster with blkmv operations rather than unpmv later on.
883 */
884 if (size <= cfg->fbheight *
885 (cfg->fbwidth - cfg->width - cfg->owidth)) {
886 memset(&a, 0, sizeof(a));
887 a.flags.flags = STI_UNPMVF_WAIT;
888 a.in.fg_colour = STI_COLOUR_WHITE;
889 a.in.bg_colour = STI_COLOUR_BLACK;
890 a.in.font_addr = scr->scr_romfont;
891
892 scr->scr_fontmaxcol = cfg->fbheight / fp->height;
893 scr->scr_fontbase = cfg->width + cfg->owidth;
894 for (uc = fp->first; uc <= fp->last; uc++) {
895 a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) *
896 fp->width + scr->scr_fontbase;
897 a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) *
898 fp->height;
899 a.in.index = uc;
900
901 (*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
902 if (a.out.errno) {
903 aprint_error_dev(sc->sc_dev, "unpmv %d "
904 "returned %d\n", uc, a.out.errno);
905 return 0;
906 }
907 }
908
909 free(scr->scr_romfont, M_DEVBUF);
910 scr->scr_romfont = NULL;
911 }
912 #endif
913
914 return 0;
915 }
916
917 /*
918 * Wrappers around STI code pointers
919 */
920
921 int
922 sti_init(struct sti_screen *scr, int mode)
923 {
924 struct sti_rom *rom = scr->scr_rom;
925 struct {
926 struct sti_initflags flags;
927 struct sti_initin in;
928 struct sti_einitin ein;
929 struct sti_initout out;
930 } a;
931
932 KASSERT(rom != NULL);
933 memset(&a, 0, sizeof(a));
934
935 a.flags.flags = STI_INITF_WAIT | STI_INITF_PBET | STI_INITF_PBETI;
936 if ((mode & STI_TEXTMODE) != 0) {
937 a.flags.flags |= STI_INITF_TEXT | STI_INITF_CMB |
938 STI_INITF_PBET | STI_INITF_PBETI | STI_INITF_ICMT;
939 a.in.text_planes = 1;
940 } else {
941 a.flags.flags |= STI_INITF_TEXT | STI_INITF_NTEXT;
942 /*
943 * Request as many text planes as STI will allow.
944 * The reason to do this - when switching to framebuffer mode
945 * for X we need access to all planes. In theory STI should do
946 * just that when we request access to both text and non-text
947 * planes as above.
948 * In reality though, at least on my PCI Visualize EG, some
949 * planes and/or colour registers remain inaccessible if we
950 * request only one text plane.
951 * Clearly we're missing a register write or two here, but so
952 * far I haven't found it.
953 */
954 a.in.text_planes = 3;
955 }
956 if ((mode & STI_CLEARSCR) != 0)
957 a.flags.flags |= STI_INITF_CLEAR;
958
959 a.in.ext_in = &a.ein;
960
961 DPRINTF(("%s: init,%p(%x, %p, %p, %p)\n",
962 device_xname(rom->rom_softc->sc_dev), rom->init, a.flags.flags,
963 &a.in, &a.out, &scr->scr_cfg));
964
965 (*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
966
967 if (a.out.text_planes != a.in.text_planes)
968 return -1; /* not colliding with sti errno values */
969 return a.out.errno;
970 }
971
972 int
973 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out)
974 {
975 struct sti_rom *rom = scr->scr_rom;
976 struct {
977 struct sti_inqconfflags flags;
978 struct sti_inqconfin in;
979 } a;
980
981 memset(&a, 0, sizeof(a));
982
983 a.flags.flags = STI_INQCONFF_WAIT;
984 (*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg);
985
986 return out->errno;
987 }
988
989 void
990 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w,
991 enum sti_bmove_funcs f)
992 {
993 struct sti_rom *rom = scr->scr_rom;
994 struct {
995 struct sti_blkmvflags flags;
996 struct sti_blkmvin in;
997 struct sti_blkmvout out;
998 } a;
999
1000 memset(&a, 0, sizeof(a));
1001
1002 a.flags.flags = STI_BLKMVF_WAIT;
1003 switch (f) {
1004 case bmf_clear:
1005 a.flags.flags |= STI_BLKMVF_CLR;
1006 a.in.bg_colour = STI_COLOUR_BLACK;
1007 break;
1008 case bmf_underline:
1009 case bmf_copy:
1010 a.in.fg_colour = STI_COLOUR_WHITE;
1011 a.in.bg_colour = STI_COLOUR_BLACK;
1012 break;
1013 case bmf_invert:
1014 a.flags.flags |= STI_BLKMVF_COLR;
1015 a.in.fg_colour = STI_COLOUR_BLACK;
1016 a.in.bg_colour = STI_COLOUR_WHITE;
1017 break;
1018 }
1019 a.in.srcx = x1;
1020 a.in.srcy = y1;
1021 a.in.dstx = x2;
1022 a.in.dsty = y2;
1023 a.in.height = h;
1024 a.in.width = w;
1025
1026 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1027 #ifdef STIDEBUG
1028 if (a.out.errno)
1029 printf("%s: blkmv returned %d\n",
1030 device_xname(rom->rom_softc->sc_dev), a.out.errno);
1031 #endif
1032 }
1033
1034 int
1035 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b)
1036 {
1037 struct sti_rom *rom = scr->scr_rom;
1038 struct {
1039 struct sti_scmentflags flags;
1040 struct sti_scmentin in;
1041 struct sti_scmentout out;
1042 } a;
1043
1044 memset(&a, 0, sizeof(a));
1045
1046 a.flags.flags = STI_SCMENTF_WAIT;
1047 a.in.entry = i;
1048 a.in.value = (r << 16) | (g << 8) | b;
1049
1050 (*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1051
1052 return a.out.errno;
1053 }
1054
1055 /*
1056 * wsdisplay accessops
1057 */
1058 int
1059 sti_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
1060 {
1061 struct sti_screen *scr = (struct sti_screen *)v;
1062 struct wsdisplay_fbinfo *wdf;
1063 struct wsdisplay_cmap *cmapp;
1064 u_int mode, idx, count;
1065 int ret;
1066
1067 ret = 0;
1068 switch (cmd) {
1069 case WSDISPLAYIO_GMODE:
1070 *(u_int *)data = scr->scr_wsmode;
1071 break;
1072
1073 case WSDISPLAYIO_SMODE:
1074 mode = *(u_int *)data;
1075 switch (mode) {
1076 case WSDISPLAYIO_MODE_EMUL:
1077 if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL)
1078 ret = sti_init(scr, STI_TEXTMODE);
1079 break;
1080 case WSDISPLAYIO_MODE_DUMBFB:
1081 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) {
1082 ret = sti_init(scr, 0);
1083 if (scr->setupfb != NULL)
1084 scr->setupfb(scr);
1085 else
1086 #if 0
1087 ret = sti_init(scr, STI_FBMODE);
1088 #else
1089 ret = EINVAL;
1090 #endif
1091 }
1092 break;
1093 case WSDISPLAYIO_MODE_MAPPED:
1094 default:
1095 ret = EINVAL;
1096 break;
1097 }
1098 if (ret == 0)
1099 scr->scr_wsmode = mode;
1100 break;
1101
1102 case WSDISPLAYIO_GTYPE:
1103 *(u_int *)data = WSDISPLAY_TYPE_STI;
1104 break;
1105
1106 case WSDISPLAYIO_GINFO:
1107 wdf = (struct wsdisplay_fbinfo *)data;
1108 wdf->height = scr->scr_cfg.scr_height;
1109 wdf->width = scr->scr_cfg.scr_width;
1110 wdf->depth = scr->scr_bpp;
1111 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1112 wdf->cmsize = 0;
1113 else
1114 wdf->cmsize = STI_NCMAP;
1115 break;
1116
1117 case WSDISPLAYIO_LINEBYTES:
1118 if (scr->scr_bpp > 8)
1119 *(u_int *)data = scr->scr_cfg.fb_width * 4;
1120 else
1121 *(u_int *)data = scr->scr_cfg.fb_width;
1122 break;
1123
1124 case WSDISPLAYIO_GETCMAP:
1125 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1126 return ENODEV;
1127 cmapp = (struct wsdisplay_cmap *)data;
1128 idx = cmapp->index;
1129 count = cmapp->count;
1130 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1131 return EINVAL;
1132 if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
1133 break;
1134 if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
1135 break;
1136 if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
1137 break;
1138 break;
1139
1140 case WSDISPLAYIO_PUTCMAP:
1141 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1142 return ENODEV;
1143 if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL) {
1144 /*
1145 * The hardware palette settings are handled by
1146 * the STI ROM in STI_TEXTMODE and changing cmap
1147 * could cause mangled text colors at least on CRX.
1148 * Updating CMAP in EMUL mode isn't expected anyway
1149 * so just ignore it.
1150 */
1151 return 0;
1152 }
1153 cmapp = (struct wsdisplay_cmap *)data;
1154 idx = cmapp->index;
1155 count = cmapp->count;
1156 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1157 return EINVAL;
1158 if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
1159 break;
1160 if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
1161 break;
1162 if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
1163 break;
1164 ret = scr->putcmap(scr, idx, count);
1165 break;
1166
1167 case WSDISPLAYIO_SVIDEO:
1168 case WSDISPLAYIO_GVIDEO:
1169 case WSDISPLAYIO_GCURPOS:
1170 case WSDISPLAYIO_SCURPOS:
1171 case WSDISPLAYIO_GCURMAX:
1172 case WSDISPLAYIO_GCURSOR:
1173 case WSDISPLAYIO_SCURSOR:
1174 default:
1175 return ENOTTY; /* not supported yet */
1176 }
1177
1178 return ret;
1179 }
1180
1181 paddr_t
1182 sti_mmap(void *v, void *vs, off_t offset, int prot)
1183 {
1184 struct sti_screen *scr = (struct sti_screen *)v;
1185 struct sti_rom *rom = scr->scr_rom;
1186 paddr_t pa;
1187
1188 if ((offset & PAGE_MASK) != 0)
1189 return -1;
1190
1191 if (offset < 0 || offset >= scr->fblen)
1192 return -1;
1193
1194 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB)
1195 return -1;
1196
1197 pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot,
1198 BUS_SPACE_MAP_LINEAR);
1199
1200 if (pa == -1)
1201 pa = scr->fbaddr + offset;
1202
1203 return pa;
1204 }
1205
1206 int
1207 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1208 int *cxp, int *cyp, long *defattr)
1209 {
1210 struct sti_screen *scr = (struct sti_screen *)v;
1211
1212 if (scr->scr_nscreens > 0)
1213 return ENOMEM;
1214
1215 *cookiep = scr;
1216 *cxp = 0;
1217 *cyp = 0;
1218 sti_alloc_attr(scr, 0, 0, 0, defattr);
1219 scr->scr_nscreens++;
1220 return 0;
1221 }
1222
1223 void
1224 sti_free_screen(void *v, void *cookie)
1225 {
1226 struct sti_screen *scr = (struct sti_screen *)v;
1227
1228 scr->scr_nscreens--;
1229 }
1230
1231 int
1232 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
1233 void *cbarg)
1234 {
1235 #if 0
1236 struct sti_screen *scr = (struct sti_screen *)v;
1237 #endif
1238
1239 return 0;
1240 }
1241
1242 int
1243 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font)
1244 {
1245 #if 0
1246 struct sti_screen *scr = (struct sti_screen *)v;
1247 #endif
1248
1249 return -1;
1250 }
1251
1252 /*
1253 * wsdisplay emulops
1254 */
1255 void
1256 sti_cursor(void *v, int on, int row, int col)
1257 {
1258 struct sti_screen *scr = (struct sti_screen *)v;
1259 struct sti_font *fp = &scr->scr_curfont;
1260
1261 sti_bmove(scr,
1262 col * fp->width, row * fp->height,
1263 col * fp->width, row * fp->height,
1264 fp->height, fp->width, bmf_invert);
1265 }
1266
1267 /*
1268 * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
1269 */
1270 static const uint8_t
1271 sti_unitoroman[0x100 - 0xa0] = {
1272 0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc, 0, 0xbd,
1273 0xab, 0, 0xf9, 0xfb, 0, 0xf6, 0, 0xb0,
1274
1275 0xb3, 0xfe, 0, 0, 0xa8, 0xf3, 0xf4, 0xf2,
1276 0, 0, 0xfa, 0xfd, 0xf7, 0xf8, 0, 0xb9,
1277
1278 0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
1279 0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
1280
1281 0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda, 0,
1282 0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
1283
1284 0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
1285 0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
1286
1287 0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce, 0,
1288 0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
1289 };
1290
1291 int
1292 sti_mapchar(void *v, int uni, u_int *index)
1293 {
1294 struct sti_screen *scr = (struct sti_screen *)v;
1295 struct sti_font *fp = &scr->scr_curfont;
1296 int c;
1297
1298 switch (fp->type) {
1299 case STI_FONT_HPROMAN8:
1300 if (uni >= 0x80 && uni < 0xa0)
1301 c = -1;
1302 else if (uni >= 0xa0 && uni < 0x100) {
1303 c = (int)sti_unitoroman[uni - 0xa0];
1304 if (c == 0)
1305 c = -1;
1306 } else
1307 c = uni;
1308 break;
1309 default:
1310 c = uni;
1311 break;
1312 }
1313
1314 if (c == -1 || c < fp->first || c > fp->last) {
1315 *index = ' ';
1316 return 0;
1317 }
1318
1319 *index = c;
1320 return 5;
1321 }
1322
1323 void
1324 sti_putchar(void *v, int row, int col, u_int uc, long attr)
1325 {
1326 struct sti_screen *scr = (struct sti_screen *)v;
1327 struct sti_rom *rom = scr->scr_rom;
1328 struct sti_font *fp = &scr->scr_curfont;
1329 int bg, fg;
1330
1331 fg = WSATTR_UNPACK_FG(attr);
1332 bg = WSATTR_UNPACK_BG(attr);
1333
1334 if (scr->scr_romfont != NULL) {
1335 /*
1336 * Font is in memory, use unpmv
1337 */
1338 struct {
1339 struct sti_unpmvflags flags;
1340 struct sti_unpmvin in;
1341 struct sti_unpmvout out;
1342 } a;
1343
1344 memset(&a, 0, sizeof(a));
1345
1346 a.flags.flags = STI_UNPMVF_WAIT;
1347 a.in.fg_colour = fg;
1348 a.in.bg_colour = bg;
1349 a.in.x = col * fp->width;
1350 a.in.y = row * fp->height;
1351 a.in.font_addr = scr->scr_romfont;
1352 a.in.index = uc;
1353
1354 (*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1355 } else {
1356 /*
1357 * Font is in frame buffer, use blkmv
1358 */
1359 struct {
1360 struct sti_blkmvflags flags;
1361 struct sti_blkmvin in;
1362 struct sti_blkmvout out;
1363 } a;
1364
1365 memset(&a, 0, sizeof(a));
1366
1367 a.flags.flags = STI_BLKMVF_WAIT;
1368 a.in.fg_colour = fg;
1369 a.in.bg_colour = bg;
1370
1371 a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
1372 fp->width + scr->scr_fontbase;
1373 a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
1374 fp->height;
1375 a.in.dstx = col * fp->width;
1376 a.in.dsty = row * fp->height;
1377 a.in.height = fp->height;
1378 a.in.width = fp->width;
1379
1380 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1381 }
1382 }
1383
1384 void
1385 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
1386 {
1387 struct sti_screen *scr = (struct sti_screen *)v;
1388 struct sti_font *fp = &scr->scr_curfont;
1389
1390 sti_bmove(scr,
1391 srccol * fp->width, row * fp->height,
1392 dstcol * fp->width, row * fp->height,
1393 fp->height, ncols * fp->width, bmf_copy);
1394 }
1395
1396 void
1397 sti_erasecols(void *v, int row, int startcol, int ncols, long attr)
1398 {
1399 struct sti_screen *scr = (struct sti_screen *)v;
1400 struct sti_font *fp = &scr->scr_curfont;
1401
1402 sti_bmove(scr,
1403 startcol * fp->width, row * fp->height,
1404 startcol * fp->width, row * fp->height,
1405 fp->height, ncols * fp->width, bmf_clear);
1406 }
1407
1408 void
1409 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
1410 {
1411 struct sti_screen *scr = (struct sti_screen *)v;
1412 struct sti_font *fp = &scr->scr_curfont;
1413
1414 sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
1415 nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
1416 }
1417
1418 void
1419 sti_eraserows(void *v, int srcrow, int nrows, long attr)
1420 {
1421 struct sti_screen *scr = (struct sti_screen *)v;
1422 struct sti_font *fp = &scr->scr_curfont;
1423
1424 sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
1425 nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
1426 }
1427
1428 int
1429 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr)
1430 {
1431 #if 0
1432 struct sti_screen *scr = (struct sti_screen *)v;
1433 #endif
1434
1435 if ((flags & (WSATTR_HILIT | WSATTR_BLINK |
1436 WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0)
1437 return EINVAL;
1438 if ((flags & WSATTR_REVERSE) != 0) {
1439 fg = STI_COLOUR_BLACK;
1440 bg = STI_COLOUR_WHITE;
1441 } else {
1442 fg = STI_COLOUR_WHITE;
1443 bg = STI_COLOUR_BLACK;
1444 }
1445
1446 *pattr = WSATTR_PACK(fg, bg, flags);
1447 return 0;
1448 }
1449
1450 /*
1451 * Early console support. Only used on hp300, currently
1452 */
1453 int
1454 sti_cnattach(struct sti_rom *rom, struct sti_screen *scr, bus_space_tag_t memt,
1455 bus_addr_t *bases, u_int codebase)
1456 {
1457 bus_space_handle_t romh;
1458 u_int romend;
1459 int error;
1460 long defattr;
1461
1462 if ((error = bus_space_map(memt, bases[0], PAGE_SIZE, 0, &romh)) != 0)
1463 return error;
1464
1465 /*
1466 * Compute real PROM size
1467 */
1468 romend = sti_rom_size(memt, romh);
1469
1470 bus_space_unmap(memt, romh, PAGE_SIZE);
1471
1472 if ((error = bus_space_map(memt, bases[0], romend, 0, &romh)) != 0)
1473 return error;
1474
1475 bases[0] = romh;
1476 if (sti_rom_setup(rom, memt, memt, romh, bases, codebase) != 0)
1477 return -1;
1478 scr->scr_rom = rom;
1479 if (sti_screen_setup(scr, STI_CLEARSCR) != 0)
1480 return -1;
1481
1482 sti_alloc_attr(scr, 0, 0, 0, &defattr);
1483 wsdisplay_cnattach(&scr->scr_wsd, scr, 0, 0, defattr);
1484
1485 return 0;
1486 }
1487
1488 int
1489 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1490 {
1491 int i, ret;
1492
1493 for (i = idx + count - 1; i >= (int)idx; i--)
1494 if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
1495 scr->scr_gcmap[i], scr->scr_bcmap[i])))
1496 return EINVAL;
1497
1498 return 0;
1499 }
1500
1501 #ifndef SMALL_KERNEL
1502
1503 void ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
1504 void ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
1505 void ngle_setup_attr_planes(struct sti_screen *scr);
1506 void ngle_setup_bt458(struct sti_screen *scr);
1507
1508 #define ngle_bt458_write(memt, memh, r, v) \
1509 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
1510
1511 void
1512 ngle_artist_setupfb(struct sti_screen *scr)
1513 {
1514 struct sti_rom *rom = scr->scr_rom;
1515 bus_space_tag_t memt = rom->memt;
1516 bus_space_handle_t memh = rom->regh[2];
1517
1518 ngle_setup_bt458(scr);
1519
1520 ngle_setup_hw(memt, memh);
1521 ngle_setup_fb(memt, memh, scr->reg10_value);
1522
1523 ngle_setup_attr_planes(scr);
1524
1525 ngle_setup_hw(memt, memh);
1526 bus_space_write_stream_4(memt, memh, NGLE_REG_21,
1527 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1528 bus_space_write_stream_4(memt, memh, NGLE_REG_27,
1529 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
1530 }
1531
1532 void
1533 ngle_elk_setupfb(struct sti_screen *scr)
1534 {
1535 struct sti_rom *rom = scr->scr_rom;
1536 bus_space_tag_t memt = rom->memt;
1537 bus_space_handle_t memh = rom->regh[2];
1538
1539 ngle_setup_bt458(scr);
1540
1541 ngle_setup_hw(memt, memh);
1542 ngle_setup_fb(memt, memh, scr->reg10_value);
1543
1544 ngle_setup_attr_planes(scr);
1545
1546 ngle_setup_hw(memt, memh);
1547 /* enable overlay planes in Bt458 command register */
1548 ngle_bt458_write(memt, memh, 0x0c, 0x06);
1549 ngle_bt458_write(memt, memh, 0x0e, 0x43);
1550 }
1551
1552 void
1553 ngle_timber_setupfb(struct sti_screen *scr)
1554 {
1555 struct sti_rom *rom = scr->scr_rom;
1556 bus_space_tag_t memt = rom->memt;
1557 bus_space_handle_t memh = rom->regh[2];
1558
1559 ngle_setup_bt458(scr);
1560
1561 ngle_setup_hw(memt, memh);
1562 /* enable overlay planes in Bt458 command register */
1563 ngle_bt458_write(memt, memh, 0x0c, 0x06);
1564 ngle_bt458_write(memt, memh, 0x0e, 0x43);
1565 }
1566
1567 void
1568 ngle_setup_bt458(struct sti_screen *scr)
1569 {
1570 struct sti_rom *rom = scr->scr_rom;
1571 bus_space_tag_t memt = rom->memt;
1572 bus_space_handle_t memh = rom->regh[2];
1573
1574 ngle_setup_hw(memt, memh);
1575 /* set Bt458 read mask register to all planes */
1576 ngle_bt458_write(memt, memh, 0x08, 0x04);
1577 ngle_bt458_write(memt, memh, 0x0a, 0xff);
1578 }
1579
1580 void
1581 ngle_setup_attr_planes(struct sti_screen *scr)
1582 {
1583 struct sti_rom *rom = scr->scr_rom;
1584 bus_space_tag_t memt = rom->memt;
1585 bus_space_handle_t memh = rom->regh[2];
1586
1587 ngle_setup_hw(memt, memh);
1588 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
1589 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302);
1590 bus_space_write_stream_4(memt, memh, NGLE_REG_12, scr->reg12_value);
1591 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
1592
1593 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000);
1594 bus_space_write_stream_4(memt, memh, NGLE_REG_9,
1595 (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height);
1596 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000);
1597 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001);
1598
1599 ngle_setup_hw(memt, memh);
1600 bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000);
1601
1602 ngle_setup_fb(memt, memh, scr->reg10_value);
1603 }
1604
1605 int
1606 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1607 {
1608 struct sti_rom *rom = scr->scr_rom;
1609 bus_space_tag_t memt = rom->memt;
1610 bus_space_handle_t memh = rom->regh[2];
1611 uint8_t *r, *g, *b;
1612 uint32_t cmap_finish;
1613
1614 if (scr->scr_bpp > 8)
1615 cmap_finish = 0x83000100;
1616 else
1617 cmap_finish = 0x80000100;
1618
1619 r = scr->scr_rcmap + idx;
1620 g = scr->scr_gcmap + idx;
1621 b = scr->scr_bcmap + idx;
1622
1623 ngle_setup_hw(memt, memh);
1624 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1625 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1626 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1627
1628 while (count-- != 0) {
1629 ngle_setup_hw(memt, memh);
1630 bus_space_write_stream_4(memt, memh, NGLE_REG_3,
1631 0x400 | (idx << 2));
1632 bus_space_write_stream_4(memt, memh, NGLE_REG_4,
1633 (*r << 16) | (*g << 8) | *b);
1634
1635 idx++;
1636 r++, g++, b++;
1637 }
1638
1639 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400);
1640 bus_space_write_stream_4(memt, memh, scr->cmap_finish_register,
1641 cmap_finish);
1642 ngle_setup_fb(memt, memh, scr->reg10_value);
1643
1644
1645 return 0;
1646 }
1647
1648 void
1649 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh)
1650 {
1651 uint8_t stat;
1652
1653 do {
1654 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1655 if (stat == 0)
1656 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1657 } while (stat != 0);
1658 }
1659
1660 void
1661 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10)
1662 {
1663
1664 ngle_setup_hw(memt, memh);
1665 bus_space_write_stream_4(memt, memh, NGLE_REG_10, reg10);
1666 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300);
1667 ngle_setup_hw(memt, memh);
1668 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
1669 }
1670 #endif /* SMALL_KERNEL */
1671