1 /*
2 TPG CVS users: please don't commit changes to this file directly, send
3 them to prumpf@tux.org and wait for a new version instead. Otherwise,
4 your changes will get lost when prumpf releases the next version, as
5 this file *will* be replaced with it. You have been warned.
6
7 2000-05-30, <deller@gmx.de>
8 */
9 #if 1
10 #define DPRINTK(x) printk x
11 #else
12 #define DPRINTK(x)
13 #endif
14
15 /*
16 * linux/drivers/video/sticon.c - console driver using HP's STI firmware
17 *
18 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
19 *
20 * Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
21 * which were
22 *
23 * Created 28 Sep 1997 by Geert Uytterhoeven
24 * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
25 * Copyright (C) 1991, 1992 Linus Torvalds
26 * 1995 Jay Estabrook
27 * Copyright (C) 1995 Geert Uytterhoeven
28 * Copyright (C) 1993 Bjoern Brauel
29 * Roman Hodek
30 * Copyright (C) 1993 Hamish Macdonald
31 * Greg Harp
32 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
33 *
34 * with work by William Rucklidge (wjr@cs.cornell.edu)
35 * Geert Uytterhoeven
36 * Jes Sorensen (jds@kom.auc.dk)
37 * Martin Apel
38 * with work by Guenther Kelleter
39 * Martin Schaller
40 * Andreas Schwab
41 * Emmanuel Marty (core@ggi-project.org)
42 * Jakub Jelinek (jj@ultra.linux.cz)
43 * Martin Mares <mj@ucw.cz>
44 *
45 * This file is subject to the terms and conditions of the GNU General Public
46 * License. See the file COPYING in the main directory of this archive for
47 * more details.
48 */
49 /*
50 * TODO:
51 * - call STI in virtual mode rather than in real mode
52 * - support for PCI-only STI ROMs (which don't have a traditional region
53 * list)
54 * - safe detection (i.e. verify there is a graphics device at a given
55 * address first, not just read a random device's io space)
56 * - support for multiple STI devices in one machine
57 * - support for byte-mode STI ROMs
58 * - support for just using STI to switch to a colour fb (stifb ?)
59 * - try to make it work on m68k hp workstations ;)
60 */
61
62 #include <linux/types.h>
63 #include <linux/sched.h>
64 #include <linux/fs.h>
65 #include <linux/kernel.h>
66 #include <linux/tty.h>
67 #include <linux/console.h>
68 #include <linux/string.h>
69 #include <linux/kd.h>
70 #include <linux/malloc.h>
71 #include <linux/vt_kern.h>
72 #include <linux/selection.h>
73 #include <linux/ioport.h>
74 #include <linux/init.h>
75 #include <linux/delay.h>
76
77 #include <asm/io.h>
78 #include <asm/real.h>
79
80 #include <linux/module.h>
81 #include <linux/fb.h>
82 #include <linux/smp.h>
83
84 #include <asm/irq.h>
85 #include <asm/system.h>
86 #include <asm/uaccess.h>
87
88 #include <video/fbcon.h>
89 #include <video/font.h>
90
91 #include "sti-bmode.h"
92
93 /* The latency of the STI functions cannot really be reduced by setting
94 * this to 0; STI doesn't seem to be designed to allow calling a different
95 * function (or the same function with different arguments) after a
96 * function exited with 1 as return value.
97 *
98 * As all of the functions below could be called from interrupt context,
99 * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
100 * block. Really bad latency there.
101 *
102 * Probably the best solution to all this is have the generic code manage
103 * the screen buffer and a kernel thread to call STI occasionally.
104 *
105 * Luckily, the frame buffer guys have the same problem so we can just wait
106 * for them to fix it and steal their solution. prumpf
107 *
108 * Actually, another long-term viable solution is to completely do STI
109 * support in userspace - that way we avoid the potential license issues
110 * of using proprietary fonts, too. */
111
112 #define STI_WAIT 1
113 #define STI_PTR(p) ( (typeof(p)) virt_to_phys(p))
114 #define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) )
115
116 static struct sti_struct default_sti = {
117 SPIN_LOCK_UNLOCKED,
118 };
119
120 static struct sti_font_flags default_font_flags = {
121 STI_WAIT, 0, 0, NULL
122 };
123
124 /* The colour indices used by STI are
125 * 0 - Black
126 * 1 - White
127 * 2 - Red
128 * 3 - Yellow/Brown
129 * 4 - Green
130 * 5 - Cyan
131 * 6 - Blue
132 * 7 - Magenta
133 *
134 * So we have the same colours as VGA (basically one bit each for R, G, B),
135 * but have to translate them, anyway. */
136
137 static u8 col_trans[8] = {
138 0, 6, 4, 5,
139 2, 7, 3, 1
140 };
141
142 #define c_fg(sti, c) col_trans[((c>> 8) & 7)]
143 #define c_bg(sti, c) col_trans[((c>>11) & 7)]
144 #define c_index(sti, c) (c&0xff)
145
146 #define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x)
147 #define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y)
148 #define sti_font_x(sti) (STI_U8(PTR_STI(sti->font)->width))
149 #define sti_font_y(sti) (STI_U8(PTR_STI(sti->font)->height))
150
151 static struct sti_init_flags default_init_flags = {
152 STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
153 };
154
155 static void sti_init_graph(struct sti_struct *sti)
156 {
157 struct sti_init_inptr_ext inptr_ext = {
158 0, { 0 }, 0, NULL
159 };
160 struct sti_init_inptr inptr = {
161 3, STI_PTR(&inptr_ext)
162 };
163 struct sti_init_outptr outptr = { 0 };
164 unsigned long flags;
165 s32 ret;
166
167 spin_lock_irqsave(&sti->lock, flags);
168
169 ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
170 &outptr, sti->glob_cfg);
171
172 spin_unlock_irqrestore(&sti->lock, flags);
173
174 sti->text_planes = outptr.text_planes;
175 }
176
177 #if 0
178 static struct sti_conf_flags default_conf_flags = {
179 STI_WAIT, 0, NULL
180 };
181
182 static void sti_inq_conf(struct sti_struct *sti)
183 {
184 struct sti_conf_inptr inptr = { NULL };
185 struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
186 struct sti_conf_outptr outptr = {
187 ext_ptr: STI_PTR(&outptr_ext)
188 };
189 unsigned long flags;
190 s32 ret;
191
192 do {
193 spin_lock_irqsave(&sti->lock, flags);
194 ret = STI_CALL(sti->inq_conf, &default_conf_flags,
195 &inptr, &outptr, sti->glob_cfg);
196 spin_unlock_irqrestore(&sti->lock, flags);
197 } while(ret == 1);
198 }
199 #endif
200
201 static void sti_putc(struct sti_struct *sti, int c, int y, int x)
202 {
203 struct sti_font_inptr inptr = {
204 (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
205 x * sti_font_x(sti), y * sti_font_y(sti), NULL
206 };
207 struct sti_font_outptr outptr = {
208 0, NULL
209 };
210 s32 ret;
211 unsigned long flags;
212
213 do {
214 spin_lock_irqsave(&sti->lock, flags);
215 ret = STI_CALL(sti->font_unpmv, &default_font_flags,
216 &inptr, &outptr, sti->glob_cfg);
217 spin_unlock_irqrestore(&sti->lock, flags);
218 } while(ret == 1);
219 }
220
221 static struct sti_blkmv_flags clear_blkmv_flags = {
222 STI_WAIT, 1, 1, 0, 0, NULL
223 };
224
225 static void sti_set(struct sti_struct *sti, int src_y, int src_x,
226 int height, int width, u8 color)
227 {
228 struct sti_blkmv_inptr inptr = {
229 color, color,
230 src_x, src_y ,
231 src_x, src_y ,
232 width, height,
233 NULL
234 };
235 struct sti_blkmv_outptr outptr = { 0, NULL };
236 s32 ret = 0;
237 unsigned long flags;
238
239 do {
240 spin_lock_irqsave(&sti->lock, flags);
241 ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
242 &inptr, &outptr, sti->glob_cfg);
243 spin_unlock_irqrestore(&sti->lock, flags);
244 } while(ret == 1);
245 }
246
247 static void sti_clear(struct sti_struct *sti, int src_y, int src_x,
248 int height, int width)
249 {
250 struct sti_blkmv_inptr inptr = {
251 0, 0,
252 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
253 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
254 width * sti_font_x(sti), height* sti_font_y(sti),
255 NULL
256 };
257 struct sti_blkmv_outptr outptr = { 0, NULL };
258 s32 ret = 0;
259 unsigned long flags;
260
261 do {
262 spin_lock_irqsave(&sti->lock, flags);
263 ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
264 &inptr, &outptr, sti->glob_cfg);
265 spin_unlock_irqrestore(&sti->lock, flags);
266 } while(ret == 1);
267 }
268
269 static struct sti_blkmv_flags default_blkmv_flags = {
270 STI_WAIT, 0, 0, 0, 0, NULL
271 };
272
273 static void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
274 int dst_y, int dst_x, int height, int width)
275 {
276 struct sti_blkmv_inptr inptr = {
277 0, 0,
278 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
279 dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
280 width * sti_font_x(sti), height* sti_font_y(sti),
281 NULL
282 };
283 struct sti_blkmv_outptr outptr = { 0, NULL };
284 s32 ret = 0;
285 unsigned long flags;
286
287 do {
288 spin_lock_irqsave(&sti->lock, flags);
289 ret = STI_CALL(sti->block_move, &default_blkmv_flags,
290 &inptr, &outptr, sti->glob_cfg);
291 spin_unlock_irqrestore(&sti->lock, flags);
292 } while(ret == 1);
293 }
294
295
296 /* STICON */
297
298 static const char __init *sticon_startup(void)
299 {
300 return "STI console";
301 }
302
303 static int sticon_set_palette(struct vc_data *c, unsigned char *table)
304 {
305 return -EINVAL;
306 }
307 static int sticon_font_op(struct vc_data *c, struct console_font_op *op)
308 {
309 return -ENOSYS;
310 }
311
312 static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
313 {
314 sti_putc(&default_sti, c, ypos, xpos);
315 }
316
317 static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
318 int count, int ypos, int xpos)
319 {
320 while(count--) {
321 sti_putc(&default_sti, *s++, ypos, xpos++);
322 }
323 }
324
325 static void sticon_cursor(struct vc_data *conp, int mode)
326 {
327 }
328
329 static int sticon_scroll(struct vc_data *conp, int t, int b, int dir,
330 int count)
331 {
332 struct sti_struct *sti = &default_sti;
333
334 if(console_blanked)
335 return 0;
336
337 sticon_cursor(conp, CM_ERASE);
338
339 switch(dir) {
340 case SM_UP:
341 sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols);
342 sti_clear(sti, b-count, 0, count, conp->vc_cols);
343
344 break;
345
346 case SM_DOWN:
347 sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols);
348 sti_clear(sti, t, 0, count, conp->vc_cols);
349
350 break;
351 }
352
353 return 0;
354 }
355
356 static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
357 int height, int width)
358 {
359 sti_bmove(&default_sti, sy, sx, dy, dx, height, width);
360 }
361
362 static void sticon_init(struct vc_data *c, int init)
363 {
364 struct sti_struct *sti = &default_sti;
365 int vc_cols, vc_rows;
366
367 sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
368 c->vc_can_do_color = 1;
369 vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti);
370 vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti);
371
372 vc_resize_con(vc_rows, vc_cols, c->vc_num);
373 }
374
375 static void sticon_deinit(struct vc_data *c)
376 {
377 }
378
379 static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
380 int width)
381 {
382 sti_clear(&default_sti, sy, sx, height, width);
383 }
384
385 static int sticon_switch(struct vc_data *conp)
386 {
387 return 0;
388 }
389
390 static int sticon_blank(struct vc_data *conp, int blank)
391 {
392 return 0;
393 }
394
395 static int sticon_scrolldelta(struct vc_data *conp, int lines)
396 {
397 return 0;
398 }
399
400 static int sticon_set_origin(struct vc_data *conp)
401 {
402 return 0;
403 }
404
405 static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
406 {
407 return NULL;
408 }
409
410 static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py)
411 {
412 return 0;
413 }
414
415 static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
416 {
417 u8 attr = ((color & 0x70) >> 1) | ((color & 7));
418
419 if(reverse) {
420 color = ((color>>3)&0x7) | ((color &0x7)<<3);
421 }
422
423
424 return attr;
425 }
426
427 static struct consw sti_con = {
428 con_startup: sticon_startup,
429 con_init: sticon_init,
430 con_deinit: sticon_deinit,
431 con_clear: sticon_clear,
432 con_putc: sticon_putc,
433 con_putcs: sticon_putcs,
434 con_cursor: sticon_cursor,
435 con_scroll: sticon_scroll,
436 con_bmove: sticon_bmove,
437 con_switch: sticon_switch,
438 con_blank: sticon_blank,
439 con_font_op: sticon_font_op,
440 con_set_palette: sticon_set_palette,
441 con_scrolldelta: sticon_scrolldelta,
442 con_set_origin: sticon_set_origin,
443 con_save_screen: NULL,
444 con_build_attr: sticon_build_attr,
445 con_invert_region: NULL,
446 con_screen_pos: sticon_screen_pos,
447 con_getxy: sticon_getxy,
448 };
449
450 #include <asm/pgalloc.h> /* need cache flush routines */
451 static void __init sti_rom_copy(unsigned long base, unsigned long offset,
452 unsigned long count, void *dest)
453 {
454 void *savedest = dest;
455 int savecount = count;
456
457 while(count >= 4) {
458 count -= 4;
459 *(u32 *)dest = gsc_readl(base + offset);
460 #if 0
461 DPRINTK(("%08x\n", *(u32 *)dest));
462 if(*(u32 *)dest == 0x64646464) {
463 DPRINTK(("!!!!\n"));
464 { u32 foo = 0; while(foo += 0x100); }
465 }
466 #endif
467 offset += 4;
468 dest += 4;
469 }
470 while(count) {
471 count--;
472 *(u8 *)dest = gsc_readb(base + offset);
473 offset++;
474 dest++;
475 }
476 __flush_dcache_range(dest, count);
477 __flush_icache_range(dest, count);
478 }
479
480 static void dump_sti_rom(struct sti_rom *rom)
481 {
482 printk("STI byte mode ROM type %d\n", STI_U8(rom->type));
483 printk(" supports %d monitors\n", STI_U8(rom->num_mons));
484 printk(" conforms to STI ROM spec revision %d.%02x\n",
485 STI_U8(rom->revno[0]) >> 4, STI_U8(rom->revno[0]) & 0x0f);
486 printk(__FUNCTION__ ": %d\n", __LINE__);
487 printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
488 (unsigned int) STI_U8(rom->graphics_id[0]),
489 (unsigned int) STI_U8(rom->graphics_id[1]),
490 (unsigned int) STI_U8(rom->graphics_id[2]),
491 (unsigned int) STI_U8(rom->graphics_id[3]),
492 (unsigned int) STI_U8(rom->graphics_id[4]),
493 (unsigned int) STI_U8(rom->graphics_id[5]),
494 (unsigned int) STI_U8(rom->graphics_id[6]),
495 (unsigned int) STI_U8(rom->graphics_id[7]));
496 printk(__FUNCTION__ ": %d\n", __LINE__);
497 printk(" font start %08x\n", STI_U32(rom->font_start));
498 printk(__FUNCTION__ ": %d\n", __LINE__);
499 printk(" region list %08x\n", STI_U32(rom->region_list));
500 printk(__FUNCTION__ ": %d\n", __LINE__);
501 printk(" init_graph %08x\n", STI_U32(rom->init_graph));
502 printk(__FUNCTION__ ": %d\n", __LINE__);
503 printk(" alternate code type %d\n", STI_U8(rom->alt_code_type));
504 printk(__FUNCTION__ ": %d\n", __LINE__);
505 }
506
507 static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
508 struct sti_rom *raw_rom)
509 {
510 struct sti_rom_font *raw_font;
511 struct sti_cooked_font *cooked_font;
512 struct sti_rom_font *font_start;
513
514 cooked_font =
515 kmalloc(sizeof *cooked_font, GFP_KERNEL);
516 if(!cooked_font)
517 return;
518
519 cooked_rom->font_start = cooked_font;
520
521 #if 0
522 DPRINTK(("%p = %p + %08x\n",
523 ((void *)raw_rom) + (STI_U32(raw_rom->font_start)),
524 ((void *)raw_rom), (STI_U32(raw_rom->font_start))));
525 #endif
526 raw_font = ((void *)raw_rom) + STI_U32(raw_rom->font_start) - 3;
527
528 font_start = raw_font;
529 cooked_font->raw = raw_font;
530
531 DPRINTK(("next font %08x\n", STI_U32(raw_font->next_font)));
532
533 while(0 && STI_U32(raw_font->next_font)) {
534 raw_font = ((void *)font_start) + STI_U32(raw_font->next_font);
535
536 cooked_font->next_font =
537 kmalloc(sizeof *cooked_font, GFP_KERNEL);
538 if(!cooked_font->next_font)
539 return;
540
541 cooked_font = cooked_font->next_font;
542
543 // cooked_font->raw = raw_font;
544
545 DPRINTK(("raw_font %p\n",
546 raw_font));
547 DPRINTK(("next_font %08x %p\n",
548 STI_U32(raw_font->next_font),
549 ((void *)font_start) + STI_U32(raw_font->next_font)));
550 }
551
552 cooked_font->next_font = NULL;
553 }
554
555 static unsigned long __init sti_cook_function(void *function,
556 u32 size)
557 {
558 sti_u32 *func = (sti_u32 *)function;
559 u32 *ret;
560 int i;
561
562 ret = kmalloc(size, GFP_KERNEL);
563 if(!ret) {
564 printk(KERN_ERR __FILE__ ": could not get memory.\n");
565 return 0;
566 }
567
568 for(i=0; i<(size/4); i++)
569 ret[i] = STI_U32(func[i]);
570
571 flush_all_caches();
572
573 return virt_to_phys(ret);
574 }
575
576 static int font_index, font_height, font_width;
577
578 static int __init sti_search_font(struct sti_cooked_rom *rom,
579 int height, int width)
580 {
581 struct sti_cooked_font *font;
582 int i = 0;
583
584 for(font = rom->font_start; font; font = font->next_font, i++) {
585 if((STI_U8(font->raw->width) == width) &&
586 (STI_U8(font->raw->height) == height))
587 return i;
588 }
589
590 return 0;
591 }
592
593 static struct sti_cooked_font * __init
594 sti_select_font(struct sti_cooked_rom *rom)
595 {
596 struct sti_cooked_font *font;
597 int i;
598
599 if(font_width && font_height)
600 font_index = sti_search_font(rom, font_height, font_width);
601
602 for(font = rom->font_start, i = font_index;
603 font && (i > 0);
604 font = font->next_font, i--);
605
606 if(font)
607 return font;
608 else
609 return rom->font_start;
610 }
611
612 /* address is a pointer to a word mode or pci rom */
613 static struct sti_struct * __init sti_read_rom(unsigned long address)
614 {
615 struct sti_struct *ret = NULL;
616 struct sti_cooked_rom *cooked = NULL;
617 struct sti_rom *raw = NULL;
618 unsigned long size;
619
620 ret = &default_sti;
621
622 if(!ret)
623 goto out_err;
624
625 cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
626 raw = kmalloc(sizeof *raw, GFP_KERNEL);
627
628 if(!(raw && cooked))
629 goto out_err;
630
631 /* reallocate raw */
632 sti_rom_copy(address, 0, sizeof *raw, raw);
633
634 dump_sti_rom(raw);
635
636 size = STI_U32(raw->last_addr) + 1;
637 size = 128*1024;
638 // DPRINTK(("size %08lx\n", size));
639 // DPRINTK(("font_start %08x\n", STI_U32(raw->font_start)));
640 // kfree(raw);
641 raw = kmalloc(size, GFP_KERNEL);
642 if(!raw)
643 goto out_err;
644 sti_rom_copy(address, 0, size-1, raw);
645
646 sti_cook_fonts(cooked, raw);
647 // sti_cook_regions(cooked, raw);
648 // sti_cook_functions(cooked, raw);
649
650 if(STI_U32(raw->region_list)) {
651 struct sti_rom_region *region =
652 ((void *)raw) + STI_U32(raw->region_list) - 3;
653
654 // DPRINTK(("region_list %08x\n", STI_U32(raw->region_list)));
655
656 ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME!! */
657
658 ret->regions[0] = STI_U32(region[0].region);
659 ret->regions[1] = STI_U32(region[1].region);
660 ret->regions[2] = STI_U32(region[2].region);
661 ret->regions[3] = STI_U32(region[3].region);
662 ret->regions[4] = STI_U32(region[4].region);
663 ret->regions[5] = STI_U32(region[5].region);
664 ret->regions[6] = STI_U32(region[6].region);
665 ret->regions[7] = STI_U32(region[7].region);
666 }
667
668 address = virt_to_phys(raw);
669
670 #if 0
671 DPRINTK(("init_graph %08x %08x\n"
672 "state_mgmt %08x %08x\n"
673 "font_unpmv %08x %08x\n"
674 "block_move %08x %08x\n"
675 "self_test %08x %08x\n"
676 "excep_hdlr %08x %08x\n"
677 "irq_conf %08x %08x\n"
678 "set_cm_e %08x %08x\n"
679 "dma_ctrl %08x %08x\n"
680 "flow_ctrl %08x %08x\n"
681 "user_timin %08x %08x\n"
682 "process_m %08x %08x\n"
683 "sti_util %08x %08x\n"
684 "end_addr %08x %08x\n",
685 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
686 STI_U32(raw->state_mgmt), STI_U32(raw->state_mgmt_m68k),
687 STI_U32(raw->font_unpmv), STI_U32(raw->font_unpmv_m68k),
688 STI_U32(raw->block_move), STI_U32(raw->block_move_m68k),
689 STI_U32(raw->self_test), STI_U32(raw->self_test_m68k),
690 STI_U32(raw->excep_hdlr), STI_U32(raw->excep_hdlr_m68k),
691 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
692 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
693 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
694 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
695 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
696 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
697 STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k),
698 STI_U32(raw->end_addr), STI_U32(raw->end_addr_m68k) ) );
699 #endif
700
701 ret->init_graph = sti_cook_function(((void *)raw)+STI_U32(raw->init_graph)-3,
702 (STI_U32(raw->state_mgmt) -
703 STI_U32(raw->init_graph))/4);
704
705
706 ret->font_unpmv = sti_cook_function(((void *)raw)+STI_U32(raw->font_unpmv)-3,
707 (STI_U32(raw->block_move) -
708 STI_U32(raw->font_unpmv))/4);
709
710 ret->block_move = sti_cook_function(((void *)raw)+STI_U32(raw->block_move)-3,
711 (STI_U32(raw->self_test) -
712 STI_U32(raw->block_move))/4);
713
714 ret->inq_conf = sti_cook_function(((void *)raw)+STI_U32(raw->inq_conf),
715 STI_U32(raw->set_cm_entry) -
716 STI_U32(raw->inq_conf));
717
718 ret->rom = cooked;
719 ret->rom->raw = raw;
720
721 ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
722
723 return ret;
724
725 out_err:
726 if(raw)
727 kfree(raw);
728 if(cooked)
729 kfree(cooked);
730
731 return NULL;
732 }
733
734 #if 0
735 static void dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
736 {
737 DPRINTK(("monitor %d\n"
738 "in friendly mode: %d\n"
739 "power consumption %d watts\n"
740 "freq ref %d\n"
741 "sti_mem_addr %p\n",
742 cfg->curr_mon,
743 cfg->friendly_boot,
744 cfg->power,
745 cfg->freq_ref,
746 cfg->sti_mem_addr));
747 }
748
749 static void dump_globcfg(struct sti_glob_cfg *glob_cfg)
750 {
751 DPRINTK(("%d text planes\n"
752 "%4d x %4d screen resolution\n"
753 "%4d x %4d offscreen\n"
754 "%4d x %4d layout\n"
755 "regions at %08x %08x %08x %08x\n"
756 "regions at %08x %08x %08x %08x\n"
757 "reent_lvl %d\n"
758 "save_addr %p\n",
759 glob_cfg->text_planes,
760 glob_cfg->onscreen_x, glob_cfg->onscreen_y,
761 glob_cfg->offscreen_x, glob_cfg->offscreen_y,
762 glob_cfg->total_x, glob_cfg->total_y,
763 glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
764 glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
765 glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
766 glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
767 glob_cfg->reent_lvl,
768 glob_cfg->save_addr));
769 dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
770 }
771 #endif
772
773 static void __init sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
774 unsigned long rom_address)
775 {
776 struct sti_glob_cfg *glob_cfg;
777 struct sti_glob_cfg_ext *glob_cfg_ext;
778 void *save_addr;
779 void *sti_mem_addr;
780
781 glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
782 glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
783 save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
784 sti_mem_addr = kmalloc(1024, GFP_KERNEL);
785
786 if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
787 return;
788
789 memset(glob_cfg, 0, sizeof *glob_cfg);
790 memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
791 memset(save_addr, 0, 1024);
792 memset(sti_mem_addr, 0, 1024);
793
794 glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
795 glob_cfg->save_addr = STI_PTR(save_addr);
796 glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
797 glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
798 glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
799 glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
800 glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
801 glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
802 glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
803 glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
804
805 glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
806
807 sti->glob_cfg = STI_PTR(glob_cfg);
808 }
809
810 static void __init sti_try_rom(unsigned long address, unsigned long hpa)
811 {
812 struct sti_struct *sti = NULL;
813 u16 sig;
814
815 /* if we can't read the ROM, bail out early. Not being able
816 * to read the hpa is okay, for romless sti */
817 if(pdc_add_valid((void*)address))
818 return;
819
820 printk("found potential STI ROM at %08lx\n", address);
821
822 sig = le16_to_cpu(gsc_readw(address));
823
824 if((sig&0xff) == 0x01) {
825 sti = sti_read_rom(address);
826 }
827
828 if(sig == 0x0303) {
829 printk("STI word mode ROM at %08lx, ignored\n",
830 address);
831
832 sti = NULL;
833 }
834
835 if(!sti)
836 return;
837
838 /* this is hacked. We need a better way to find out the HPA for
839 * romless STI (eg search for the graphics devices we know about
840 * by sversion) */
841 if (!pdc_add_valid((void *)0xf5000000)) DPRINTK(("f4000000 b\n"));
842 if (!pdc_add_valid((void *)0xf7000000)) DPRINTK(("f6000000 b\n"));
843 if (!pdc_add_valid((void *)0xf9000000)) DPRINTK(("f8000000 b\n"));
844 if (!pdc_add_valid((void *)0xfb000000)) DPRINTK(("fa000000 b\n"));
845 sti_init_glob_cfg(sti, hpa, address);
846
847 sti_init_graph(sti);
848
849 //sti_inq_conf(sti);
850 #if !defined(SERIAL_CONSOLE)
851 {
852 extern void pdc_console_die(void);
853 pdc_console_die();
854 }
855 #endif
856
857 take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1);
858
859 /* sti_inq_conf(sti); */
860 }
861
862 static unsigned long sti_address;
863 static unsigned long sti_hpa;
864
865 static void __init sti_init_roms(void)
866 {
867 /* handle the command line */
868 if(sti_address && sti_hpa) {
869 sti_try_rom(sti_address, sti_hpa);
870
871 return;
872 }
873
874 /* 712, 715, some other boxes don't have a separate STI ROM,
875 * but use part of the regular flash */
876 if(PAGE0->proc_sti) {
877 printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
878 if(!pdc_add_valid((void *)0xf9000000))
879 sti_try_rom(PAGE0->proc_sti, 0xf8000000);
880 else if(!pdc_add_valid((void *)0xf5000000))
881 sti_try_rom(PAGE0->proc_sti, 0xf4000000);
882 else if(!pdc_add_valid((void *)0xf7000000))
883 sti_try_rom(PAGE0->proc_sti, 0xf6000000);
884 else if(!pdc_add_valid((void *)0xfb000000))
885 sti_try_rom(PAGE0->proc_sti, 0xfa000000);
886 }
887
888 /* standard locations for GSC graphic devices */
889 if(!pdc_add_valid((void *)0xf4000000))
890 sti_try_rom(0xf4000000, 0xf4000000);
891 if(!pdc_add_valid((void *)0xf6000000))
892 sti_try_rom(0xf6000000, 0xf6000000);
893 if(!pdc_add_valid((void *)0xf8000000))
894 sti_try_rom(0xf8000000, 0xf8000000);
895 if(!pdc_add_valid((void *)0xfa000000))
896 sti_try_rom(0xfa000000, 0xfa000000);
897 }
898
899 static int __init sti_init(void)
900 {
901 printk("searching for byte mode STI ROMs\n");
902 sti_init_roms();
903 return 0;
904 }
905
906 module_init(sti_init)
907
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.