sti.c revision 1.39 1 /* $NetBSD: sti.c,v 1.39 2024/08/19 16:09:42 skrll 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.39 2024/08/19 16:09:42 skrll 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 case WSDISPLAYIO_GINFO:
1126 wdf = (struct wsdisplay_fbinfo *)data;
1127 wdf->height = scr->scr_cfg.scr_height;
1128 wdf->width = scr->scr_cfg.scr_width;
1129 wdf->depth = scr->scr_bpp;
1130 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1131 wdf->cmsize = 0;
1132 else
1133 wdf->cmsize = STI_NCMAP;
1134 break;
1135
1136 case WSDISPLAYIO_LINEBYTES:
1137 if (scr->scr_bpp > 8)
1138 *(u_int *)data = scr->scr_cfg.fb_width * 4;
1139 else
1140 *(u_int *)data = scr->scr_cfg.fb_width;
1141 break;
1142
1143 case WSDISPLAYIO_GETCMAP:
1144 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1145 return ENODEV;
1146 cmapp = (struct wsdisplay_cmap *)data;
1147 idx = cmapp->index;
1148 count = cmapp->count;
1149 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1150 return EINVAL;
1151 if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
1152 break;
1153 if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
1154 break;
1155 if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
1156 break;
1157 break;
1158
1159 case WSDISPLAYIO_PUTCMAP:
1160 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1161 return ENODEV;
1162 if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL) {
1163 /*
1164 * The hardware palette settings are handled by
1165 * the STI ROM in STI_TEXTMODE and changing cmap
1166 * could cause mangled text colors at least on CRX.
1167 * Updating CMAP in EMUL mode isn't expected anyway
1168 * so just ignore it.
1169 */
1170 return 0;
1171 }
1172 cmapp = (struct wsdisplay_cmap *)data;
1173 idx = cmapp->index;
1174 count = cmapp->count;
1175 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1176 return EINVAL;
1177 if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
1178 break;
1179 if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
1180 break;
1181 if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
1182 break;
1183 ret = scr->putcmap(scr, idx, count);
1184 break;
1185
1186 case WSDISPLAYIO_SVIDEO:
1187 case WSDISPLAYIO_GVIDEO:
1188 case WSDISPLAYIO_GCURPOS:
1189 case WSDISPLAYIO_SCURPOS:
1190 case WSDISPLAYIO_GCURMAX:
1191 case WSDISPLAYIO_GCURSOR:
1192 case WSDISPLAYIO_SCURSOR:
1193 default:
1194 return ENOTTY; /* not supported yet */
1195 }
1196
1197 return ret;
1198 }
1199
1200 paddr_t
1201 sti_mmap(void *v, void *vs, off_t offset, int prot)
1202 {
1203 struct sti_screen *scr = (struct sti_screen *)v;
1204 struct sti_rom *rom = scr->scr_rom;
1205 paddr_t pa;
1206
1207 if ((offset & PAGE_MASK) != 0)
1208 return -1;
1209
1210 if (offset < 0 || offset >= scr->fblen)
1211 return -1;
1212
1213 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB)
1214 return -1;
1215
1216 pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot,
1217 BUS_SPACE_MAP_LINEAR);
1218
1219 if (pa == -1)
1220 pa = scr->fbaddr + offset;
1221
1222 return pa;
1223 }
1224
1225 int
1226 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1227 int *cxp, int *cyp, long *defattr)
1228 {
1229 struct sti_screen *scr = (struct sti_screen *)v;
1230
1231 if (scr->scr_nscreens > 0)
1232 return ENOMEM;
1233
1234 *cookiep = scr;
1235 *cxp = 0;
1236 *cyp = 0;
1237 sti_alloc_attr(scr, 0, 0, 0, defattr);
1238 scr->scr_nscreens++;
1239 return 0;
1240 }
1241
1242 void
1243 sti_free_screen(void *v, void *cookie)
1244 {
1245 struct sti_screen *scr = (struct sti_screen *)v;
1246
1247 scr->scr_nscreens--;
1248 }
1249
1250 int
1251 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
1252 void *cbarg)
1253 {
1254 #if 0
1255 struct sti_screen *scr = (struct sti_screen *)v;
1256 #endif
1257
1258 return 0;
1259 }
1260
1261 int
1262 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font)
1263 {
1264 #if 0
1265 struct sti_screen *scr = (struct sti_screen *)v;
1266 #endif
1267
1268 return -1;
1269 }
1270
1271 /*
1272 * wsdisplay emulops
1273 */
1274 void
1275 sti_cursor(void *v, int on, int row, int col)
1276 {
1277 struct sti_screen *scr = (struct sti_screen *)v;
1278 struct sti_font *fp = &scr->scr_curfont;
1279
1280 sti_bmove(scr,
1281 col * fp->width, row * fp->height,
1282 col * fp->width, row * fp->height,
1283 fp->height, fp->width, bmf_invert);
1284 }
1285
1286 /*
1287 * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
1288 */
1289 static const uint8_t
1290 sti_unitoroman[0x100 - 0xa0] = {
1291 0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc, 0, 0xbd,
1292 0xab, 0, 0xf9, 0xfb, 0, 0xf6, 0, 0xb0,
1293
1294 0xb3, 0xfe, 0, 0, 0xa8, 0xf3, 0xf4, 0xf2,
1295 0, 0, 0xfa, 0xfd, 0xf7, 0xf8, 0, 0xb9,
1296
1297 0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
1298 0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
1299
1300 0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda, 0,
1301 0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
1302
1303 0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
1304 0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
1305
1306 0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce, 0,
1307 0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
1308 };
1309
1310 int
1311 sti_mapchar(void *v, int uni, u_int *index)
1312 {
1313 struct sti_screen *scr = (struct sti_screen *)v;
1314 struct sti_font *fp = &scr->scr_curfont;
1315 int c;
1316
1317 switch (fp->type) {
1318 case STI_FONT_HPROMAN8:
1319 if (uni >= 0x80 && uni < 0xa0)
1320 c = -1;
1321 else if (uni >= 0xa0 && uni < 0x100) {
1322 c = (int)sti_unitoroman[uni - 0xa0];
1323 if (c == 0)
1324 c = -1;
1325 } else
1326 c = uni;
1327 break;
1328 default:
1329 c = uni;
1330 break;
1331 }
1332
1333 if (c == -1 || c < fp->first || c > fp->last) {
1334 *index = ' ';
1335 return 0;
1336 }
1337
1338 *index = c;
1339 return 5;
1340 }
1341
1342 void
1343 sti_putchar(void *v, int row, int col, u_int uc, long attr)
1344 {
1345 struct sti_screen *scr = (struct sti_screen *)v;
1346 struct sti_rom *rom = scr->scr_rom;
1347 struct sti_font *fp = &scr->scr_curfont;
1348 int bg, fg;
1349
1350 fg = WSATTR_UNPACK_FG(attr);
1351 bg = WSATTR_UNPACK_BG(attr);
1352
1353 if (scr->scr_romfont != NULL) {
1354 /*
1355 * Font is in memory, use unpmv
1356 */
1357 struct {
1358 struct sti_unpmvflags flags;
1359 struct sti_unpmvin in;
1360 struct sti_unpmvout out;
1361 } a;
1362
1363 memset(&a, 0, sizeof(a));
1364
1365 a.flags.flags = STI_UNPMVF_WAIT;
1366 a.in.fg_colour = fg;
1367 a.in.bg_colour = bg;
1368 a.in.x = col * fp->width;
1369 a.in.y = row * fp->height;
1370 a.in.font_addr = scr->scr_romfont;
1371 a.in.index = uc;
1372
1373 (*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1374 } else {
1375 /*
1376 * Font is in frame buffer, use blkmv
1377 */
1378 struct {
1379 struct sti_blkmvflags flags;
1380 struct sti_blkmvin in;
1381 struct sti_blkmvout out;
1382 } a;
1383
1384 memset(&a, 0, sizeof(a));
1385
1386 a.flags.flags = STI_BLKMVF_WAIT;
1387 a.in.fg_colour = fg;
1388 a.in.bg_colour = bg;
1389
1390 a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
1391 fp->width + scr->scr_fontbase;
1392 a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
1393 fp->height;
1394 a.in.dstx = col * fp->width;
1395 a.in.dsty = row * fp->height;
1396 a.in.height = fp->height;
1397 a.in.width = fp->width;
1398
1399 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1400 }
1401 }
1402
1403 void
1404 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
1405 {
1406 struct sti_screen *scr = (struct sti_screen *)v;
1407 struct sti_font *fp = &scr->scr_curfont;
1408
1409 sti_bmove(scr,
1410 srccol * fp->width, row * fp->height,
1411 dstcol * fp->width, row * fp->height,
1412 fp->height, ncols * fp->width, bmf_copy);
1413 }
1414
1415 void
1416 sti_erasecols(void *v, int row, int startcol, int ncols, long attr)
1417 {
1418 struct sti_screen *scr = (struct sti_screen *)v;
1419 struct sti_font *fp = &scr->scr_curfont;
1420
1421 sti_bmove(scr,
1422 startcol * fp->width, row * fp->height,
1423 startcol * fp->width, row * fp->height,
1424 fp->height, ncols * fp->width, bmf_clear);
1425 }
1426
1427 void
1428 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
1429 {
1430 struct sti_screen *scr = (struct sti_screen *)v;
1431 struct sti_font *fp = &scr->scr_curfont;
1432
1433 sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
1434 nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
1435 }
1436
1437 void
1438 sti_eraserows(void *v, int srcrow, int nrows, long attr)
1439 {
1440 struct sti_screen *scr = (struct sti_screen *)v;
1441 struct sti_font *fp = &scr->scr_curfont;
1442
1443 sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
1444 nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
1445 }
1446
1447 int
1448 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr)
1449 {
1450 #if 0
1451 struct sti_screen *scr = (struct sti_screen *)v;
1452 #endif
1453
1454 if ((flags & (WSATTR_HILIT | WSATTR_BLINK |
1455 WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0)
1456 return EINVAL;
1457 if ((flags & WSATTR_REVERSE) != 0) {
1458 fg = STI_COLOUR_BLACK;
1459 bg = STI_COLOUR_WHITE;
1460 } else {
1461 fg = STI_COLOUR_WHITE;
1462 bg = STI_COLOUR_BLACK;
1463 }
1464
1465 *pattr = WSATTR_PACK(fg, bg, flags);
1466 return 0;
1467 }
1468
1469 /*
1470 * Early console support. Only used on hp300, currently
1471 */
1472 int
1473 sti_cnattach(struct sti_rom *rom, struct sti_screen *scr, bus_space_tag_t memt,
1474 bus_addr_t *bases, u_int codebase)
1475 {
1476 bus_space_handle_t romh;
1477 u_int romend;
1478 int error;
1479 long defattr;
1480
1481 if ((error = bus_space_map(memt, bases[0], PAGE_SIZE, 0, &romh)) != 0)
1482 return error;
1483
1484 /*
1485 * Compute real PROM size
1486 */
1487 romend = sti_rom_size(memt, romh);
1488
1489 bus_space_unmap(memt, romh, PAGE_SIZE);
1490
1491 if ((error = bus_space_map(memt, bases[0], romend, 0, &romh)) != 0)
1492 return error;
1493
1494 bases[0] = romh;
1495 if (sti_rom_setup(rom, memt, memt, romh, bases, codebase) != 0)
1496 return -1;
1497 scr->scr_rom = rom;
1498 if (sti_screen_setup(scr, STI_CLEARSCR) != 0)
1499 return -1;
1500
1501 sti_alloc_attr(scr, 0, 0, 0, &defattr);
1502 wsdisplay_cnattach(&scr->scr_wsd, scr, 0, 0, defattr);
1503
1504 return 0;
1505 }
1506
1507 int
1508 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1509 {
1510 int i, ret;
1511
1512 for (i = idx + count - 1; i >= (int)idx; i--)
1513 if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
1514 scr->scr_gcmap[i], scr->scr_bcmap[i])))
1515 return EINVAL;
1516
1517 return 0;
1518 }
1519
1520 #ifndef SMALL_KERNEL
1521
1522 void ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
1523 void ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
1524 void ngle_setup_attr_planes(struct sti_screen *scr);
1525 void ngle_setup_bt458(struct sti_screen *scr);
1526
1527 #define ngle_bt458_write(memt, memh, r, v) \
1528 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
1529
1530 void
1531 ngle_artist_setupfb(struct sti_screen *scr)
1532 {
1533 struct sti_rom *rom = scr->scr_rom;
1534 bus_space_tag_t memt = rom->memt;
1535 bus_space_handle_t memh = rom->regh[2];
1536
1537 ngle_setup_bt458(scr);
1538
1539 ngle_setup_hw(memt, memh);
1540 ngle_setup_fb(memt, memh, scr->reg10_value);
1541
1542 ngle_setup_attr_planes(scr);
1543
1544 ngle_setup_hw(memt, memh);
1545 bus_space_write_stream_4(memt, memh, NGLE_REG_21,
1546 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1547 bus_space_write_stream_4(memt, memh, NGLE_REG_27,
1548 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
1549 }
1550
1551 void
1552 ngle_elk_setupfb(struct sti_screen *scr)
1553 {
1554 struct sti_rom *rom = scr->scr_rom;
1555 bus_space_tag_t memt = rom->memt;
1556 bus_space_handle_t memh = rom->regh[2];
1557
1558 ngle_setup_bt458(scr);
1559
1560 ngle_setup_hw(memt, memh);
1561 ngle_setup_fb(memt, memh, scr->reg10_value);
1562
1563 ngle_setup_attr_planes(scr);
1564
1565 ngle_setup_hw(memt, memh);
1566 /* enable overlay planes in Bt458 command register */
1567 ngle_bt458_write(memt, memh, 0x0c, 0x06);
1568 ngle_bt458_write(memt, memh, 0x0e, 0x43);
1569 }
1570
1571 void
1572 ngle_timber_setupfb(struct sti_screen *scr)
1573 {
1574 struct sti_rom *rom = scr->scr_rom;
1575 bus_space_tag_t memt = rom->memt;
1576 bus_space_handle_t memh = rom->regh[2];
1577
1578 ngle_setup_bt458(scr);
1579
1580 ngle_setup_hw(memt, memh);
1581 /* enable overlay planes in Bt458 command register */
1582 ngle_bt458_write(memt, memh, 0x0c, 0x06);
1583 ngle_bt458_write(memt, memh, 0x0e, 0x43);
1584 }
1585
1586 void
1587 ngle_setup_bt458(struct sti_screen *scr)
1588 {
1589 struct sti_rom *rom = scr->scr_rom;
1590 bus_space_tag_t memt = rom->memt;
1591 bus_space_handle_t memh = rom->regh[2];
1592
1593 ngle_setup_hw(memt, memh);
1594 /* set Bt458 read mask register to all planes */
1595 ngle_bt458_write(memt, memh, 0x08, 0x04);
1596 ngle_bt458_write(memt, memh, 0x0a, 0xff);
1597 }
1598
1599 void
1600 ngle_setup_attr_planes(struct sti_screen *scr)
1601 {
1602 struct sti_rom *rom = scr->scr_rom;
1603 bus_space_tag_t memt = rom->memt;
1604 bus_space_handle_t memh = rom->regh[2];
1605
1606 ngle_setup_hw(memt, memh);
1607 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
1608 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302);
1609 bus_space_write_stream_4(memt, memh, NGLE_REG_12, scr->reg12_value);
1610 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
1611
1612 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000);
1613 bus_space_write_stream_4(memt, memh, NGLE_REG_9,
1614 (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height);
1615 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000);
1616 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001);
1617
1618 ngle_setup_hw(memt, memh);
1619 bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000);
1620
1621 ngle_setup_fb(memt, memh, scr->reg10_value);
1622 }
1623
1624 int
1625 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1626 {
1627 struct sti_rom *rom = scr->scr_rom;
1628 bus_space_tag_t memt = rom->memt;
1629 bus_space_handle_t memh = rom->regh[2];
1630 uint8_t *r, *g, *b;
1631 uint32_t cmap_finish;
1632
1633 if (scr->scr_bpp > 8)
1634 cmap_finish = 0x83000100;
1635 else
1636 cmap_finish = 0x80000100;
1637
1638 r = scr->scr_rcmap + idx;
1639 g = scr->scr_gcmap + idx;
1640 b = scr->scr_bcmap + idx;
1641
1642 ngle_setup_hw(memt, memh);
1643 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1644 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1645 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1646
1647 while (count-- != 0) {
1648 ngle_setup_hw(memt, memh);
1649 bus_space_write_stream_4(memt, memh, NGLE_REG_3,
1650 0x400 | (idx << 2));
1651 bus_space_write_stream_4(memt, memh, NGLE_REG_4,
1652 (*r << 16) | (*g << 8) | *b);
1653
1654 idx++;
1655 r++, g++, b++;
1656 }
1657
1658
1659 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400);
1660 bus_space_write_stream_4(memt, memh, scr->cmap_finish_register,
1661 cmap_finish);
1662 ngle_setup_fb(memt, memh, scr->reg10_value);
1663
1664
1665 return 0;
1666 }
1667
1668 int
1669 ngle_hcrx_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1670 {
1671 struct sti_rom *rom = scr->scr_rom;
1672 bus_space_tag_t memt = rom->memt;
1673 bus_space_handle_t memh = rom->regh[2];
1674 uint8_t *r, *g, *b;
1675 uint32_t cmap_finish;
1676
1677 if (scr->scr_bpp > 8)
1678 cmap_finish = 0x80000100;
1679 else
1680 cmap_finish = 0x82000100;
1681
1682 r = scr->scr_rcmap + idx;
1683 g = scr->scr_gcmap + idx;
1684 b = scr->scr_bcmap + idx;
1685
1686 ngle_setup_hw(memt, memh);
1687 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1688 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1689 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1690
1691 while (count-- != 0) {
1692 ngle_setup_hw(memt, memh);
1693 bus_space_write_stream_4(memt, memh, NGLE_REG_3,
1694 0x400 | (idx << 2));
1695 bus_space_write_stream_4(memt, memh, NGLE_REG_4,
1696 (*r << 16) | (*g << 8) | *b);
1697
1698 idx++;
1699 r++, g++, b++;
1700 }
1701
1702
1703 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400);
1704 bus_space_write_stream_4(memt, memh, NGLE_REG_38, cmap_finish);
1705 ngle_setup_fb(memt, memh, scr->reg10_value);
1706
1707
1708 return 0;
1709 }
1710
1711 void
1712 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh)
1713 {
1714 uint8_t stat;
1715
1716 do {
1717 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1718 if (stat == 0)
1719 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1720 } while (stat != 0);
1721 }
1722
1723 void
1724 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10)
1725 {
1726
1727 ngle_setup_hw(memt, memh);
1728 bus_space_write_stream_4(memt, memh, NGLE_REG_10, reg10);
1729 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300);
1730 ngle_setup_hw(memt, memh);
1731 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
1732 }
1733 #endif /* SMALL_KERNEL */
1734