- Kai Germaschewski: ymfpci cleanups and resource leak fixes
[davej-history.git] / drivers / video / sticore.c
blob56e7f43ce5f9cb7c58badbf84e6ec50167bd9903
1 #include <linux/module.h>
2 #include <linux/types.h>
3 #include <linux/kernel.h>
4 #include <linux/malloc.h>
5 #include <linux/init.h>
7 #include <asm/uaccess.h>
8 #include <asm/pgalloc.h>
9 #include <asm/io.h>
11 #include "sti.h"
13 struct sti_struct default_sti = {
14 SPIN_LOCK_UNLOCKED,
17 static struct sti_font_flags default_font_flags = {
18 STI_WAIT, 0, 0, NULL
21 /* The colour indices used by STI are
22 * 0 - Black
23 * 1 - White
24 * 2 - Red
25 * 3 - Yellow/Brown
26 * 4 - Green
27 * 5 - Cyan
28 * 6 - Blue
29 * 7 - Magenta
31 * So we have the same colours as VGA (basically one bit each for R, G, B),
32 * but have to translate them, anyway. */
34 static u8 col_trans[8] = {
35 0, 6, 4, 5,
36 2, 7, 3, 1
39 #define c_fg(sti, c) col_trans[((c>> 8) & 7)]
40 #define c_bg(sti, c) col_trans[((c>>11) & 7)]
41 #define c_index(sti, c) (c&0xff)
43 static struct sti_init_flags default_init_flags = {
44 STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
47 void
48 sti_init_graph(struct sti_struct *sti)
50 struct sti_init_inptr_ext inptr_ext = {
51 0, { 0 }, 0, NULL
53 struct sti_init_inptr inptr = {
54 3, STI_PTR(&inptr_ext)
56 struct sti_init_outptr outptr = { 0 };
57 unsigned long flags;
58 s32 ret;
60 spin_lock_irqsave(&sti->lock, flags);
62 ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
63 &outptr, sti->glob_cfg);
65 spin_unlock_irqrestore(&sti->lock, flags);
67 sti->text_planes = outptr.text_planes;
70 static struct sti_conf_flags default_conf_flags = {
71 STI_WAIT, 0, NULL
74 void
75 sti_inq_conf(struct sti_struct *sti)
77 struct sti_conf_inptr inptr = { NULL };
78 struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
79 struct sti_conf_outptr outptr = {
80 ext_ptr: STI_PTR(&outptr_ext)
82 unsigned long flags;
83 s32 ret;
85 do {
86 spin_lock_irqsave(&sti->lock, flags);
87 ret = STI_CALL(sti->inq_conf, &default_conf_flags,
88 &inptr, &outptr, sti->glob_cfg);
89 spin_unlock_irqrestore(&sti->lock, flags);
90 } while(ret == 1);
93 void
94 sti_putc(struct sti_struct *sti, int c, int y, int x)
96 struct sti_font_inptr inptr = {
97 (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
98 x * sti_font_x(sti), y * sti_font_y(sti), NULL
100 struct sti_font_outptr outptr = {
101 0, NULL
103 s32 ret;
104 unsigned long flags;
106 do {
107 spin_lock_irqsave(&sti->lock, flags);
108 ret = STI_CALL(sti->font_unpmv, &default_font_flags,
109 &inptr, &outptr, sti->glob_cfg);
110 spin_unlock_irqrestore(&sti->lock, flags);
111 } while(ret == 1);
114 static struct sti_blkmv_flags clear_blkmv_flags = {
115 STI_WAIT, 1, 1, 0, 0, NULL
118 void
119 sti_set(struct sti_struct *sti, int src_y, int src_x,
120 int height, int width, u8 color)
122 struct sti_blkmv_inptr inptr = {
123 color, color,
124 src_x, src_y ,
125 src_x, src_y ,
126 width, height,
127 NULL
129 struct sti_blkmv_outptr outptr = { 0, NULL };
130 s32 ret = 0;
131 unsigned long flags;
133 do {
134 spin_lock_irqsave(&sti->lock, flags);
135 ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
136 &inptr, &outptr, sti->glob_cfg);
137 spin_unlock_irqrestore(&sti->lock, flags);
138 } while(ret == 1);
141 void
142 sti_clear(struct sti_struct *sti, int src_y, int src_x,
143 int height, int width)
145 struct sti_blkmv_inptr inptr = {
146 0, 0,
147 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
148 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
149 width * sti_font_x(sti), height* sti_font_y(sti),
150 NULL
152 struct sti_blkmv_outptr outptr = { 0, NULL };
153 s32 ret = 0;
154 unsigned long flags;
156 do {
157 spin_lock_irqsave(&sti->lock, flags);
158 ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
159 &inptr, &outptr, sti->glob_cfg);
160 spin_unlock_irqrestore(&sti->lock, flags);
161 } while(ret == 1);
164 static struct sti_blkmv_flags default_blkmv_flags = {
165 STI_WAIT, 0, 0, 0, 0, NULL
168 void
169 sti_bmove(struct sti_struct *sti, int src_y, int src_x,
170 int dst_y, int dst_x, int height, int width)
172 struct sti_blkmv_inptr inptr = {
173 0, 0,
174 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
175 dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
176 width * sti_font_x(sti), height* sti_font_y(sti),
177 NULL
179 struct sti_blkmv_outptr outptr = { 0, NULL };
180 s32 ret = 0;
181 unsigned long flags;
183 do {
184 spin_lock_irqsave(&sti->lock, flags);
185 ret = STI_CALL(sti->block_move, &default_blkmv_flags,
186 &inptr, &outptr, sti->glob_cfg);
187 spin_unlock_irqrestore(&sti->lock, flags);
188 } while(ret == 1);
192 static void __init
193 sti_rom_copy(unsigned long base, unsigned long offset,
194 unsigned long count, void *dest)
196 void *savedest = dest;
197 int savecount = count;
199 while(count >= 4) {
200 count -= 4;
201 *(u32 *)dest = gsc_readl(base + offset);
202 offset += 4;
203 dest += 4;
205 while(count) {
206 count--;
207 *(u8 *)dest = gsc_readb(base + offset);
208 offset++;
209 dest++;
211 __flush_dcache_range((unsigned long) dest, count);
212 __flush_icache_range((unsigned long) dest, count);
215 static void dump_sti_rom(struct sti_rom *rom)
217 printk("STI word mode ROM type %d\n", rom->type[3]);
218 printk(" supports %d monitors\n", rom->num_mons);
219 printk(" conforms to STI ROM spec revision %d.%02x\n",
220 rom->revno[0] >> 4, rom->revno[0] & 0x0f);
221 printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
222 rom->graphics_id[0],
223 rom->graphics_id[1],
224 rom->graphics_id[2],
225 rom->graphics_id[3],
226 rom->graphics_id[4],
227 rom->graphics_id[5],
228 rom->graphics_id[6],
229 rom->graphics_id[7]);
230 printk(" font start %08x\n", rom->font_start);
231 printk(" region list %08x\n", rom->region_list);
232 printk(" init_graph %08x\n", rom->init_graph);
233 printk(" alternate code type %d\n", rom->alt_code_type);
236 static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
237 struct sti_rom *raw_rom)
239 struct sti_rom_font *raw_font;
240 struct sti_cooked_font *cooked_font;
241 struct sti_rom_font *font_start;
243 cooked_font =
244 kmalloc(sizeof *cooked_font, GFP_KERNEL);
245 if(!cooked_font)
246 return;
248 cooked_rom->font_start = cooked_font;
250 raw_font = ((void *)raw_rom) + (raw_rom->font_start);
252 font_start = raw_font;
253 cooked_font->raw = raw_font;
255 while(raw_font->next_font) {
256 raw_font = ((void *)font_start) + (raw_font->next_font);
258 cooked_font->next_font =
259 kmalloc(sizeof *cooked_font, GFP_KERNEL);
260 if(!cooked_font->next_font)
261 return;
263 cooked_font = cooked_font->next_font;
265 cooked_font->raw = raw_font;
268 cooked_font->next_font = NULL;
271 static int font_index, font_height, font_width;
273 static int __init sti_font_setup(char *str)
275 char *x;
277 /* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style
278 * command lines. */
280 if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
281 font_height = simple_strtoul(str, NULL, 0);
282 font_width = simple_strtoul(x+1, NULL, 0);
283 } else {
284 font_index = simple_strtoul(str, NULL, 0);
287 return 0;
290 __setup("sti_font=", sti_font_setup);
292 static int __init sti_search_font(struct sti_cooked_rom *rom,
293 int height, int width)
295 struct sti_cooked_font *font;
296 int i = 0;
298 for(font = rom->font_start; font; font = font->next_font, i++) {
299 if((font->raw->width == width) && (font->raw->height == height))
300 return i;
303 return 0;
306 static struct sti_cooked_font * __init
307 sti_select_font(struct sti_cooked_rom *rom)
309 struct sti_cooked_font *font;
310 int i;
312 if(font_width && font_height)
313 font_index = sti_search_font(rom, font_height, font_width);
315 for(font = rom->font_start, i = font_index;
316 font && (i > 0);
317 font = font->next_font, i--);
319 if(font)
320 return font;
321 else
322 return rom->font_start;
325 static void __init
326 sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
328 printk( "monitor %d\n"
329 "in friendly mode: %d\n"
330 "power consumption %d watts\n"
331 "freq ref %d\n"
332 "sti_mem_addr %p\n",
333 cfg->curr_mon,
334 cfg->friendly_boot,
335 cfg->power,
336 cfg->freq_ref,
337 cfg->sti_mem_addr);
340 void __init
341 sti_dump_globcfg(struct sti_glob_cfg *glob_cfg)
343 printk( "%d text planes\n"
344 "%4d x %4d screen resolution\n"
345 "%4d x %4d offscreen\n"
346 "%4d x %4d layout\n"
347 "regions at %08x %08x %08x %08x\n"
348 "regions at %08x %08x %08x %08x\n"
349 "reent_lvl %d\n"
350 "save_addr %p\n",
351 glob_cfg->text_planes,
352 glob_cfg->onscreen_x, glob_cfg->onscreen_y,
353 glob_cfg->offscreen_x, glob_cfg->offscreen_y,
354 glob_cfg->total_x, glob_cfg->total_y,
355 glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
356 glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
357 glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
358 glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
359 glob_cfg->reent_lvl,
360 glob_cfg->save_addr);
361 sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
364 static void __init
365 sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
366 unsigned long rom_address)
368 struct sti_glob_cfg *glob_cfg;
369 struct sti_glob_cfg_ext *glob_cfg_ext;
370 void *save_addr;
371 void *sti_mem_addr;
373 glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
374 glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
375 save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
376 sti_mem_addr = kmalloc(1024, GFP_KERNEL);
378 if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
379 return;
381 memset(glob_cfg, 0, sizeof *glob_cfg);
382 memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
383 memset(save_addr, 0, 1024);
384 memset(sti_mem_addr, 0, 1024);
386 glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
387 glob_cfg->save_addr = STI_PTR(save_addr);
388 glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
389 glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
390 glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
391 glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
392 glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
393 glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
394 glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
395 glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
397 glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
399 sti->glob_cfg = STI_PTR(glob_cfg);
402 /* address is a pointer to a word mode or pci rom */
403 static struct sti_struct * __init
404 sti_read_rom(unsigned long address)
406 struct sti_struct *ret = NULL;
407 struct sti_cooked_rom *cooked = NULL;
408 struct sti_rom *raw = NULL;
409 unsigned long size;
411 ret = &default_sti;
413 if(!ret)
414 goto out_err;
416 cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
417 raw = kmalloc(sizeof *raw, GFP_KERNEL);
419 if(!(raw && cooked))
420 goto out_err;
422 /* reallocate raw */
423 sti_rom_copy(address, 0, sizeof *raw, raw);
425 dump_sti_rom(raw);
427 size = raw->last_addr;
428 /* kfree(raw); */
429 raw = kmalloc(size, GFP_KERNEL);
430 if(!raw)
431 goto out_err;
432 sti_rom_copy(address, 0, size, raw);
434 sti_cook_fonts(cooked, raw);
435 #if 0
436 sti_cook_regions(cooked, raw);
437 sti_cook_functions(cooked, raw);
438 #endif
440 if(raw->region_list) {
441 ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME */
443 memcpy(ret->regions, ((void *)raw)+raw->region_list, 32);
446 address = virt_to_phys(raw);
448 ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff);
449 ret->block_move = address+(raw->block_move & 0x03ffffff);
450 ret->init_graph = address+(raw->init_graph & 0x03ffffff);
451 ret->inq_conf = address+(raw->inq_conf & 0x03ffffff);
453 ret->rom = cooked;
454 ret->rom->raw = raw;
456 ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
458 return ret;
460 out_err:
461 if(raw)
462 kfree(raw);
463 if(cooked)
464 kfree(cooked);
466 return NULL;
469 static struct sti_struct * __init
470 sti_try_rom(unsigned long address, unsigned long hpa)
472 struct sti_struct *sti = NULL;
473 u16 sig;
475 test_rom:
476 /* if we can't read the ROM, bail out early. Not being able
477 * to read the hpa is okay, for romless sti */
478 if(pdc_add_valid((void*)address))
479 return NULL;
481 printk("found potential STI ROM at %08lx\n", address);
483 sig = le16_to_cpu(gsc_readw(address));
485 if((sig==0x55aa) || (sig==0xaa55)) {
486 address += le32_to_cpu(gsc_readl(address+8));
487 printk("sig %04x, PCI STI ROM at %08lx\n",
488 sig, address);
490 goto test_rom;
493 if((sig&0xff) == 0x01) {
494 printk("STI byte mode ROM at %08lx, ignored\n",
495 address);
497 sti = NULL;
500 if(sig == 0x0303) {
501 printk("STI word mode ROM at %08lx\n",
502 address);
504 sti = sti_read_rom(address);
507 if (!sti)
508 return NULL;
510 /* this is hacked. We need a better way to find out the HPA for
511 * romless STI (eg search for the graphics devices we know about
512 * by sversion) */
513 if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n");
514 if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n");
515 if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n");
516 if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n");
517 sti_init_glob_cfg(sti, hpa, address);
519 sti_init_graph(sti);
521 sti_inq_conf(sti);
522 sti_dump_globcfg(PTR_STI(sti->glob_cfg));
524 return sti;
527 static unsigned long sti_address;
528 static unsigned long sti_hpa;
530 /* XXX: should build a list of STI ROMs */
531 struct sti_struct * __init
532 sti_init_roms(void)
534 struct sti_struct *tmp = NULL, *sti = NULL;
536 /* handle the command line */
537 if (sti_address && sti_hpa) {
538 return sti_try_rom(sti_address, sti_hpa);
541 /* 712, 715, some other boxes don't have a separate STI ROM,
542 * but use part of the regular flash */
543 if (PAGE0->proc_sti) {
544 printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
545 if (!pdc_add_valid((void *)0xf9000000))
546 sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000);
547 else if (!pdc_add_valid((void *)0xf5000000))
548 sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000);
549 else if (!pdc_add_valid((void *)0xf7000000))
550 sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000);
551 else if (!pdc_add_valid((void *)0xfb000000))
552 sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000);
556 /* standard locations for GSC graphic devices */
557 if (!pdc_add_valid((void *)0xf4000000))
558 tmp = sti_try_rom(0xf4000000, 0xf4000000);
559 sti = tmp ? tmp : sti;
560 if (!pdc_add_valid((void *)0xf6000000))
561 tmp = sti_try_rom(0xf6000000, 0xf6000000);
562 sti = tmp ? tmp : sti;
563 if (!pdc_add_valid((void *)0xf8000000))
564 tmp = sti_try_rom(0xf8000000, 0xf8000000);
565 sti = tmp ? tmp : sti;
566 if (!pdc_add_valid((void *)0xfa000000))
567 tmp = sti_try_rom(0xfa000000, 0xfa000000);
568 sti = tmp ? tmp : sti;
570 return sti;
573 static int __init
574 sti_setup(char *str)
576 char *end;
578 if(strcmp(str, "pdc") == 0) {
579 sti_address = PAGE0->proc_sti;
581 return 1;
582 } else {
583 sti_address = simple_strtoul(str, &end, 16);
585 if((end == str) || (sti_address < 0xf0000000)) {
586 sti_address = 0;
587 return 0;
590 sti_hpa = sti_address;
592 return 1;
595 return 0;
598 __setup("sti=", sti_setup);