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