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