Mercurial > mplayer.hg
comparison drivers/radeon/radeonfb.c @ 1911:89313cfc8fec
Initial import of Ani Joshi's radeonfb-0.0.9
author | nick |
---|---|
date | Tue, 18 Sep 2001 16:12:34 +0000 |
parents | |
children | 33afcb62fc64 |
comparison
equal
deleted
inserted
replaced
1910:06fa415119bc | 1911:89313cfc8fec |
---|---|
1 /* | |
2 * drivers/video/radeonfb.c | |
3 * framebuffer driver for ATI Radeon chipset video boards | |
4 * | |
5 * Copyright 2000 Ani Joshi <ajoshi@unixbox.com> | |
6 * | |
7 * | |
8 * ChangeLog: | |
9 * 2000-08-03 initial version 0.0.1 | |
10 * 2000-09-10 more bug fixes, public release 0.0.5 | |
11 * 2001-02-19 mode bug fixes, 0.0.7 | |
12 * 2001-07-05 fixed scrolling issues, engine initialization, | |
13 * and minor mode tweaking, 0.0.9 | |
14 * | |
15 * | |
16 * Special thanks to ATI DevRel team for their hardware donations. | |
17 * | |
18 */ | |
19 | |
20 | |
21 #define RADEON_VERSION "0.0.9" | |
22 | |
23 | |
24 #include <linux/config.h> | |
25 #include <linux/module.h> | |
26 #include <linux/kernel.h> | |
27 #include <linux/errno.h> | |
28 #include <linux/string.h> | |
29 #include <linux/mm.h> | |
30 #include <linux/tty.h> | |
31 #include <linux/malloc.h> | |
32 #include <linux/delay.h> | |
33 #include <linux/fb.h> | |
34 #include <linux/console.h> | |
35 #include <linux/selection.h> | |
36 #include <linux/ioport.h> | |
37 #include <linux/init.h> | |
38 #include <linux/pci.h> | |
39 | |
40 #include <asm/io.h> | |
41 | |
42 #include <video/fbcon.h> | |
43 #include <video/fbcon-cfb8.h> | |
44 #include <video/fbcon-cfb16.h> | |
45 #include <video/fbcon-cfb24.h> | |
46 #include <video/fbcon-cfb32.h> | |
47 | |
48 #include "radeon.h" | |
49 | |
50 | |
51 #define DEBUG 0 | |
52 | |
53 #if DEBUG | |
54 #define RTRACE printk | |
55 #else | |
56 #define RTRACE if(0) printk | |
57 #endif | |
58 | |
59 | |
60 | |
61 enum radeon_chips { | |
62 RADEON_QD, | |
63 RADEON_QE, | |
64 RADEON_QF, | |
65 RADEON_QG | |
66 }; | |
67 | |
68 | |
69 static struct pci_device_id radeonfb_pci_table[] __devinitdata = { | |
70 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD}, | |
71 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE}, | |
72 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF}, | |
73 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG}, | |
74 { 0, } | |
75 }; | |
76 MODULE_DEVICE_TABLE(pci, radeonfb_pci_table); | |
77 | |
78 | |
79 typedef struct { | |
80 u16 reg; | |
81 u32 val; | |
82 } reg_val; | |
83 | |
84 | |
85 /* these common regs are cleared before mode setting so they do not | |
86 * interfere with anything | |
87 */ | |
88 reg_val common_regs[] = { | |
89 { OVR_CLR, 0 }, | |
90 { OVR_WID_LEFT_RIGHT, 0 }, | |
91 { OVR_WID_TOP_BOTTOM, 0 }, | |
92 { OV0_SCALE_CNTL, 0 }, | |
93 { SUBPIC_CNTL, 0 }, | |
94 { VIPH_CONTROL, 0 }, | |
95 { I2C_CNTL_1, 0 }, | |
96 { GEN_INT_CNTL, 0 }, | |
97 { CAP0_TRIG_CNTL, 0 }, | |
98 }; | |
99 | |
100 #define COMMON_REGS_SIZE = (sizeof(common_regs)/sizeof(common_regs[0])) | |
101 | |
102 typedef struct { | |
103 u8 clock_chip_type; | |
104 u8 struct_size; | |
105 u8 accelerator_entry; | |
106 u8 VGA_entry; | |
107 u16 VGA_table_offset; | |
108 u16 POST_table_offset; | |
109 u16 XCLK; | |
110 u16 MCLK; | |
111 u8 num_PLL_blocks; | |
112 u8 size_PLL_blocks; | |
113 u16 PCLK_ref_freq; | |
114 u16 PCLK_ref_divider; | |
115 u32 PCLK_min_freq; | |
116 u32 PCLK_max_freq; | |
117 u16 MCLK_ref_freq; | |
118 u16 MCLK_ref_divider; | |
119 u32 MCLK_min_freq; | |
120 u32 MCLK_max_freq; | |
121 u16 XCLK_ref_freq; | |
122 u16 XCLK_ref_divider; | |
123 u32 XCLK_min_freq; | |
124 u32 XCLK_max_freq; | |
125 } __attribute__ ((packed)) PLL_BLOCK; | |
126 | |
127 | |
128 struct pll_info { | |
129 int ppll_max; | |
130 int ppll_min; | |
131 int xclk; | |
132 int ref_div; | |
133 int ref_clk; | |
134 }; | |
135 | |
136 | |
137 struct ram_info { | |
138 int ml; | |
139 int mb; | |
140 int trcd; | |
141 int trp; | |
142 int twr; | |
143 int cl; | |
144 int tr2w; | |
145 int loop_latency; | |
146 int rloop; | |
147 }; | |
148 | |
149 | |
150 struct radeon_regs { | |
151 u32 crtc_h_total_disp; | |
152 u32 crtc_h_sync_strt_wid; | |
153 u32 crtc_v_total_disp; | |
154 u32 crtc_v_sync_strt_wid; | |
155 u32 crtc_pitch; | |
156 u32 flags; | |
157 u32 pix_clock; | |
158 int xres, yres; | |
159 int bpp; | |
160 u32 crtc_gen_cntl; | |
161 u32 crtc_ext_cntl; | |
162 u32 dac_cntl; | |
163 u32 dda_config; | |
164 u32 dda_on_off; | |
165 u32 ppll_div_3; | |
166 u32 ppll_ref_div; | |
167 }; | |
168 | |
169 | |
170 struct radeonfb_info { | |
171 struct fb_info info; | |
172 | |
173 struct radeon_regs state; | |
174 struct radeon_regs init_state; | |
175 | |
176 char name[10]; | |
177 char ram_type[12]; | |
178 | |
179 u32 mmio_base_phys; | |
180 u32 fb_base_phys; | |
181 | |
182 u32 mmio_base; | |
183 u32 fb_base; | |
184 | |
185 struct pci_dev *pdev; | |
186 | |
187 struct display disp; | |
188 int currcon; | |
189 struct display *currcon_display; | |
190 | |
191 struct { u8 red, green, blue, pad; } palette[256]; | |
192 | |
193 int chipset; | |
194 int video_ram; | |
195 u8 rev; | |
196 int pitch, bpp, depth; | |
197 int xres, yres, pixclock; | |
198 | |
199 u32 dp_gui_master_cntl; | |
200 | |
201 struct pll_info pll; | |
202 int pll_output_freq, post_div, fb_div; | |
203 | |
204 struct ram_info ram; | |
205 | |
206 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) | |
207 union { | |
208 #if defined(FBCON_HAS_CFB16) | |
209 u_int16_t cfb16[16]; | |
210 #endif | |
211 #if defined(FBCON_HAS_CFB32) | |
212 u_int32_t cfb32[16]; | |
213 #endif | |
214 } con_cmap; | |
215 #endif | |
216 }; | |
217 | |
218 | |
219 static struct fb_var_screeninfo radeonfb_default_var = { | |
220 640, 480, 640, 480, 0, 0, 8, 0, | |
221 {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, | |
222 0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2, | |
223 0, FB_VMODE_NONINTERLACED | |
224 }; | |
225 | |
226 | |
227 /* | |
228 * IO macros | |
229 */ | |
230 | |
231 #define INREG8(addr) readb((rinfo->mmio_base)+addr) | |
232 #define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr) | |
233 #define INREG(addr) readl((rinfo->mmio_base)+addr) | |
234 #define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr) | |
235 | |
236 #define OUTPLL(addr,val) OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000001f) | 0x00000080); \ | |
237 OUTREG(CLOCK_CNTL_DATA, val) | |
238 #define OUTPLLP(addr,val,mask) \ | |
239 do { \ | |
240 unsigned int _tmp = INPLL(addr); \ | |
241 _tmp &= (mask); \ | |
242 _tmp |= (val); \ | |
243 OUTPLL(addr, _tmp); \ | |
244 } while (0) | |
245 | |
246 #define OUTREGP(addr,val,mask) \ | |
247 do { \ | |
248 unsigned int _tmp = INREG(addr); \ | |
249 _tmp &= (mask); \ | |
250 _tmp |= (val); \ | |
251 OUTREG(addr, _tmp); \ | |
252 } while (0) | |
253 | |
254 | |
255 static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr) | |
256 { | |
257 OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000001f); | |
258 return (INREG(CLOCK_CNTL_DATA)); | |
259 } | |
260 | |
261 #define INPLL(addr) _INPLL(rinfo, addr) | |
262 | |
263 | |
264 /* | |
265 * 2D engine routines | |
266 */ | |
267 | |
268 static __inline__ void radeon_engine_flush (struct radeonfb_info *rinfo) | |
269 { | |
270 int i; | |
271 | |
272 /* initiate flush */ | |
273 OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, | |
274 ~RB2D_DC_FLUSH_ALL); | |
275 | |
276 for (i=0; i < 2000000; i++) { | |
277 if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) | |
278 break; | |
279 } | |
280 } | |
281 | |
282 | |
283 static __inline__ void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries) | |
284 { | |
285 int i; | |
286 | |
287 for (i=0; i<2000000; i++) | |
288 if ((INREG(RBBM_STATUS) & 0x7f) >= entries) | |
289 return; | |
290 } | |
291 | |
292 | |
293 static __inline__ void _radeon_engine_idle (struct radeonfb_info *rinfo) | |
294 { | |
295 int i; | |
296 | |
297 /* ensure FIFO is empty before waiting for idle */ | |
298 _radeon_fifo_wait (rinfo, 64); | |
299 | |
300 for (i=0; i<2000000; i++) { | |
301 if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) { | |
302 radeon_engine_flush (rinfo); | |
303 return; | |
304 } | |
305 } | |
306 } | |
307 | |
308 | |
309 #define radeon_engine_idle() _radeon_engine_idle(rinfo) | |
310 #define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries) | |
311 | |
312 | |
313 | |
314 /* | |
315 * helper routines | |
316 */ | |
317 | |
318 static __inline__ u32 radeon_get_dstbpp(u16 depth) | |
319 { | |
320 switch (depth) { | |
321 case 8: | |
322 return DST_8BPP; | |
323 case 15: | |
324 return DST_15BPP; | |
325 case 16: | |
326 return DST_16BPP; | |
327 case 32: | |
328 return DST_32BPP; | |
329 default: | |
330 return 0; | |
331 } | |
332 } | |
333 | |
334 | |
335 static void _radeon_engine_reset(struct radeonfb_info *rinfo) | |
336 { | |
337 u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset; | |
338 | |
339 radeon_engine_flush (rinfo); | |
340 | |
341 clock_cntl_index = INREG(CLOCK_CNTL_INDEX); | |
342 mclk_cntl = INPLL(MCLK_CNTL); | |
343 | |
344 OUTPLL(MCLK_CNTL, (mclk_cntl | | |
345 FORCEON_MCLKA | | |
346 FORCEON_MCLKB | | |
347 FORCEON_YCLKA | | |
348 FORCEON_YCLKB | | |
349 FORCEON_MC | | |
350 FORCEON_AIC)); | |
351 rbbm_soft_reset = INREG(RBBM_SOFT_RESET); | |
352 | |
353 OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset | | |
354 SOFT_RESET_CP | | |
355 SOFT_RESET_HI | | |
356 SOFT_RESET_SE | | |
357 SOFT_RESET_RE | | |
358 SOFT_RESET_PP | | |
359 SOFT_RESET_E2 | | |
360 SOFT_RESET_RB | | |
361 SOFT_RESET_HDP); | |
362 INREG(RBBM_SOFT_RESET); | |
363 OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32) | |
364 ~(SOFT_RESET_CP | | |
365 SOFT_RESET_HI | | |
366 SOFT_RESET_SE | | |
367 SOFT_RESET_RE | | |
368 SOFT_RESET_PP | | |
369 SOFT_RESET_E2 | | |
370 SOFT_RESET_RB | | |
371 SOFT_RESET_HDP)); | |
372 INREG(RBBM_SOFT_RESET); | |
373 | |
374 OUTPLL(MCLK_CNTL, mclk_cntl); | |
375 OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); | |
376 OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); | |
377 | |
378 return; | |
379 } | |
380 | |
381 #define radeon_engine_reset() _radeon_engine_reset(rinfo) | |
382 | |
383 | |
384 static __inline__ u8 radeon_get_post_div_bitval(int post_div) | |
385 { | |
386 switch (post_div) { | |
387 case 1: | |
388 return 0x00; | |
389 case 2: | |
390 return 0x01; | |
391 case 3: | |
392 return 0x04; | |
393 case 4: | |
394 return 0x02; | |
395 case 6: | |
396 return 0x06; | |
397 case 8: | |
398 return 0x03; | |
399 case 12: | |
400 return 0x07; | |
401 default: | |
402 return 0x02; | |
403 } | |
404 } | |
405 | |
406 | |
407 | |
408 static __inline__ int round_div(int num, int den) | |
409 { | |
410 return (num + (den / 2)) / den; | |
411 } | |
412 | |
413 | |
414 | |
415 static __inline__ int min_bits_req(int val) | |
416 { | |
417 int bits_req = 0; | |
418 | |
419 if (val == 0) | |
420 bits_req = 1; | |
421 | |
422 while (val) { | |
423 val >>= 1; | |
424 bits_req++; | |
425 } | |
426 | |
427 return (bits_req); | |
428 } | |
429 | |
430 | |
431 static __inline__ int _max(int val1, int val2) | |
432 { | |
433 if (val1 >= val2) | |
434 return val1; | |
435 else | |
436 return val2; | |
437 } | |
438 | |
439 | |
440 | |
441 /* | |
442 * globals | |
443 */ | |
444 | |
445 static char fontname[40] __initdata; | |
446 static char *mode_option __initdata; | |
447 static char noaccel __initdata = 0; | |
448 | |
449 #ifdef FBCON_HAS_CFB8 | |
450 static struct display_switch fbcon_radeon8; | |
451 #endif | |
452 | |
453 | |
454 /* | |
455 * prototypes | |
456 */ | |
457 | |
458 static int radeonfb_get_fix (struct fb_fix_screeninfo *fix, int con, | |
459 struct fb_info *info); | |
460 static int radeonfb_get_var (struct fb_var_screeninfo *var, int con, | |
461 struct fb_info *info); | |
462 static int radeonfb_set_var (struct fb_var_screeninfo *var, int con, | |
463 struct fb_info *info); | |
464 static int radeonfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, | |
465 struct fb_info *info); | |
466 static int radeonfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, | |
467 struct fb_info *info); | |
468 static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con, | |
469 struct fb_info *info); | |
470 static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, | |
471 unsigned long arg, int con, struct fb_info *info); | |
472 static int radeonfb_switch (int con, struct fb_info *info); | |
473 static int radeonfb_updatevar (int con, struct fb_info *info); | |
474 static void radeonfb_blank (int blank, struct fb_info *info); | |
475 static int radeon_get_cmap_len (const struct fb_var_screeninfo *var); | |
476 static int radeon_getcolreg (unsigned regno, unsigned *red, unsigned *green, | |
477 unsigned *blue, unsigned *transp, | |
478 struct fb_info *info); | |
479 static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, | |
480 unsigned blue, unsigned transp, struct fb_info *info); | |
481 static void radeon_set_dispsw (struct radeonfb_info *rinfo); | |
482 static void radeon_save_state (struct radeonfb_info *rinfo, | |
483 struct radeon_regs *save); | |
484 static void radeon_engine_init (struct radeonfb_info *rinfo); | |
485 static void radeon_load_video_mode (struct radeonfb_info *rinfo, | |
486 struct fb_var_screeninfo *mode); | |
487 static void radeon_write_mode (struct radeonfb_info *rinfo, | |
488 struct radeon_regs *mode); | |
489 static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo); | |
490 static int __devinit radeon_init_disp (struct radeonfb_info *rinfo); | |
491 static int radeon_init_disp_var (struct radeonfb_info *rinfo); | |
492 static int radeonfb_pci_register (struct pci_dev *pdev, | |
493 const struct pci_device_id *ent); | |
494 static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev); | |
495 static char *radeon_find_rom(struct radeonfb_info *rinfo); | |
496 static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg); | |
497 | |
498 | |
499 static struct fb_ops radeon_fb_ops = { | |
500 fb_get_fix: radeonfb_get_fix, | |
501 fb_get_var: radeonfb_get_var, | |
502 fb_set_var: radeonfb_set_var, | |
503 fb_get_cmap: radeonfb_get_cmap, | |
504 fb_set_cmap: radeonfb_set_cmap, | |
505 fb_pan_display: radeonfb_pan_display, | |
506 fb_ioctl: radeonfb_ioctl, | |
507 }; | |
508 | |
509 | |
510 static struct pci_driver radeonfb_driver = { | |
511 name: "radeonfb", | |
512 id_table: radeonfb_pci_table, | |
513 probe: radeonfb_pci_register, | |
514 remove: radeonfb_pci_unregister, | |
515 }; | |
516 | |
517 | |
518 int __init radeonfb_init (void) | |
519 { | |
520 return pci_module_init (&radeonfb_driver); | |
521 } | |
522 | |
523 | |
524 void __exit radeonfb_exit (void) | |
525 { | |
526 pci_unregister_driver (&radeonfb_driver); | |
527 } | |
528 | |
529 | |
530 int __init radeonfb_setup (char *options) | |
531 { | |
532 char *this_opt; | |
533 | |
534 if (!options || !*options) | |
535 return 0; | |
536 | |
537 for (this_opt = strtok (options, ","); this_opt; | |
538 this_opt = strtok (NULL, ",")) { | |
539 if (!strncmp (this_opt, "font:", 5)) { | |
540 char *p; | |
541 int i; | |
542 | |
543 p = this_opt + 5; | |
544 for (i=0; i<sizeof (fontname) - 1; i++) | |
545 if (!*p || *p == ' ' || *p == ',') | |
546 break; | |
547 memcpy(fontname, this_opt + 5, i); | |
548 } else if (!strncmp(this_opt, "noaccel", 7)) { | |
549 noaccel = 1; | |
550 } | |
551 else mode_option = this_opt; | |
552 } | |
553 | |
554 return 0; | |
555 } | |
556 | |
557 #ifdef MODULE | |
558 module_init(radeonfb_init); | |
559 module_exit(radeonfb_exit); | |
560 #endif | |
561 | |
562 | |
563 MODULE_AUTHOR("Ani Joshi"); | |
564 MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset"); | |
565 | |
566 | |
567 | |
568 static int radeonfb_pci_register (struct pci_dev *pdev, | |
569 const struct pci_device_id *ent) | |
570 { | |
571 struct radeonfb_info *rinfo; | |
572 u32 tmp; | |
573 int i, j; | |
574 char *bios_seg = NULL; | |
575 | |
576 rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL); | |
577 if (!rinfo) { | |
578 printk ("radeonfb: could not allocate memory\n"); | |
579 return -ENODEV; | |
580 } | |
581 | |
582 memset (rinfo, 0, sizeof (struct radeonfb_info)); | |
583 | |
584 /* enable device */ | |
585 { | |
586 int err; | |
587 | |
588 if ((err = pci_enable_device(pdev))) { | |
589 printk("radeonfb: cannot enable device\n"); | |
590 kfree (rinfo); | |
591 return -ENODEV; | |
592 } | |
593 } | |
594 | |
595 /* set base addrs */ | |
596 rinfo->fb_base_phys = pci_resource_start (pdev, 0); | |
597 rinfo->mmio_base_phys = pci_resource_start (pdev, 2); | |
598 | |
599 /* request the mem regions */ | |
600 if (!request_mem_region (rinfo->fb_base_phys, | |
601 pci_resource_len(pdev, 0), "radeonfb")) { | |
602 printk ("radeonfb: cannot reserve FB region\n"); | |
603 kfree (rinfo); | |
604 return -ENODEV; | |
605 } | |
606 | |
607 if (!request_mem_region (rinfo->mmio_base_phys, | |
608 pci_resource_len(pdev, 2), "radeonfb")) { | |
609 printk ("radeonfb: cannot reserve MMIO region\n"); | |
610 release_mem_region (rinfo->fb_base_phys, | |
611 pci_resource_len(pdev, 0)); | |
612 kfree (rinfo); | |
613 return -ENODEV; | |
614 } | |
615 | |
616 /* map the regions */ | |
617 rinfo->mmio_base = (u32) ioremap (rinfo->mmio_base_phys, | |
618 RADEON_REGSIZE); | |
619 if (!rinfo->mmio_base) { | |
620 printk ("radeonfb: cannot map MMIO\n"); | |
621 release_mem_region (rinfo->mmio_base_phys, | |
622 pci_resource_len(pdev, 2)); | |
623 release_mem_region (rinfo->fb_base_phys, | |
624 pci_resource_len(pdev, 0)); | |
625 kfree (rinfo); | |
626 return -ENODEV; | |
627 } | |
628 | |
629 /* chipset */ | |
630 switch (pdev->device) { | |
631 case PCI_DEVICE_ID_RADEON_QD: | |
632 strcpy(rinfo->name, "Radeon QD "); | |
633 break; | |
634 case PCI_DEVICE_ID_RADEON_QE: | |
635 strcpy(rinfo->name, "Radeon QE "); | |
636 break; | |
637 case PCI_DEVICE_ID_RADEON_QF: | |
638 strcpy(rinfo->name, "Radeon QF "); | |
639 break; | |
640 case PCI_DEVICE_ID_RADEON_QG: | |
641 strcpy(rinfo->name, "Radeon QG "); | |
642 break; | |
643 default: | |
644 return -ENODEV; | |
645 } | |
646 | |
647 /* framebuffer size */ | |
648 tmp = INREG(CONFIG_MEMSIZE); | |
649 | |
650 /* mem size is bits [28:0], mask off the rest */ | |
651 rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK; | |
652 | |
653 /* ram type */ | |
654 tmp = INREG(MEM_SDRAM_MODE_REG); | |
655 switch ((MEM_CFG_TYPE & tmp) >> 30) { | |
656 case 0: | |
657 /* SDR SGRAM (2:1) */ | |
658 strcpy(rinfo->ram_type, "SDR SGRAM"); | |
659 rinfo->ram.ml = 4; | |
660 rinfo->ram.mb = 4; | |
661 rinfo->ram.trcd = 1; | |
662 rinfo->ram.trp = 2; | |
663 rinfo->ram.twr = 1; | |
664 rinfo->ram.cl = 2; | |
665 rinfo->ram.loop_latency = 16; | |
666 rinfo->ram.rloop = 16; | |
667 | |
668 break; | |
669 case 1: | |
670 /* DDR SGRAM */ | |
671 strcpy(rinfo->ram_type, "DDR SGRAM"); | |
672 rinfo->ram.ml = 4; | |
673 rinfo->ram.mb = 4; | |
674 rinfo->ram.trcd = 3; | |
675 rinfo->ram.trp = 3; | |
676 rinfo->ram.twr = 2; | |
677 rinfo->ram.cl = 3; | |
678 rinfo->ram.tr2w = 1; | |
679 rinfo->ram.loop_latency = 16; | |
680 rinfo->ram.rloop = 16; | |
681 | |
682 break; | |
683 default: | |
684 /* 64-bit SDR SGRAM */ | |
685 strcpy(rinfo->ram_type, "SDR SGRAM 64"); | |
686 rinfo->ram.ml = 4; | |
687 rinfo->ram.mb = 8; | |
688 rinfo->ram.trcd = 3; | |
689 rinfo->ram.trp = 3; | |
690 rinfo->ram.twr = 1; | |
691 rinfo->ram.cl = 3; | |
692 rinfo->ram.tr2w = 1; | |
693 rinfo->ram.loop_latency = 17; | |
694 rinfo->ram.rloop = 17; | |
695 | |
696 break; | |
697 } | |
698 | |
699 bios_seg = radeon_find_rom(rinfo); | |
700 radeon_get_pllinfo(rinfo, bios_seg); | |
701 | |
702 printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d\n", | |
703 rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); | |
704 | |
705 RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); | |
706 | |
707 rinfo->fb_base = (u32) ioremap (rinfo->fb_base_phys, | |
708 rinfo->video_ram); | |
709 if (!rinfo->fb_base) { | |
710 printk ("radeonfb: cannot map FB\n"); | |
711 iounmap ((void*)rinfo->mmio_base); | |
712 release_mem_region (rinfo->mmio_base_phys, | |
713 pci_resource_len(pdev, 2)); | |
714 release_mem_region (rinfo->fb_base_phys, | |
715 pci_resource_len(pdev, 0)); | |
716 kfree (rinfo); | |
717 return -ENODEV; | |
718 } | |
719 | |
720 /* XXX turn off accel for now, blts aren't working right */ | |
721 noaccel = 1; | |
722 | |
723 /* set all the vital stuff */ | |
724 radeon_set_fbinfo (rinfo); | |
725 | |
726 /* save current mode regs before we switch into the new one | |
727 * so we can restore this upon __exit | |
728 */ | |
729 radeon_save_state (rinfo, &rinfo->init_state); | |
730 | |
731 /* init palette */ | |
732 for (i=0; i<16; i++) { | |
733 j = color_table[i]; | |
734 rinfo->palette[i].red = default_red[j]; | |
735 rinfo->palette[i].green = default_grn[j]; | |
736 rinfo->palette[i].blue = default_blu[j]; | |
737 } | |
738 | |
739 pdev->driver_data = rinfo; | |
740 | |
741 if (register_framebuffer ((struct fb_info *) rinfo) < 0) { | |
742 printk ("radeonfb: could not register framebuffer\n"); | |
743 iounmap ((void*)rinfo->fb_base); | |
744 iounmap ((void*)rinfo->mmio_base); | |
745 release_mem_region (rinfo->mmio_base_phys, | |
746 pci_resource_len(pdev, 2)); | |
747 release_mem_region (rinfo->fb_base_phys, | |
748 pci_resource_len(pdev, 0)); | |
749 kfree (rinfo); | |
750 return -ENODEV; | |
751 } | |
752 | |
753 if (!noaccel) { | |
754 /* initialize the engine */ | |
755 radeon_engine_init (rinfo); | |
756 } | |
757 | |
758 printk ("radeonfb: ATI Radeon %s %d MB\n", rinfo->ram_type, | |
759 (rinfo->video_ram/(1024*1024))); | |
760 | |
761 return 0; | |
762 } | |
763 | |
764 | |
765 | |
766 static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) | |
767 { | |
768 struct radeonfb_info *rinfo = pdev->driver_data; | |
769 | |
770 if (!rinfo) | |
771 return; | |
772 | |
773 /* restore original state */ | |
774 radeon_write_mode (rinfo, &rinfo->init_state); | |
775 | |
776 unregister_framebuffer ((struct fb_info *) rinfo); | |
777 | |
778 iounmap ((void*)rinfo->mmio_base); | |
779 iounmap ((void*)rinfo->fb_base); | |
780 | |
781 release_mem_region (rinfo->mmio_base_phys, | |
782 pci_resource_len(pdev, 2)); | |
783 release_mem_region (rinfo->fb_base_phys, | |
784 pci_resource_len(pdev, 0)); | |
785 | |
786 kfree (rinfo); | |
787 } | |
788 | |
789 | |
790 | |
791 static char *radeon_find_rom(struct radeonfb_info *rinfo) | |
792 { | |
793 u32 segstart; | |
794 char *rom_base; | |
795 char *rom; | |
796 int stage; | |
797 int i; | |
798 char aty_rom_sig[] = "761295520"; | |
799 char radeon_sig[] = "RG6"; | |
800 | |
801 #if defined(__i386__) | |
802 for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { | |
803 stage = 1; | |
804 | |
805 rom_base = (char *)ioremap(segstart, 0x1000); | |
806 | |
807 if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) | |
808 stage = 2; | |
809 | |
810 | |
811 if (stage != 2) { | |
812 iounmap(rom_base); | |
813 continue; | |
814 } | |
815 | |
816 rom = rom_base; | |
817 | |
818 for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) { | |
819 if (aty_rom_sig[0] == *rom) | |
820 if (strncmp(aty_rom_sig, rom, | |
821 strlen(aty_rom_sig)) == 0) | |
822 stage = 3; | |
823 rom++; | |
824 } | |
825 if (stage != 3) { | |
826 iounmap(rom_base); | |
827 continue; | |
828 } | |
829 rom = rom_base; | |
830 | |
831 for (i = 0; (i < 512) && (stage != 4); i++) { | |
832 if (radeon_sig[0] == *rom) | |
833 if (strncmp(radeon_sig, rom, | |
834 strlen(radeon_sig)) == 0) | |
835 stage = 4; | |
836 rom++; | |
837 } | |
838 if (stage != 4) { | |
839 iounmap(rom_base); | |
840 continue; | |
841 } | |
842 | |
843 return rom_base; | |
844 } | |
845 #endif | |
846 return NULL; | |
847 } | |
848 | |
849 | |
850 | |
851 static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg) | |
852 { | |
853 void *bios_header; | |
854 void *header_ptr; | |
855 u16 bios_header_offset, pll_info_offset; | |
856 PLL_BLOCK pll; | |
857 | |
858 if (bios_seg) { | |
859 bios_header = bios_seg + 0x48L; | |
860 header_ptr = bios_header; | |
861 | |
862 bios_header_offset = readw(header_ptr); | |
863 bios_header = bios_seg + bios_header_offset; | |
864 bios_header += 0x30; | |
865 | |
866 header_ptr = bios_header; | |
867 pll_info_offset = readw(header_ptr); | |
868 header_ptr = bios_seg + pll_info_offset; | |
869 | |
870 memcpy_fromio(&pll, header_ptr, 50); | |
871 | |
872 rinfo->pll.xclk = (u32)pll.XCLK; | |
873 rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq; | |
874 rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider; | |
875 rinfo->pll.ppll_min = pll.PCLK_min_freq; | |
876 rinfo->pll.ppll_max = pll.PCLK_max_freq; | |
877 } else { | |
878 /* no BIOS or BIOS not found, use defaults */ | |
879 | |
880 rinfo->pll.ppll_max = 35000; | |
881 rinfo->pll.ppll_min = 12000; | |
882 rinfo->pll.xclk = 16600; | |
883 rinfo->pll.ref_div = 67; | |
884 rinfo->pll.ref_clk = 2700; | |
885 } | |
886 } | |
887 | |
888 static void radeon_engine_init (struct radeonfb_info *rinfo) | |
889 { | |
890 u32 temp; | |
891 | |
892 /* disable 3D engine */ | |
893 OUTREG(RB3D_CNTL, 0); | |
894 | |
895 radeon_engine_reset (); | |
896 | |
897 radeon_fifo_wait (1); | |
898 OUTREG(DSTCACHE_MODE, 0); | |
899 | |
900 /* XXX */ | |
901 rinfo->pitch = ((rinfo->xres * (rinfo->depth / 8) + 0x3f)) >> 6; | |
902 | |
903 radeon_fifo_wait (1); | |
904 temp = INREG(DEFAULT_PITCH_OFFSET); | |
905 OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | | |
906 (rinfo->pitch << 0x16))); | |
907 | |
908 radeon_fifo_wait (1); | |
909 OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); | |
910 | |
911 radeon_fifo_wait (1); | |
912 OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | | |
913 DEFAULT_SC_BOTTOM_MAX)); | |
914 | |
915 temp = radeon_get_dstbpp(rinfo->depth); | |
916 rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); | |
917 radeon_fifo_wait (1); | |
918 OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | | |
919 GMC_BRUSH_SOLID_COLOR | | |
920 GMC_SRC_DATATYPE_COLOR)); | |
921 | |
922 radeon_fifo_wait (7); | |
923 | |
924 /* clear line drawing regs */ | |
925 OUTREG(DST_LINE_START, 0); | |
926 OUTREG(DST_LINE_END, 0); | |
927 | |
928 /* set brush color regs */ | |
929 OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); | |
930 OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); | |
931 | |
932 /* set source color regs */ | |
933 OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); | |
934 OUTREG(DP_SRC_BKGD_CLR, 0x00000000); | |
935 | |
936 /* default write mask */ | |
937 OUTREG(DP_WRITE_MSK, 0xffffffff); | |
938 | |
939 radeon_engine_idle (); | |
940 } | |
941 | |
942 | |
943 | |
944 static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) | |
945 { | |
946 struct fb_info *info; | |
947 | |
948 info = &rinfo->info; | |
949 | |
950 strcpy (info->modename, rinfo->name); | |
951 info->node = -1; | |
952 info->flags = FBINFO_FLAG_DEFAULT; | |
953 info->fbops = &radeon_fb_ops; | |
954 info->display_fg = NULL; | |
955 strncpy (info->fontname, fontname, sizeof (info->fontname)); | |
956 info->fontname[sizeof (info->fontname) - 1] = 0; | |
957 info->changevar = NULL; | |
958 info->switch_con = radeonfb_switch; | |
959 info->updatevar = radeonfb_updatevar; | |
960 info->blank = radeonfb_blank; | |
961 | |
962 if (radeon_init_disp (rinfo) < 0) | |
963 return -1; | |
964 | |
965 return 0; | |
966 } | |
967 | |
968 | |
969 | |
970 static int __devinit radeon_init_disp (struct radeonfb_info *rinfo) | |
971 { | |
972 struct fb_info *info; | |
973 struct display *disp; | |
974 | |
975 info = &rinfo->info; | |
976 disp = &rinfo->disp; | |
977 | |
978 disp->var = radeonfb_default_var; | |
979 info->disp = disp; | |
980 | |
981 radeon_set_dispsw (rinfo); | |
982 | |
983 if (noaccel) | |
984 disp->scrollmode = SCROLL_YREDRAW; | |
985 else | |
986 disp->scrollmode = 0; | |
987 | |
988 rinfo->currcon_display = disp; | |
989 | |
990 if ((radeon_init_disp_var (rinfo)) < 0) | |
991 return -1; | |
992 | |
993 return 0; | |
994 } | |
995 | |
996 | |
997 | |
998 static int radeon_init_disp_var (struct radeonfb_info *rinfo) | |
999 { | |
1000 #ifndef MODULE | |
1001 if (mode_option) | |
1002 fb_find_mode (&rinfo->disp.var, &rinfo->info, mode_option, | |
1003 NULL, 0, NULL, 8); | |
1004 else | |
1005 #endif | |
1006 fb_find_mode (&rinfo->disp.var, &rinfo->info, "640x480-8@60", | |
1007 NULL, 0, NULL, 0); | |
1008 | |
1009 if (noaccel) | |
1010 rinfo->disp.var.accel_flags &= ~FB_ACCELF_TEXT; | |
1011 else | |
1012 rinfo->disp.var.accel_flags |= FB_ACCELF_TEXT; | |
1013 | |
1014 return 0; | |
1015 } | |
1016 | |
1017 | |
1018 | |
1019 static void radeon_set_dispsw (struct radeonfb_info *rinfo) | |
1020 { | |
1021 struct display *disp = &rinfo->disp; | |
1022 int accel; | |
1023 | |
1024 accel = disp->var.accel_flags & FB_ACCELF_TEXT; | |
1025 | |
1026 disp->dispsw_data = NULL; | |
1027 | |
1028 disp->screen_base = (char*)rinfo->fb_base; | |
1029 disp->type = FB_TYPE_PACKED_PIXELS; | |
1030 disp->type_aux = 0; | |
1031 disp->ypanstep = 1; | |
1032 disp->ywrapstep = 0; | |
1033 disp->can_soft_blank = 1; | |
1034 disp->inverse = 0; | |
1035 | |
1036 rinfo->depth = disp->var.bits_per_pixel; | |
1037 switch (disp->var.bits_per_pixel) { | |
1038 #ifdef FBCON_HAS_CFB8 | |
1039 case 8: | |
1040 disp->dispsw = accel ? &fbcon_radeon8 : &fbcon_cfb8; | |
1041 disp->visual = FB_VISUAL_PSEUDOCOLOR; | |
1042 disp->line_length = disp->var.xres_virtual; | |
1043 break; | |
1044 #endif | |
1045 #ifdef FBCON_HAS_CFB16 | |
1046 case 16: | |
1047 disp->dispsw = &fbcon_cfb16; | |
1048 disp->dispsw_data = &rinfo->con_cmap.cfb16; | |
1049 disp->visual = FB_VISUAL_DIRECTCOLOR; | |
1050 disp->line_length = disp->var.xres_virtual * 2; | |
1051 break; | |
1052 #endif | |
1053 #ifdef FBCON_HAS_CFB32 | |
1054 case 32: | |
1055 disp->dispsw = &fbcon_cfb32; | |
1056 disp->dispsw_data = &rinfo->con_cmap.cfb32; | |
1057 disp->visual = FB_VISUAL_DIRECTCOLOR; | |
1058 disp->line_length = disp->var.xres_virtual * 4; | |
1059 break; | |
1060 #endif | |
1061 default: | |
1062 printk ("radeonfb: setting fbcon_dummy renderer\n"); | |
1063 disp->dispsw = &fbcon_dummy; | |
1064 } | |
1065 | |
1066 return; | |
1067 } | |
1068 | |
1069 | |
1070 | |
1071 /* | |
1072 * fb ops | |
1073 */ | |
1074 | |
1075 static int radeonfb_get_fix (struct fb_fix_screeninfo *fix, int con, | |
1076 struct fb_info *info) | |
1077 { | |
1078 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1079 struct display *disp; | |
1080 | |
1081 disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; | |
1082 | |
1083 memset (fix, 0, sizeof (struct fb_fix_screeninfo)); | |
1084 strcpy (fix->id, rinfo->name); | |
1085 | |
1086 fix->smem_start = rinfo->fb_base_phys; | |
1087 fix->smem_len = rinfo->video_ram; | |
1088 | |
1089 fix->type = disp->type; | |
1090 fix->type_aux = disp->type_aux; | |
1091 fix->visual = disp->visual; | |
1092 | |
1093 fix->xpanstep = 1; | |
1094 fix->ypanstep = 1; | |
1095 fix->ywrapstep = 0; | |
1096 | |
1097 fix->line_length = disp->line_length; | |
1098 | |
1099 fix->mmio_start = rinfo->mmio_base_phys; | |
1100 fix->mmio_len = RADEON_REGSIZE; | |
1101 if (noaccel) | |
1102 fix->accel = FB_ACCEL_NONE; | |
1103 else | |
1104 fix->accel = 40; /* XXX */ | |
1105 | |
1106 return 0; | |
1107 } | |
1108 | |
1109 | |
1110 | |
1111 static int radeonfb_get_var (struct fb_var_screeninfo *var, int con, | |
1112 struct fb_info *info) | |
1113 { | |
1114 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1115 | |
1116 *var = (con < 0) ? rinfo->disp.var : fb_display[con].var; | |
1117 | |
1118 return 0; | |
1119 } | |
1120 | |
1121 | |
1122 | |
1123 static int radeonfb_set_var (struct fb_var_screeninfo *var, int con, | |
1124 struct fb_info *info) | |
1125 { | |
1126 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1127 struct display *disp; | |
1128 struct fb_var_screeninfo v; | |
1129 int nom, den, i, accel; | |
1130 unsigned chgvar = 0; | |
1131 static struct { | |
1132 int xres, yres; | |
1133 } modes[] = { | |
1134 { | |
1135 1600, 1280}, { | |
1136 1280, 1024}, { | |
1137 1024, 768}, { | |
1138 800, 600}, { | |
1139 640, 480}, { | |
1140 -1, -1} | |
1141 }; | |
1142 | |
1143 disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; | |
1144 | |
1145 accel = var->accel_flags & FB_ACCELF_TEXT; | |
1146 | |
1147 if (con >= 0) { | |
1148 chgvar = ((disp->var.xres != var->xres) || | |
1149 (disp->var.yres != var->yres) || | |
1150 (disp->var.xres_virtual != var->xres_virtual) || | |
1151 (disp->var.yres_virtual != var->yres_virtual) || | |
1152 memcmp (&disp->var.red, &var->red, sizeof (var->red)) || | |
1153 memcmp (&disp->var.green, &var->green, sizeof (var->green)) || | |
1154 memcmp (&disp->var.blue, &var->blue, sizeof (var->blue))); | |
1155 } | |
1156 | |
1157 memcpy (&v, var, sizeof (v)); | |
1158 | |
1159 switch (v.bits_per_pixel) { | |
1160 #ifdef FBCON_HAS_CFB8 | |
1161 case 8: | |
1162 v.bits_per_pixel = 8; | |
1163 disp->dispsw = accel ? &fbcon_radeon8 : &fbcon_cfb8; | |
1164 nom = den = 1; | |
1165 disp->line_length = v.xres_virtual; | |
1166 disp->visual = FB_VISUAL_PSEUDOCOLOR; | |
1167 v.red.offset = v.green.offset = v.blue.offset = 0; | |
1168 v.red.length = v.green.length = v.blue.length = 8; | |
1169 break; | |
1170 #endif | |
1171 | |
1172 #ifdef FBCON_HAS_CFB16 | |
1173 case 16: | |
1174 v.bits_per_pixel = 16; | |
1175 disp->dispsw = &fbcon_cfb16; | |
1176 disp->dispsw_data = &rinfo->con_cmap.cfb16; | |
1177 nom = 2; | |
1178 den = 1; | |
1179 disp->line_length = v.xres_virtual * 2; | |
1180 disp->visual = FB_VISUAL_DIRECTCOLOR; | |
1181 v.red.offset = 11; | |
1182 v.green.offset = 5; | |
1183 v.blue.offset = 0; | |
1184 v.red.length = 5; | |
1185 v.green.length = 6; | |
1186 v.blue.length = 5; | |
1187 break; | |
1188 #endif | |
1189 | |
1190 #ifdef FBCON_HAS_CFB32 | |
1191 case 32: | |
1192 v.bits_per_pixel = 32; | |
1193 disp->dispsw = &fbcon_cfb32; | |
1194 disp->dispsw_data = rinfo->con_cmap.cfb32; | |
1195 nom = 4; | |
1196 den = 1; | |
1197 disp->line_length = v.xres_virtual * 4; | |
1198 disp->visual = FB_VISUAL_DIRECTCOLOR; | |
1199 v.red.offset = 16; | |
1200 v.green.offset = 8; | |
1201 v.blue.offset = 0; | |
1202 v.red.length = v.blue.length = v.green.length = 8; | |
1203 break; | |
1204 #endif | |
1205 default: | |
1206 printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", | |
1207 var->xres, var->yres, var->bits_per_pixel); | |
1208 return -EINVAL; | |
1209 } | |
1210 | |
1211 if (v.xres * nom / den * v.yres > (rinfo->video_ram)) { | |
1212 printk ("radeonfb: mode %dx%dx%d rejected, not enough video ram\n", | |
1213 var->xres, var->yres, var->bits_per_pixel); | |
1214 return -EINVAL; | |
1215 } | |
1216 | |
1217 if (v.xres_virtual == -1 && v.yres_virtual == -1) { | |
1218 printk ("radeonfb: using maximum available virtual resolution\n"); | |
1219 for (i = 0; modes[i].xres != -1; i++) { | |
1220 if (modes[i].xres * nom / den * modes[i].yres < (rinfo->video_ram/2)) | |
1221 break; | |
1222 } | |
1223 if (modes[i].xres == -1) { | |
1224 printk ("radeonfb: could not find a virtual res\n"); | |
1225 return -EINVAL; | |
1226 } | |
1227 v.xres_virtual = modes[i].xres; | |
1228 v.yres_virtual = modes[i].yres; | |
1229 | |
1230 printk ("radeonfb: virtual resolution set to maximum of %dx%d\n", | |
1231 v.xres_virtual, v.yres_virtual); | |
1232 } | |
1233 | |
1234 if (v.xoffset < 0) | |
1235 v.xoffset = 0; | |
1236 if (v.yoffset < 0) | |
1237 v.yoffset = 0; | |
1238 | |
1239 if (v.xoffset > v.xres_virtual - v.xres) | |
1240 v.xoffset = v.xres_virtual - v.xres - 1; | |
1241 | |
1242 if (v.yoffset > v.yres_virtual - v.yres) | |
1243 v.yoffset = v.yres_virtual - v.yres - 1; | |
1244 | |
1245 v.red.msb_right = v.green.msb_right = v.blue.msb_right = | |
1246 v.transp.offset = v.transp.length = | |
1247 v.transp.msb_right = 0; | |
1248 | |
1249 switch (v.activate & FB_ACTIVATE_MASK) { | |
1250 case FB_ACTIVATE_TEST: | |
1251 return 0; | |
1252 case FB_ACTIVATE_NXTOPEN: | |
1253 case FB_ACTIVATE_NOW: | |
1254 break; | |
1255 default: | |
1256 return -EINVAL; | |
1257 } | |
1258 | |
1259 disp->type = FB_TYPE_PACKED_PIXELS; | |
1260 | |
1261 memcpy (&disp->var, &v, sizeof (v)); | |
1262 | |
1263 radeon_load_video_mode (rinfo, &v); | |
1264 | |
1265 if (chgvar && info && info->changevar) | |
1266 info->changevar (con); | |
1267 | |
1268 return 0; | |
1269 } | |
1270 | |
1271 | |
1272 | |
1273 static int radeonfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, | |
1274 struct fb_info *info) | |
1275 { | |
1276 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1277 struct display *disp; | |
1278 | |
1279 disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; | |
1280 | |
1281 if (con == rinfo->currcon) { | |
1282 int rc = fb_get_cmap (cmap, kspc, radeon_getcolreg, info); | |
1283 return rc; | |
1284 } else if (disp->cmap.len) | |
1285 fb_copy_cmap (&disp->cmap, cmap, kspc ? 0 : 2); | |
1286 else | |
1287 fb_copy_cmap (fb_default_cmap (radeon_get_cmap_len (&disp->var)), | |
1288 cmap, kspc ? 0 : 2); | |
1289 | |
1290 return 0; | |
1291 } | |
1292 | |
1293 | |
1294 | |
1295 static int radeonfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, | |
1296 struct fb_info *info) | |
1297 { | |
1298 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1299 struct display *disp; | |
1300 unsigned int cmap_len; | |
1301 | |
1302 disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; | |
1303 | |
1304 cmap_len = radeon_get_cmap_len (&disp->var); | |
1305 if (disp->cmap.len != cmap_len) { | |
1306 int err = fb_alloc_cmap (&disp->cmap, cmap_len, 0); | |
1307 if (err) | |
1308 return err; | |
1309 } | |
1310 | |
1311 if (con == rinfo->currcon) { | |
1312 int rc = fb_set_cmap (cmap, kspc, radeon_setcolreg, info); | |
1313 return rc; | |
1314 } else | |
1315 fb_copy_cmap (cmap, &disp->cmap, kspc ? 0 : 1); | |
1316 | |
1317 return 0; | |
1318 } | |
1319 | |
1320 | |
1321 | |
1322 static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con, | |
1323 struct fb_info *info) | |
1324 { | |
1325 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1326 struct display *disp; | |
1327 unsigned int base; | |
1328 | |
1329 disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; | |
1330 | |
1331 if (var->xoffset > (var->xres_virtual - var->xres)) | |
1332 return -EINVAL; | |
1333 if (var->yoffset > (var->yres_virtual - var->yres)) | |
1334 return -EINVAL; | |
1335 | |
1336 if (var->vmode & FB_VMODE_YWRAP) { | |
1337 if (var->yoffset < 0 || | |
1338 var->yoffset >= disp->var.yres_virtual || | |
1339 var->xoffset ) | |
1340 return -EINVAL; | |
1341 } else { | |
1342 if (var->xoffset + disp->var.xres > disp->var.xres_virtual || | |
1343 var->yoffset + disp->var.yres > disp->var.yres_virtual) | |
1344 return -EINVAL; | |
1345 } | |
1346 | |
1347 base = var->yoffset * disp->line_length + var->xoffset; | |
1348 | |
1349 disp->var.xoffset = var->xoffset; | |
1350 disp->var.yoffset = var->yoffset; | |
1351 | |
1352 if (var->vmode & FB_VMODE_YWRAP) | |
1353 disp->var.vmode |= FB_VMODE_YWRAP; | |
1354 else | |
1355 disp->var.vmode &= ~FB_VMODE_YWRAP; | |
1356 | |
1357 return 0; | |
1358 } | |
1359 | |
1360 | |
1361 | |
1362 static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, | |
1363 unsigned long arg, int con, struct fb_info *info) | |
1364 { | |
1365 return -EINVAL; | |
1366 } | |
1367 | |
1368 | |
1369 | |
1370 static int radeonfb_switch (int con, struct fb_info *info) | |
1371 { | |
1372 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1373 struct display *disp; | |
1374 struct fb_cmap *cmap; | |
1375 int switchcon = 0; | |
1376 | |
1377 disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; | |
1378 | |
1379 if (rinfo->currcon >= 0) { | |
1380 cmap = &(rinfo->currcon_display->cmap); | |
1381 if (cmap->len) | |
1382 fb_get_cmap (cmap, 1, radeon_getcolreg, info); | |
1383 } | |
1384 | |
1385 if ((disp->var.xres != rinfo->xres) || | |
1386 (disp->var.yres != rinfo->yres) || | |
1387 (disp->var.pixclock != rinfo->pixclock) || | |
1388 (disp->var.bits_per_pixel != rinfo->depth)) | |
1389 switchcon = 1; | |
1390 | |
1391 if (switchcon) { | |
1392 rinfo->currcon = con; | |
1393 rinfo->currcon_display = disp; | |
1394 disp->var.activate = FB_ACTIVATE_NOW; | |
1395 | |
1396 radeonfb_set_var (&disp->var, con, info); | |
1397 radeon_set_dispsw (rinfo); | |
1398 } | |
1399 | |
1400 return 0; | |
1401 } | |
1402 | |
1403 | |
1404 | |
1405 static int radeonfb_updatevar (int con, struct fb_info *info) | |
1406 { | |
1407 int rc; | |
1408 | |
1409 rc = (con < 0) ? -EINVAL : radeonfb_pan_display (&fb_display[con].var, | |
1410 con, info); | |
1411 | |
1412 return rc; | |
1413 } | |
1414 | |
1415 static void radeonfb_blank (int blank, struct fb_info *info) | |
1416 { | |
1417 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1418 u8 mode = 0; | |
1419 | |
1420 switch (blank) { | |
1421 case 0: | |
1422 /* unblank */ | |
1423 mode = 0; | |
1424 break; | |
1425 case 1: | |
1426 /* blank */ | |
1427 mode = ((INREG8(CRTC_EXT_CNTL + 1) & 3) | 4); | |
1428 break; | |
1429 case 2: | |
1430 case 3: | |
1431 case 4: | |
1432 mode = blank | 4; | |
1433 break; | |
1434 } | |
1435 | |
1436 OUTREG8(CRTC_EXT_CNTL + 1, mode); | |
1437 } | |
1438 | |
1439 | |
1440 | |
1441 static int radeon_get_cmap_len (const struct fb_var_screeninfo *var) | |
1442 { | |
1443 int rc = 16; /* reasonable default */ | |
1444 | |
1445 switch (var->bits_per_pixel) { | |
1446 case 8: | |
1447 rc = 256; | |
1448 break; | |
1449 case 16: | |
1450 rc = 64; | |
1451 break; | |
1452 default: | |
1453 rc = 32; | |
1454 break; | |
1455 } | |
1456 | |
1457 return rc; | |
1458 } | |
1459 | |
1460 | |
1461 | |
1462 static int radeon_getcolreg (unsigned regno, unsigned *red, unsigned *green, | |
1463 unsigned *blue, unsigned *transp, | |
1464 struct fb_info *info) | |
1465 { | |
1466 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1467 | |
1468 if (regno > 255) | |
1469 return 1; | |
1470 | |
1471 *red = (rinfo->palette[regno].red<<8) | rinfo->palette[regno].red; | |
1472 *green = (rinfo->palette[regno].green<<8) | rinfo->palette[regno].green; | |
1473 *blue = (rinfo->palette[regno].blue<<8) | rinfo->palette[regno].blue; | |
1474 *transp = 0; | |
1475 | |
1476 return 0; | |
1477 } | |
1478 | |
1479 | |
1480 | |
1481 static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, | |
1482 unsigned blue, unsigned transp, struct fb_info *info) | |
1483 { | |
1484 struct radeonfb_info *rinfo = (struct radeonfb_info *) info; | |
1485 u32 pindex, col; | |
1486 | |
1487 if (regno > 255) | |
1488 return 1; | |
1489 | |
1490 red >>= 8; | |
1491 green >>= 8; | |
1492 blue >>= 8; | |
1493 rinfo->palette[regno].red = red; | |
1494 rinfo->palette[regno].green = green; | |
1495 rinfo->palette[regno].blue = blue; | |
1496 | |
1497 /* init gamma for hicolor */ | |
1498 if ((rinfo->depth > 8) && (regno == 0)) { | |
1499 int i; | |
1500 u32 tmp; | |
1501 | |
1502 for (i=0; i<255; i++) { | |
1503 OUTREG(PALETTE_INDEX, i); | |
1504 tmp = (i << 16) | (i << 8) | i; | |
1505 radeon_fifo_wait(32); | |
1506 OUTREG(PALETTE_DATA, tmp); | |
1507 } | |
1508 } | |
1509 | |
1510 /* default */ | |
1511 pindex = regno; | |
1512 col = (red << 16) | (green << 8) | blue; | |
1513 | |
1514 if (rinfo->depth == 16) { | |
1515 pindex = regno << 3; | |
1516 | |
1517 if ((rinfo->depth == 16) && (regno >= 32)) { | |
1518 pindex -= 252; | |
1519 | |
1520 col = (rinfo->palette[regno >> 1].red << 16) | | |
1521 (green << 8) | | |
1522 (rinfo->palette[regno >> 1].blue); | |
1523 } else { | |
1524 col = (red << 16) | (green << 8) | blue; | |
1525 } | |
1526 } | |
1527 | |
1528 OUTREG8(PALETTE_INDEX, pindex); | |
1529 radeon_fifo_wait(32); | |
1530 OUTREG(PALETTE_DATA, col); | |
1531 | |
1532 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) | |
1533 if (regno < 32) { | |
1534 switch (rinfo->depth) { | |
1535 #ifdef FBCON_HAS_CFB16 | |
1536 case 16: | |
1537 rinfo->con_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | | |
1538 regno; | |
1539 break; | |
1540 #endif | |
1541 #ifdef FBCON_HAS_CFB32 | |
1542 case 32: { | |
1543 u32 i; | |
1544 | |
1545 i = (regno << 8) | regno; | |
1546 rinfo->con_cmap.cfb32[regno] = (i << 16) | i; | |
1547 break; | |
1548 } | |
1549 #endif | |
1550 } | |
1551 } | |
1552 #endif | |
1553 return 0; | |
1554 } | |
1555 | |
1556 | |
1557 | |
1558 static void radeon_save_state (struct radeonfb_info *rinfo, | |
1559 struct radeon_regs *save) | |
1560 { | |
1561 save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL); | |
1562 save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL); | |
1563 save->dac_cntl = INREG(DAC_CNTL); | |
1564 save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP); | |
1565 save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID); | |
1566 save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP); | |
1567 save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID); | |
1568 save->crtc_pitch = INREG(CRTC_PITCH); | |
1569 } | |
1570 | |
1571 | |
1572 | |
1573 static void radeon_load_video_mode (struct radeonfb_info *rinfo, | |
1574 struct fb_var_screeninfo *mode) | |
1575 { | |
1576 struct radeon_regs newmode; | |
1577 int hTotal, vTotal, hSyncStart, hSyncEnd, | |
1578 hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; | |
1579 u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; | |
1580 u32 dotClock = 1000000000 / mode->pixclock, | |
1581 sync, h_sync_pol, v_sync_pol; | |
1582 int freq = dotClock / 10; /* x 100 */ | |
1583 int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise; | |
1584 int useable_precision, roff, ron; | |
1585 int min_bits, format = 0; | |
1586 int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; | |
1587 | |
1588 rinfo->xres = mode->xres; | |
1589 rinfo->yres = mode->yres; | |
1590 rinfo->pixclock = mode->pixclock; | |
1591 | |
1592 hSyncStart = mode->xres + mode->right_margin; | |
1593 hSyncEnd = hSyncStart + mode->hsync_len; | |
1594 hTotal = hSyncEnd + mode->left_margin; | |
1595 | |
1596 vSyncStart = mode->yres + mode->lower_margin; | |
1597 vSyncEnd = vSyncStart + mode->vsync_len; | |
1598 vTotal = vSyncEnd + mode->upper_margin; | |
1599 | |
1600 sync = mode->sync; | |
1601 h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; | |
1602 v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; | |
1603 | |
1604 RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", | |
1605 hSyncStart, hSyncEnd, hTotal); | |
1606 RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", | |
1607 vSyncStart, vSyncEnd, vTotal); | |
1608 | |
1609 hsync_wid = (hSyncEnd - hSyncStart) / 8; | |
1610 vsync_wid = vSyncEnd - vSyncStart; | |
1611 if (hsync_wid == 0) | |
1612 hsync_wid = 1; | |
1613 else if (hsync_wid > 0x3f) /* max */ | |
1614 hsync_wid = 0x3f; | |
1615 | |
1616 if (vsync_wid == 0) | |
1617 vsync_wid = 1; | |
1618 else if (vsync_wid > 0x1f) /* max */ | |
1619 vsync_wid = 0x1f; | |
1620 | |
1621 if (mode->sync & FB_SYNC_HOR_HIGH_ACT) | |
1622 hSyncPol = 1; | |
1623 else | |
1624 hSyncPol = 0; | |
1625 | |
1626 if (mode->sync & FB_SYNC_VERT_HIGH_ACT) | |
1627 vSyncPol = 1; | |
1628 else | |
1629 vSyncPol = 0; | |
1630 | |
1631 cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; | |
1632 | |
1633 switch (mode->bits_per_pixel) { | |
1634 case 8: | |
1635 format = DST_8BPP; | |
1636 bytpp = 1; | |
1637 break; | |
1638 case 16: | |
1639 format = DST_16BPP; | |
1640 bytpp = 2; | |
1641 break; | |
1642 case 24: | |
1643 format = DST_24BPP; | |
1644 bytpp = 3; | |
1645 break; | |
1646 case 32: | |
1647 format = DST_32BPP; | |
1648 bytpp = 4; | |
1649 break; | |
1650 } | |
1651 | |
1652 hsync_fudge = hsync_adj_tab[format-1]; | |
1653 hsync_start = hSyncStart - 8 + hsync_fudge; | |
1654 | |
1655 newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | | |
1656 (format << 8); | |
1657 | |
1658 newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; | |
1659 | |
1660 newmode.dac_cntl = INREG(DAC_CNTL) | DAC_MASK_ALL | DAC_VGA_ADR_EN | | |
1661 DAC_8BIT_EN; | |
1662 | |
1663 newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0xffff) | | |
1664 (((mode->xres / 8) - 1) << 16)); | |
1665 | |
1666 newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | | |
1667 (hsync_wid << 16) | (hSyncPol << 23)); | |
1668 | |
1669 newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) | | |
1670 ((mode->yres - 1) << 16); | |
1671 | |
1672 newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | | |
1673 (vsync_wid << 16) | (vSyncPol << 23)); | |
1674 | |
1675 newmode.crtc_pitch = (mode->xres >> 3); | |
1676 | |
1677 rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f) | |
1678 & ~(0x3f)) / 64; | |
1679 | |
1680 RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", | |
1681 newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid); | |
1682 RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", | |
1683 newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid); | |
1684 | |
1685 newmode.xres = mode->xres; | |
1686 newmode.yres = mode->yres; | |
1687 | |
1688 rinfo->bpp = mode->bits_per_pixel; | |
1689 | |
1690 if (freq > rinfo->pll.ppll_max) | |
1691 freq = rinfo->pll.ppll_max; | |
1692 if (freq*12 < rinfo->pll.ppll_min) | |
1693 freq = rinfo->pll.ppll_min / 12; | |
1694 | |
1695 { | |
1696 struct { | |
1697 int divider; | |
1698 int bitvalue; | |
1699 } *post_div, | |
1700 post_divs[] = { | |
1701 { 1, 0 }, | |
1702 { 2, 1 }, | |
1703 { 4, 2 }, | |
1704 { 8, 3 }, | |
1705 { 3, 4 }, | |
1706 { 16, 5 }, | |
1707 { 6, 6 }, | |
1708 { 12, 7 }, | |
1709 { 0, 0 }, | |
1710 }; | |
1711 | |
1712 for (post_div = &post_divs[0]; post_div->divider; ++post_div) { | |
1713 rinfo->pll_output_freq = post_div->divider * freq; | |
1714 if (rinfo->pll_output_freq >= rinfo->pll.ppll_min && | |
1715 rinfo->pll_output_freq <= rinfo->pll.ppll_max) | |
1716 break; | |
1717 } | |
1718 | |
1719 rinfo->post_div = post_div->divider; | |
1720 rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq, | |
1721 rinfo->pll.ref_clk); | |
1722 newmode.ppll_ref_div = rinfo->pll.ref_div; | |
1723 newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); | |
1724 } | |
1725 | |
1726 RTRACE("post div = 0x%x\n", rinfo->post_div); | |
1727 RTRACE("fb_div = 0x%x\n", rinfo->fb_div); | |
1728 RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3); | |
1729 | |
1730 /* DDA */ | |
1731 vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div, | |
1732 rinfo->pll.ref_div * rinfo->post_div); | |
1733 xclk_freq = rinfo->pll.xclk; | |
1734 | |
1735 xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel); | |
1736 | |
1737 min_bits = min_bits_req(xclk_per_trans); | |
1738 useable_precision = min_bits + 1; | |
1739 | |
1740 xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision), | |
1741 vclk_freq * mode->bits_per_pixel); | |
1742 | |
1743 ron = (4 * rinfo->ram.mb + 3 * _max(rinfo->ram.trcd - 2, 0) + | |
1744 2 * rinfo->ram.trp + rinfo->ram.twr + rinfo->ram.cl + rinfo->ram.tr2w + | |
1745 xclk_per_trans) << (11 - useable_precision); | |
1746 roff = xclk_per_trans_precise * (32 - 4); | |
1747 | |
1748 RTRACE("ron = %d, roff = %d\n", ron, roff); | |
1749 RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise); | |
1750 | |
1751 if ((ron + rinfo->ram.rloop) >= roff) { | |
1752 printk("radeonfb: error ron out of range\n"); | |
1753 return; | |
1754 } | |
1755 | |
1756 newmode.dda_config = (xclk_per_trans_precise | | |
1757 (useable_precision << 16) | | |
1758 (rinfo->ram.rloop << 20)); | |
1759 newmode.dda_on_off = (ron << 16) | roff; | |
1760 | |
1761 /* do it! */ | |
1762 radeon_write_mode (rinfo, &newmode); | |
1763 | |
1764 return; | |
1765 } | |
1766 | |
1767 | |
1768 | |
1769 static void radeon_write_mode (struct radeonfb_info *rinfo, | |
1770 struct radeon_regs *mode) | |
1771 { | |
1772 int i; | |
1773 | |
1774 /* blank screen */ | |
1775 OUTREG8(CRTC_EXT_CNTL + 1, 4); | |
1776 | |
1777 for (i=0; i<9; i++) | |
1778 OUTREG(common_regs[i].reg, common_regs[i].val); | |
1779 | |
1780 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); | |
1781 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl, | |
1782 CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS); | |
1783 OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING); | |
1784 OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); | |
1785 OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); | |
1786 OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); | |
1787 OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); | |
1788 OUTREG(CRTC_OFFSET, 0); | |
1789 OUTREG(CRTC_OFFSET_CNTL, 0); | |
1790 OUTREG(CRTC_PITCH, mode->crtc_pitch); | |
1791 | |
1792 while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) != | |
1793 PPLL_DIV_SEL_MASK) { | |
1794 OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff); | |
1795 } | |
1796 | |
1797 OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff); | |
1798 | |
1799 while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) != | |
1800 (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) { | |
1801 OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK); | |
1802 } | |
1803 | |
1804 while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) != | |
1805 (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) { | |
1806 OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK); | |
1807 } | |
1808 | |
1809 while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) != | |
1810 (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) { | |
1811 OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK); | |
1812 } | |
1813 | |
1814 OUTPLL(HTOTAL_CNTL, 0); | |
1815 | |
1816 OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET); | |
1817 | |
1818 OUTREG(DDA_CONFIG, mode->dda_config); | |
1819 OUTREG(DDA_ON_OFF, mode->dda_on_off); | |
1820 | |
1821 /* unblank screen */ | |
1822 OUTREG8(CRTC_EXT_CNTL + 1, 0); | |
1823 | |
1824 return; | |
1825 } | |
1826 | |
1827 | |
1828 | |
1829 /* | |
1830 * text console acceleration | |
1831 */ | |
1832 | |
1833 | |
1834 static void fbcon_radeon_bmove(struct display *p, int srcy, int srcx, | |
1835 int dsty, int dstx, int height, int width) | |
1836 { | |
1837 struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info); | |
1838 u32 dp_cntl = DST_LAST_PEL; | |
1839 | |
1840 srcx *= fontwidth(p); | |
1841 srcy *= fontheight(p); | |
1842 dstx *= fontwidth(p); | |
1843 dsty *= fontheight(p); | |
1844 width *= fontwidth(p); | |
1845 height *= fontheight(p); | |
1846 | |
1847 if (srcy < dsty) { | |
1848 srcy += height - 1; | |
1849 dsty += height - 1; | |
1850 } else | |
1851 dp_cntl |= DST_Y_TOP_TO_BOTTOM; | |
1852 | |
1853 if (srcx < dstx) { | |
1854 srcx += width - 1; | |
1855 dstx += width - 1; | |
1856 } else | |
1857 dp_cntl |= DST_X_LEFT_TO_RIGHT; | |
1858 | |
1859 radeon_fifo_wait(6); | |
1860 OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | | |
1861 GMC_BRUSH_NONE | | |
1862 GMC_SRC_DATATYPE_COLOR | | |
1863 ROP3_S | | |
1864 DP_SRC_SOURCE_MEMORY)); | |
1865 OUTREG(DP_WRITE_MSK, 0xffffffff); | |
1866 OUTREG(DP_CNTL, dp_cntl); | |
1867 OUTREG(SRC_Y_X, (srcy << 16) | srcx); | |
1868 OUTREG(DST_Y_X, (dsty << 16) | dstx); | |
1869 OUTREG(DST_HEIGHT_WIDTH, (height << 16) | width); | |
1870 } | |
1871 | |
1872 | |
1873 | |
1874 static void fbcon_radeon_clear(struct vc_data *conp, struct display *p, | |
1875 int srcy, int srcx, int height, int width) | |
1876 { | |
1877 struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info); | |
1878 u32 clr; | |
1879 u32 temp; | |
1880 | |
1881 clr = attr_bgcol_ec(p, conp); | |
1882 clr |= (clr << 8); | |
1883 clr |= (clr << 16); | |
1884 | |
1885 srcx *= fontwidth(p); | |
1886 srcy *= fontheight(p); | |
1887 width *= fontwidth(p); | |
1888 height *= fontheight(p); | |
1889 | |
1890 radeon_fifo_wait(6); | |
1891 OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | | |
1892 GMC_BRUSH_SOLID_COLOR | | |
1893 GMC_SRC_DATATYPE_COLOR | | |
1894 ROP3_P)); | |
1895 OUTREG(DP_BRUSH_FRGD_CLR, clr); | |
1896 OUTREG(DP_WRITE_MSK, 0xffffffff); | |
1897 OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); | |
1898 OUTREG(DST_Y_X, (srcy << 16) | srcx); | |
1899 OUTREG(DST_WIDTH_HEIGHT, (width << 16) | height); | |
1900 } | |
1901 | |
1902 | |
1903 | |
1904 | |
1905 #ifdef FBCON_HAS_CFB8 | |
1906 static struct display_switch fbcon_radeon8 = { | |
1907 setup: fbcon_cfb8_setup, | |
1908 bmove: fbcon_radeon_bmove, | |
1909 clear: fbcon_cfb8_clear, | |
1910 putc: fbcon_cfb8_putc, | |
1911 putcs: fbcon_cfb8_putcs, | |
1912 revc: fbcon_cfb8_revc, | |
1913 clear_margins: fbcon_cfb8_clear_margins, | |
1914 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) | |
1915 }; | |
1916 #endif |