- Alan Cox: synch. PA-RISC arch and bitops cleanups
[davej-history.git] / drivers / video / sticore.c
blobbc3bf85f10bcddb511e9db64df59f2ed38c12cc6
1 #include <linux/config.h>
2 #include <linux/module.h>
3 #include <linux/types.h>
4 #include <linux/kernel.h>
5 #include <linux/malloc.h>
6 #include <linux/init.h>
8 #include <asm/uaccess.h>
9 #include <asm/pgalloc.h>
10 #include <asm/io.h>
12 #include "sti.h"
14 struct sti_struct default_sti = {
15 SPIN_LOCK_UNLOCKED,
18 static struct sti_font_flags default_font_flags = {
19 STI_WAIT, 0, 0, NULL
22 /* The colour indices used by STI are
23 * 0 - Black
24 * 1 - White
25 * 2 - Red
26 * 3 - Yellow/Brown
27 * 4 - Green
28 * 5 - Cyan
29 * 6 - Blue
30 * 7 - Magenta
32 * So we have the same colours as VGA (basically one bit each for R, G, B),
33 * but have to translate them, anyway. */
35 static u8 col_trans[8] = {
36 0, 6, 4, 5,
37 2, 7, 3, 1
40 #define c_fg(sti, c) col_trans[((c>> 8) & 7)]
41 #define c_bg(sti, c) col_trans[((c>>11) & 7)]
42 #define c_index(sti, c) (c&0xff)
44 static struct sti_init_flags default_init_flags = {
45 STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
48 void
49 sti_init_graph(struct sti_struct *sti)
51 struct sti_init_inptr_ext inptr_ext = {
52 0, { 0 }, 0, NULL
54 struct sti_init_inptr inptr = {
55 3, STI_PTR(&inptr_ext)
57 struct sti_init_outptr outptr = { 0 };
58 unsigned long flags;
59 s32 ret;
61 spin_lock_irqsave(&sti->lock, flags);
63 ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
64 &outptr, sti->glob_cfg);
66 spin_unlock_irqrestore(&sti->lock, flags);
68 sti->text_planes = outptr.text_planes;
71 static struct sti_conf_flags default_conf_flags = {
72 STI_WAIT, 0, NULL
75 void
76 sti_inq_conf(struct sti_struct *sti)
78 struct sti_conf_inptr inptr = { NULL };
79 struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL };
80 struct sti_conf_outptr outptr = {
81 ext_ptr: STI_PTR(&outptr_ext)
83 unsigned long flags;
84 s32 ret;
86 do {
87 spin_lock_irqsave(&sti->lock, flags);
88 ret = STI_CALL(sti->inq_conf, &default_conf_flags,
89 &inptr, &outptr, sti->glob_cfg);
90 spin_unlock_irqrestore(&sti->lock, flags);
91 } while(ret == 1);
94 void
95 sti_putc(struct sti_struct *sti, int c, int y, int x)
97 struct sti_font_inptr inptr = {
98 (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
99 x * sti_font_x(sti), y * sti_font_y(sti), NULL
101 struct sti_font_outptr outptr = {
102 0, NULL
104 s32 ret;
105 unsigned long flags;
107 do {
108 spin_lock_irqsave(&sti->lock, flags);
109 ret = STI_CALL(sti->font_unpmv, &default_font_flags,
110 &inptr, &outptr, sti->glob_cfg);
111 spin_unlock_irqrestore(&sti->lock, flags);
112 } while(ret == 1);
115 static struct sti_blkmv_flags clear_blkmv_flags = {
116 STI_WAIT, 1, 1, 0, 0, NULL
119 void
120 sti_set(struct sti_struct *sti, int src_y, int src_x,
121 int height, int width, u8 color)
123 struct sti_blkmv_inptr inptr = {
124 color, color,
125 src_x, src_y ,
126 src_x, src_y ,
127 width, height,
128 NULL
130 struct sti_blkmv_outptr outptr = { 0, NULL };
131 s32 ret = 0;
132 unsigned long flags;
134 do {
135 spin_lock_irqsave(&sti->lock, flags);
136 ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
137 &inptr, &outptr, sti->glob_cfg);
138 spin_unlock_irqrestore(&sti->lock, flags);
139 } while(ret == 1);
142 void
143 sti_clear(struct sti_struct *sti, int src_y, int src_x,
144 int height, int width)
146 struct sti_blkmv_inptr inptr = {
147 0, 0,
148 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
149 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
150 width * sti_font_x(sti), height* sti_font_y(sti),
151 NULL
153 struct sti_blkmv_outptr outptr = { 0, NULL };
154 s32 ret = 0;
155 unsigned long flags;
157 do {
158 spin_lock_irqsave(&sti->lock, flags);
159 ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
160 &inptr, &outptr, sti->glob_cfg);
161 spin_unlock_irqrestore(&sti->lock, flags);
162 } while(ret == 1);
165 static struct sti_blkmv_flags default_blkmv_flags = {
166 STI_WAIT, 0, 0, 0, 0, NULL
169 void
170 sti_bmove(struct sti_struct *sti, int src_y, int src_x,
171 int dst_y, int dst_x, int height, int width)
173 struct sti_blkmv_inptr inptr = {
174 0, 0,
175 src_x * sti_font_x(sti), src_y * sti_font_y(sti),
176 dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
177 width * sti_font_x(sti), height* sti_font_y(sti),
178 NULL
180 struct sti_blkmv_outptr outptr = { 0, NULL };
181 s32 ret = 0;
182 unsigned long flags;
184 do {
185 spin_lock_irqsave(&sti->lock, flags);
186 ret = STI_CALL(sti->block_move, &default_blkmv_flags,
187 &inptr, &outptr, sti->glob_cfg);
188 spin_unlock_irqrestore(&sti->lock, flags);
189 } while(ret == 1);
193 static void __init
194 sti_rom_copy(unsigned long base, unsigned long offset,
195 unsigned long count, void *dest)
197 void *savedest = dest;
198 int savecount = count;
200 while(count >= 4) {
201 count -= 4;
202 *(u32 *)dest = gsc_readl(base + offset);
203 offset += 4;
204 dest += 4;
206 while(count) {
207 count--;
208 *(u8 *)dest = gsc_readb(base + offset);
209 offset++;
210 dest++;
212 __flush_dcache_range((unsigned long) dest, count);
213 __flush_icache_range((unsigned long) dest, count);
216 static void dump_sti_rom(struct sti_rom *rom)
218 printk("STI word mode ROM type %d\n", rom->type[3]);
219 printk(" supports %d monitors\n", rom->num_mons);
220 printk(" conforms to STI ROM spec revision %d.%02x\n",
221 rom->revno[0] >> 4, rom->revno[0] & 0x0f);
222 printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
223 rom->graphics_id[0],
224 rom->graphics_id[1],
225 rom->graphics_id[2],
226 rom->graphics_id[3],
227 rom->graphics_id[4],
228 rom->graphics_id[5],
229 rom->graphics_id[6],
230 rom->graphics_id[7]);
231 printk(" font start %08x\n", rom->font_start);
232 printk(" region list %08x\n", rom->region_list);
233 printk(" init_graph %08x\n", rom->init_graph);
234 printk(" alternate code type %d\n", rom->alt_code_type);
237 static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
238 struct sti_rom *raw_rom)
240 struct sti_rom_font *raw_font;
241 struct sti_cooked_font *cooked_font;
242 struct sti_rom_font *font_start;
244 cooked_font =
245 kmalloc(sizeof *cooked_font, GFP_KERNEL);
246 if(!cooked_font)
247 return;
249 cooked_rom->font_start = cooked_font;
251 raw_font = ((void *)raw_rom) + (raw_rom->font_start);
253 font_start = raw_font;
254 cooked_font->raw = raw_font;
256 while(raw_font->next_font) {
257 raw_font = ((void *)font_start) + (raw_font->next_font);
259 cooked_font->next_font =
260 kmalloc(sizeof *cooked_font, GFP_KERNEL);
261 if(!cooked_font->next_font)
262 return;
264 cooked_font = cooked_font->next_font;
266 cooked_font->raw = raw_font;
269 cooked_font->next_font = NULL;
272 static int font_index, font_height, font_width;
274 static int __init sti_font_setup(char *str)
276 char *x;
278 /* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style
279 * command lines. */
281 if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
282 font_height = simple_strtoul(str, NULL, 0);
283 font_width = simple_strtoul(x+1, NULL, 0);
284 } else {
285 font_index = simple_strtoul(str, NULL, 0);
288 return 0;
291 __setup("sti_font=", sti_font_setup);
293 static int __init sti_search_font(struct sti_cooked_rom *rom,
294 int height, int width)
296 struct sti_cooked_font *font;
297 int i = 0;
299 for(font = rom->font_start; font; font = font->next_font, i++) {
300 if((font->raw->width == width) && (font->raw->height == height))
301 return i;
304 return 0;
307 static struct sti_cooked_font * __init
308 sti_select_font(struct sti_cooked_rom *rom)
310 struct sti_cooked_font *font;
311 int i;
313 if(font_width && font_height)
314 font_index = sti_search_font(rom, font_height, font_width);
316 for(font = rom->font_start, i = font_index;
317 font && (i > 0);
318 font = font->next_font, i--);
320 if(font)
321 return font;
322 else
323 return rom->font_start;
326 static void __init
327 sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
329 printk( "monitor %d\n"
330 "in friendly mode: %d\n"
331 "power consumption %d watts\n"
332 "freq ref %d\n"
333 "sti_mem_addr %p\n",
334 cfg->curr_mon,
335 cfg->friendly_boot,
336 cfg->power,
337 cfg->freq_ref,
338 cfg->sti_mem_addr);
341 void __init
342 sti_dump_globcfg(struct sti_glob_cfg *glob_cfg)
344 printk( "%d text planes\n"
345 "%4d x %4d screen resolution\n"
346 "%4d x %4d offscreen\n"
347 "%4d x %4d layout\n"
348 "regions at %08x %08x %08x %08x\n"
349 "regions at %08x %08x %08x %08x\n"
350 "reent_lvl %d\n"
351 "save_addr %p\n",
352 glob_cfg->text_planes,
353 glob_cfg->onscreen_x, glob_cfg->onscreen_y,
354 glob_cfg->offscreen_x, glob_cfg->offscreen_y,
355 glob_cfg->total_x, glob_cfg->total_y,
356 glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
357 glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
358 glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
359 glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
360 glob_cfg->reent_lvl,
361 glob_cfg->save_addr);
362 sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
365 static void __init
366 sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
367 unsigned long rom_address)
369 struct sti_glob_cfg *glob_cfg;
370 struct sti_glob_cfg_ext *glob_cfg_ext;
371 void *save_addr;
372 void *sti_mem_addr;
374 glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
375 glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
376 save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
377 sti_mem_addr = kmalloc(1024, GFP_KERNEL);
379 if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
380 return;
382 memset(glob_cfg, 0, sizeof *glob_cfg);
383 memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
384 memset(save_addr, 0, 1024);
385 memset(sti_mem_addr, 0, 1024);
387 glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
388 glob_cfg->save_addr = STI_PTR(save_addr);
389 glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
390 glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
391 glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
392 glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
393 glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
394 glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
395 glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
396 glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
398 glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
400 sti->glob_cfg = STI_PTR(glob_cfg);
403 /* address is a pointer to a word mode or pci rom */
404 static struct sti_struct * __init
405 sti_read_rom(unsigned long address)
407 struct sti_struct *ret = NULL;
408 struct sti_cooked_rom *cooked = NULL;
409 struct sti_rom *raw = NULL;
410 unsigned long size;
412 ret = &default_sti;
414 if(!ret)
415 goto out_err;
417 cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
418 raw = kmalloc(sizeof *raw, GFP_KERNEL);
420 if(!(raw && cooked))
421 goto out_err;
423 /* reallocate raw */
424 sti_rom_copy(address, 0, sizeof *raw, raw);
426 dump_sti_rom(raw);
428 size = raw->last_addr;
429 /* kfree(raw); */
430 raw = kmalloc(size, GFP_KERNEL);
431 if(!raw)
432 goto out_err;
433 sti_rom_copy(address, 0, size, raw);
435 sti_cook_fonts(cooked, raw);
436 #if 0
437 sti_cook_regions(cooked, raw);
438 sti_cook_functions(cooked, raw);
439 #endif
441 if(raw->region_list) {
442 ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME */
444 memcpy(ret->regions, ((void *)raw)+raw->region_list, 32);
447 address = virt_to_phys(raw);
449 ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff);
450 ret->block_move = address+(raw->block_move & 0x03ffffff);
451 ret->init_graph = address+(raw->init_graph & 0x03ffffff);
452 ret->inq_conf = address+(raw->inq_conf & 0x03ffffff);
454 ret->rom = cooked;
455 ret->rom->raw = raw;
457 ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
459 return ret;
461 out_err:
462 if(raw)
463 kfree(raw);
464 if(cooked)
465 kfree(cooked);
467 return NULL;
470 static struct sti_struct * __init
471 sti_try_rom(unsigned long address, unsigned long hpa)
473 struct sti_struct *sti = NULL;
474 u16 sig;
476 test_rom:
477 /* if we can't read the ROM, bail out early. Not being able
478 * to read the hpa is okay, for romless sti */
479 if(pdc_add_valid((void*)address))
480 return NULL;
482 printk("found potential STI ROM at %08lx\n", address);
484 sig = le16_to_cpu(gsc_readw(address));
486 if((sig==0x55aa) || (sig==0xaa55)) {
487 address += le32_to_cpu(gsc_readl(address+8));
488 printk("sig %04x, PCI STI ROM at %08lx\n",
489 sig, address);
491 goto test_rom;
494 if((sig&0xff) == 0x01) {
495 printk("STI byte mode ROM at %08lx, ignored\n",
496 address);
498 sti = NULL;
501 if(sig == 0x0303) {
502 printk("STI word mode ROM at %08lx\n",
503 address);
505 sti = sti_read_rom(address);
508 if (!sti)
509 return NULL;
511 /* this is hacked. We need a better way to find out the HPA for
512 * romless STI (eg search for the graphics devices we know about
513 * by sversion) */
514 if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n");
515 if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n");
516 if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n");
517 if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n");
518 sti_init_glob_cfg(sti, hpa, address);
520 sti_init_graph(sti);
522 sti_inq_conf(sti);
523 sti_dump_globcfg(PTR_STI(sti->glob_cfg));
525 return sti;
528 static unsigned long sti_address;
529 static unsigned long sti_hpa;
531 /* XXX: should build a list of STI ROMs */
532 struct sti_struct * __init
533 sti_init_roms(void)
535 struct sti_struct *tmp = NULL, *sti = NULL;
537 /* handle the command line */
538 if (sti_address && sti_hpa) {
539 return sti_try_rom(sti_address, sti_hpa);
542 /* 712, 715, some other boxes don't have a separate STI ROM,
543 * but use part of the regular flash */
544 if (PAGE0->proc_sti) {
545 printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
546 if (!pdc_add_valid((void *)0xf9000000))
547 sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000);
548 else if (!pdc_add_valid((void *)0xf5000000))
549 sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000);
550 else if (!pdc_add_valid((void *)0xf7000000))
551 sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000);
552 else if (!pdc_add_valid((void *)0xfb000000))
553 sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000);
557 /* standard locations for GSC graphic devices */
558 if (!pdc_add_valid((void *)0xf4000000))
559 tmp = sti_try_rom(0xf4000000, 0xf4000000);
560 sti = tmp ? tmp : sti;
561 if (!pdc_add_valid((void *)0xf6000000))
562 tmp = sti_try_rom(0xf6000000, 0xf6000000);
563 sti = tmp ? tmp : sti;
564 if (!pdc_add_valid((void *)0xf8000000))
565 tmp = sti_try_rom(0xf8000000, 0xf8000000);
566 sti = tmp ? tmp : sti;
567 if (!pdc_add_valid((void *)0xfa000000))
568 tmp = sti_try_rom(0xfa000000, 0xfa000000);
569 sti = tmp ? tmp : sti;
571 return sti;
574 static int __init
575 sti_setup(char *str)
577 char *end;
579 if(strcmp(str, "pdc") == 0) {
580 sti_address = PAGE0->proc_sti;
582 return 1;
583 } else {
584 sti_address = simple_strtoul(str, &end, 16);
586 if((end == str) || (sti_address < 0xf0000000)) {
587 sti_address = 0;
588 return 0;
591 sti_hpa = sti_address;
593 return 1;
596 return 0;
599 __setup("sti=", sti_setup);