blob: 9ebb0b0c965ac388a4adc0d61c06804cd5089404 [file] [log] [blame]
Jason Jin2181b5d2007-07-06 08:33:33 +08001/*
2 * ATI Radeon Video card Framebuffer driver.
3 *
4 * Copyright 2007 Freescale Semiconductor, Inc.
5 * Zhang Wei <wei.zhang@freescale.com>
6 * Jason Jin <jason.jin@freescale.com>
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 *
26 * Some codes of this file is partly ported from Linux kernel
27 * ATI video framebuffer driver.
28 *
29 * Now the driver is tested on below ATI chips:
30 * 9200
31 * X300
32 * X700
33 *
34 */
35
36#include <common.h>
37
Jason Jin2181b5d2007-07-06 08:33:33 +080038#include <command.h>
39#include <pci.h>
40#include <asm/processor.h>
41#include <asm/errno.h>
42#include <asm/io.h>
43#include <malloc.h>
44#include <video_fb.h>
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +010045#include "videomodes.h"
Jason Jin2181b5d2007-07-06 08:33:33 +080046
47#include <radeon.h>
48#include "ati_ids.h"
49#include "ati_radeon_fb.h"
50
51#undef DEBUG
52
53#ifdef DEBUG
54#define DPRINT(x...) printf(x)
55#else
56#define DPRINT(x...) do{}while(0)
57#endif
58
59#ifndef min_t
60#define min_t(type,x,y) \
61 ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
62#endif
63
64#define MAX_MAPPED_VRAM (2048*2048*4)
65#define MIN_MAPPED_VRAM (1024*768*1)
66
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +010067#define RADEON_BUFFER_ALIGN 0x00000fff
68#define SURF_UPPER_BOUND(x,y,bpp) (((((x) * (((y) + 15) & ~15) * (bpp)/8) + RADEON_BUFFER_ALIGN) \
69 & ~RADEON_BUFFER_ALIGN) - 1)
70#define RADEON_CRT_PITCH(width, bpp) ((((width) * (bpp) + ((bpp) * 8 - 1)) / ((bpp) * 8)) | \
71 ((((width) * (bpp) + ((bpp) * 8 - 1)) / ((bpp) * 8)) << 16))
72
73#define CRTC_H_TOTAL_DISP_VAL(htotal, hdisp) \
74 (((((htotal) / 8) - 1) & 0x3ff) | (((((hdisp) / 8) - 1) & 0x1ff) << 16))
75#define CRTC_HSYNC_STRT_WID_VAL(hsync_srtr, hsync_wid) \
76 (((hsync_srtr) & 0x1fff) | (((hsync_wid) & 0x3f) << 16))
77#define CRTC_V_TOTAL_DISP_VAL(vtotal, vdisp) \
78 ((((vtotal) - 1) & 0xffff) | (((vdisp) - 1) << 16))
79#define CRTC_VSYNC_STRT_WID_VAL(vsync_srtr, vsync_wid) \
80 ((((vsync_srtr) - 1) & 0xfff) | (((vsync_wid) & 0x1f) << 16))
81
Jason Jin2181b5d2007-07-06 08:33:33 +080082/*#define PCI_VENDOR_ID_ATI*/
83#define PCI_CHIP_RV280_5960 0x5960
84#define PCI_CHIP_RV280_5961 0x5961
85#define PCI_CHIP_RV280_5962 0x5962
86#define PCI_CHIP_RV280_5964 0x5964
Anatolij Gustschin1a45d3f2008-02-14 18:22:04 +010087#define PCI_CHIP_RV280_5C63 0x5C63
Jason Jin2181b5d2007-07-06 08:33:33 +080088#define PCI_CHIP_RV370_5B60 0x5B60
89#define PCI_CHIP_RV380_5657 0x5657
90#define PCI_CHIP_R420_554d 0x554d
91
92static struct pci_device_id ati_radeon_pci_ids[] = {
93 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5960},
94 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5961},
95 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5962},
96 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5964},
Anatolij Gustschin1a45d3f2008-02-14 18:22:04 +010097 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5C63},
Jason Jin2181b5d2007-07-06 08:33:33 +080098 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV370_5B60},
99 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV380_5657},
100 {PCI_VENDOR_ID_ATI, PCI_CHIP_R420_554d},
101 {0, 0}
102};
103
104static u16 ati_radeon_id_family_table[][2] = {
105 {PCI_CHIP_RV280_5960, CHIP_FAMILY_RV280},
106 {PCI_CHIP_RV280_5961, CHIP_FAMILY_RV280},
107 {PCI_CHIP_RV280_5962, CHIP_FAMILY_RV280},
108 {PCI_CHIP_RV280_5964, CHIP_FAMILY_RV280},
Anatolij Gustschin1a45d3f2008-02-14 18:22:04 +0100109 {PCI_CHIP_RV280_5C63, CHIP_FAMILY_RV280},
Jason Jin2181b5d2007-07-06 08:33:33 +0800110 {PCI_CHIP_RV370_5B60, CHIP_FAMILY_RV380},
111 {PCI_CHIP_RV380_5657, CHIP_FAMILY_RV380},
112 {PCI_CHIP_R420_554d, CHIP_FAMILY_R420},
113 {0, 0}
114};
115
116u16 get_radeon_id_family(u16 device)
117{
118 int i;
119 for (i=0; ati_radeon_id_family_table[0][i]; i+=2)
120 if (ati_radeon_id_family_table[0][i] == device)
121 return ati_radeon_id_family_table[0][i + 1];
122 return 0;
123}
124
125struct radeonfb_info *rinfo;
126
127static void radeon_identify_vram(struct radeonfb_info *rinfo)
128{
129 u32 tmp;
130
131 /* framebuffer size */
132 if ((rinfo->family == CHIP_FAMILY_RS100) ||
133 (rinfo->family == CHIP_FAMILY_RS200) ||
134 (rinfo->family == CHIP_FAMILY_RS300)) {
135 u32 tom = INREG(NB_TOM);
136 tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
137
138 radeon_fifo_wait(6);
139 OUTREG(MC_FB_LOCATION, tom);
140 OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
141 OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
142 OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
143
144 /* This is supposed to fix the crtc2 noise problem. */
145 OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
146
147 if ((rinfo->family == CHIP_FAMILY_RS100) ||
148 (rinfo->family == CHIP_FAMILY_RS200)) {
149 /* This is to workaround the asic bug for RMX, some versions
150 of BIOS dosen't have this register initialized correctly.
151 */
152 OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
153 ~CRTC_H_CUTOFF_ACTIVE_EN);
154 }
155 } else {
156 tmp = INREG(CONFIG_MEMSIZE);
Wolfgang Denk96bb2e02007-08-06 02:17:36 +0200157 }
Jason Jin2181b5d2007-07-06 08:33:33 +0800158
159 /* mem size is bits [28:0], mask off the rest */
160 rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
161
162 /*
163 * Hack to get around some busted production M6's
164 * reporting no ram
165 */
166 if (rinfo->video_ram == 0) {
167 switch (rinfo->pdev.device) {
168 case PCI_CHIP_RADEON_LY:
169 case PCI_CHIP_RADEON_LZ:
170 rinfo->video_ram = 8192 * 1024;
171 break;
172 default:
173 break;
174 }
175 }
176
177 /*
178 * Now try to identify VRAM type
179 */
180 if ((rinfo->family >= CHIP_FAMILY_R300) ||
181 (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
182 rinfo->vram_ddr = 1;
183 else
184 rinfo->vram_ddr = 0;
185
186 tmp = INREG(MEM_CNTL);
187 if (IS_R300_VARIANT(rinfo)) {
188 tmp &= R300_MEM_NUM_CHANNELS_MASK;
189 switch (tmp) {
190 case 0: rinfo->vram_width = 64; break;
191 case 1: rinfo->vram_width = 128; break;
192 case 2: rinfo->vram_width = 256; break;
193 default: rinfo->vram_width = 128; break;
194 }
195 } else if ((rinfo->family == CHIP_FAMILY_RV100) ||
196 (rinfo->family == CHIP_FAMILY_RS100) ||
197 (rinfo->family == CHIP_FAMILY_RS200)){
198 if (tmp & RV100_MEM_HALF_MODE)
199 rinfo->vram_width = 32;
200 else
201 rinfo->vram_width = 64;
202 } else {
203 if (tmp & MEM_NUM_CHANNELS_MASK)
204 rinfo->vram_width = 128;
205 else
206 rinfo->vram_width = 64;
207 }
208
209 /* This may not be correct, as some cards can have half of channel disabled
210 * ToDo: identify these cases
211 */
212
213 DPRINT("radeonfb: Found %ldk of %s %d bits wide videoram\n",
214 rinfo->video_ram / 1024,
215 rinfo->vram_ddr ? "DDR" : "SDRAM",
216 rinfo->vram_width);
217
218}
219
220static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
221{
222 int i;
223
224 radeon_fifo_wait(20);
225
226#if 0
227 /* Workaround from XFree */
228 if (rinfo->is_mobility) {
Wolfgang Denk96bb2e02007-08-06 02:17:36 +0200229 /* A temporal workaround for the occational blanking on certain laptop
Jason Jin2181b5d2007-07-06 08:33:33 +0800230 * panels. This appears to related to the PLL divider registers
231 * (fail to lock?). It occurs even when all dividers are the same
232 * with their old settings. In this case we really don't need to
233 * fiddle with PLL registers. By doing this we can avoid the blanking
234 * problem with some panels.
Wolfgang Denk96bb2e02007-08-06 02:17:36 +0200235 */
Jason Jin2181b5d2007-07-06 08:33:33 +0800236 if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
237 (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
238 (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
239 /* We still have to force a switch to selected PPLL div thanks to
240 * an XFree86 driver bug which will switch it away in some cases
241 * even when using UseFDev */
242 OUTREGP(CLOCK_CNTL_INDEX,
243 mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
244 ~PPLL_DIV_SEL_MASK);
245 radeon_pll_errata_after_index(rinfo);
246 radeon_pll_errata_after_data(rinfo);
247 return;
248 }
249 }
250#endif
251 if(rinfo->pdev.device == PCI_CHIP_RV370_5B60) return;
252
253 /* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
254 OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
255
256 /* Reset PPLL & enable atomic update */
257 OUTPLLP(PPLL_CNTL,
258 PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
259 ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
260
261 /* Switch to selected PPLL divider */
262 OUTREGP(CLOCK_CNTL_INDEX,
263 mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
264 ~PPLL_DIV_SEL_MASK);
265
266 /* Set PPLL ref. div */
267 if (rinfo->family == CHIP_FAMILY_R300 ||
268 rinfo->family == CHIP_FAMILY_RS300 ||
269 rinfo->family == CHIP_FAMILY_R350 ||
270 rinfo->family == CHIP_FAMILY_RV350) {
271 if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
272 /* When restoring console mode, use saved PPLL_REF_DIV
273 * setting.
274 */
275 OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);
276 } else {
277 /* R300 uses ref_div_acc field as real ref divider */
278 OUTPLLP(PPLL_REF_DIV,
279 (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
280 ~R300_PPLL_REF_DIV_ACC_MASK);
281 }
282 } else
283 OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
284
285 /* Set PPLL divider 3 & post divider*/
286 OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
287 OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
288
289 /* Write update */
290 while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
291 ;
292 OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
293
294 /* Wait read update complete */
295 /* FIXME: Certain revisions of R300 can't recover here. Not sure of
296 the cause yet, but this workaround will mask the problem for now.
297 Other chips usually will pass at the very first test, so the
298 workaround shouldn't have any effect on them. */
299 for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)
300 ;
301
302 OUTPLL(HTOTAL_CNTL, 0);
303
304 /* Clear reset & atomic update */
305 OUTPLLP(PPLL_CNTL, 0,
306 ~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
307
308 /* We may want some locking ... oh well */
309 udelay(5000);
310
311 /* Switch back VCLK source to PPLL */
312 OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
313}
314
315typedef struct {
316 u16 reg;
317 u32 val;
318} reg_val;
319
Wolfgang Denk92254112007-11-18 16:36:27 +0100320#if 0 /* unused ? -> scheduled for removal */
Jason Jin2181b5d2007-07-06 08:33:33 +0800321/* these common regs are cleared before mode setting so they do not
322 * interfere with anything
323 */
324static reg_val common_regs[] = {
325 { OVR_CLR, 0 },
326 { OVR_WID_LEFT_RIGHT, 0 },
327 { OVR_WID_TOP_BOTTOM, 0 },
328 { OV0_SCALE_CNTL, 0 },
329 { SUBPIC_CNTL, 0 },
330 { VIPH_CONTROL, 0 },
331 { I2C_CNTL_1, 0 },
332 { GEN_INT_CNTL, 0 },
333 { CAP0_TRIG_CNTL, 0 },
334 { CAP1_TRIG_CNTL, 0 },
335};
Wolfgang Denk92254112007-11-18 16:36:27 +0100336#endif /* 0 */
Jason Jin2181b5d2007-07-06 08:33:33 +0800337
338void radeon_setmode(void)
339{
Jason Jin2181b5d2007-07-06 08:33:33 +0800340 struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
341
342 mode->crtc_gen_cntl = 0x03000200;
343 mode->crtc_ext_cntl = 0x00008048;
344 mode->dac_cntl = 0xff002100;
345 mode->crtc_h_total_disp = 0x4f0063;
346 mode->crtc_h_sync_strt_wid = 0x8c02a2;
347 mode->crtc_v_total_disp = 0x01df020c;
348 mode->crtc_v_sync_strt_wid = 0x8201ea;
349 mode->crtc_pitch = 0x00500050;
350
351 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
352 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
353 ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
354 OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
355 OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
356 OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
357 OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
358 OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
359 OUTREG(CRTC_OFFSET, 0);
360 OUTREG(CRTC_OFFSET_CNTL, 0);
361 OUTREG(CRTC_PITCH, mode->crtc_pitch);
362
363 mode->clk_cntl_index = 0x300;
364 mode->ppll_ref_div = 0xc;
365 mode->ppll_div_3 = 0x00030059;
366
367 radeon_write_pll_regs(rinfo, mode);
368}
369
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100370static void set_pal(void)
371{
372 int idx, val = 0;
373
374 for (idx = 0; idx < 256; idx++) {
375 OUTREG8(PALETTE_INDEX, idx);
376 OUTREG(PALETTE_DATA, val);
377 val += 0x00010101;
378 }
379}
380
381void radeon_setmode_9200(int vesa_idx, int bpp)
382{
383 struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
384
385 mode->crtc_gen_cntl = CRTC_EN | CRTC_EXT_DISP_EN;
386 mode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON;
387 mode->dac_cntl = DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN;
388 mode->crtc_offset_cntl = CRTC_OFFSET_CNTL__CRTC_TILE_EN;
389
390 switch (bpp) {
391 case 24:
392 mode->crtc_gen_cntl |= 0x6 << 8; /* x888 */
393#if defined(__BIG_ENDIAN)
394 mode->surface_cntl = NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP;
395 mode->surf_info[0] = NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP;
396#endif
397 break;
398 case 16:
399 mode->crtc_gen_cntl |= 0x4 << 8; /* 565 */
400#if defined(__BIG_ENDIAN)
401 mode->surface_cntl = NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP;
402 mode->surf_info[0] = NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP;
403#endif
404 break;
405 default:
406 mode->crtc_gen_cntl |= 0x2 << 8; /* palette */
407 mode->surface_cntl = 0x00000000;
408 break;
409 }
410
411 switch (vesa_idx) {
412 case RES_MODE_1280x1024:
413 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1688,1280);
414 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(1066,1024);
415 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(1025,3);
416#if defined(CONFIG_RADEON_VREFRESH_75HZ)
417 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1288,18);
418 mode->ppll_div_3 = 0x00010078;
419#else /* default @ 60 Hz */
420 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1320,14);
421 mode->ppll_div_3 = 0x00010060;
422#endif
423 /*
424 * for this mode pitch expands to the same value for 32, 16 and 8 bpp,
425 * so we set it here once only.
426 */
427 mode->crtc_pitch = RADEON_CRT_PITCH(1280,32);
428 switch (bpp) {
429 case 24:
430 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1280 * 4 / 16);
431 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,32);
432 break;
433 case 16:
434 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1280 * 2 / 16);
435 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,16);
436 break;
437 default: /* 8 bpp */
438 mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1280 * 1 / 16);
439 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,8);
440 break;
441 }
442 break;
443 case RES_MODE_1024x768:
444#if defined(CONFIG_RADEON_VREFRESH_75HZ)
445 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1312,1024);
446 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1032,12);
447 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(800,768);
448 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(769,3);
449 mode->ppll_div_3 = 0x0002008c;
450#else /* @ 60 Hz */
451 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1344,1024);
452 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1040,17) | CRTC_H_SYNC_POL;
453 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(806,768);
454 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(771,6) | CRTC_V_SYNC_POL;
455 mode->ppll_div_3 = 0x00020074;
456#endif
457 /* also same pitch value for 32, 16 and 8 bpp */
458 mode->crtc_pitch = RADEON_CRT_PITCH(1024,32);
459 switch (bpp) {
460 case 24:
461 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1024 * 4 / 16);
462 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,32);
463 break;
464 case 16:
465 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1024 * 2 / 16);
466 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,16);
467 break;
468 default: /* 8 bpp */
469 mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1024 * 1 / 16);
470 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,8);
471 break;
472 }
473 break;
474 case RES_MODE_800x600:
475 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1056,800);
476#if defined(CONFIG_RADEON_VREFRESH_75HZ)
477 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(808,10);
478 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(625,600);
479 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(601,3);
480 mode->ppll_div_3 = 0x000300b0;
481#else /* @ 60 Hz */
482 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(832,16);
483 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(628,600);
484 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(601,4);
485 mode->ppll_div_3 = 0x0003008e;
486#endif
487 switch (bpp) {
488 case 24:
489 mode->crtc_pitch = RADEON_CRT_PITCH(832,32);
490 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (832 * 4 / 16);
491 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(832,600,32);
492 break;
493 case 16:
494 mode->crtc_pitch = RADEON_CRT_PITCH(896,16);
495 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (896 * 2 / 16);
496 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(896,600,16);
497 break;
498 default: /* 8 bpp */
499 mode->crtc_pitch = RADEON_CRT_PITCH(1024,8);
500 mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1024 * 1 / 16);
501 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,600,8);
502 break;
503 }
504 break;
505 default: /* RES_MODE_640x480 */
506#if defined(CONFIG_RADEON_VREFRESH_75HZ)
507 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(840,640);
508 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(648,8) | CRTC_H_SYNC_POL;
509 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(500,480);
510 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(481,3) | CRTC_V_SYNC_POL;
511 mode->ppll_div_3 = 0x00030070;
512#else /* @ 60 Hz */
513 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(800,640);
514 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(674,12) | CRTC_H_SYNC_POL;
515 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(525,480);
516 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(491,2) | CRTC_V_SYNC_POL;
517 mode->ppll_div_3 = 0x00030059;
518#endif
519 /* also same pitch value for 32, 16 and 8 bpp */
520 mode->crtc_pitch = RADEON_CRT_PITCH(640,32);
521 switch (bpp) {
522 case 24:
523 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (640 * 4 / 16);
524 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(640,480,32);
525 break;
526 case 16:
527 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (640 * 2 / 16);
528 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(640,480,16);
529 break;
530 default: /* 8 bpp */
531 mode->crtc_offset_cntl = 0x00000000;
532 break;
533 }
534 break;
535 }
536
537 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl | CRTC_DISP_REQ_EN_B);
538 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
539 (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
540 OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
541 OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
542 OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
543 OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
544 OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
545 OUTREG(CRTC_OFFSET, 0);
546 OUTREG(CRTC_OFFSET_CNTL, mode->crtc_offset_cntl);
547 OUTREG(CRTC_PITCH, mode->crtc_pitch);
548 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
549
550 mode->clk_cntl_index = 0x300;
551 mode->ppll_ref_div = 0xc;
552
553 radeon_write_pll_regs(rinfo, mode);
554
555 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
556 ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
557 OUTREG(SURFACE0_INFO, mode->surf_info[0]);
558 OUTREG(SURFACE0_LOWER_BOUND, 0);
559 OUTREG(SURFACE0_UPPER_BOUND, mode->surf_upper_bound[0]);
560 OUTREG(SURFACE_CNTL, mode->surface_cntl);
561
562 if (bpp > 8)
563 set_pal();
564
565 free(mode);
566}
567
Jean-Christophe PLAGNIOL-VILLARDe6b1ec12007-11-20 20:41:48 +0100568#include "../bios_emulator/include/biosemu.h"
Wolfgang Denk92254112007-11-18 16:36:27 +0100569extern int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp);
570
Jason Jin2181b5d2007-07-06 08:33:33 +0800571int radeon_probe(struct radeonfb_info *rinfo)
572{
573 pci_dev_t pdev;
574 u16 did;
575
576 pdev = pci_find_devices(ati_radeon_pci_ids, 0);
577
578 if (pdev != -1) {
579 pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
580 printf("ATI Radeon video card (%04x, %04x) found @(%d:%d:%d)\n",
581 PCI_VENDOR_ID_ATI, did, (pdev >> 16) & 0xff,
582 (pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
583
584 strcpy(rinfo->name, "ATI Radeon");
585 rinfo->pdev.vendor = PCI_VENDOR_ID_ATI;
586 rinfo->pdev.device = did;
587 rinfo->family = get_radeon_id_family(rinfo->pdev.device);
588 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
589 &rinfo->fb_base_phys);
590 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2,
591 &rinfo->mmio_base_phys);
592 rinfo->fb_base_phys &= 0xfffff000;
593 rinfo->mmio_base_phys &= ~0x04;
594
595 rinfo->mmio_base = (void *)rinfo->mmio_base_phys;
596 DPRINT("rinfo->mmio_base = 0x%x\n",rinfo->mmio_base);
597 rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
598 DPRINT("rinfo->fb_local_base = 0x%x\n",rinfo->fb_local_base);
599 /* PostBIOS with x86 emulater */
600 BootVideoCardBIOS(pdev, NULL, 0);
601
602 /*
603 * Check for errata
604 * (These will be added in the future for the chipfamily
605 * R300, RV200, RS200, RV100, RS100.)
606 */
607
608 /* Get VRAM size and type */
609 radeon_identify_vram(rinfo);
610
611 rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM,
612 rinfo->video_ram);
613 rinfo->fb_base = (void *)rinfo->fb_base_phys;
614
615 DPRINT("Radeon: framebuffer base phy address 0x%08x," \
616 "MMIO base phy address 0x%08x," \
617 "framebuffer local base 0x%08x.\n ",
618 rinfo->fb_base_phys, rinfo->mmio_base_phys,
619 rinfo->fb_local_base);
620
621 return 0;
622 }
623 return -1;
624}
625
626/*
627 * The Graphic Device
628 */
629GraphicDevice ctfb;
630
631#define CURSOR_SIZE 0x1000 /* in KByte for HW Cursor */
632#define PATTERN_ADR (pGD->dprBase + CURSOR_SIZE) /* pattern Memory after Cursor Memory */
633#define PATTERN_SIZE 8*8*4 /* 4 Bytes per Pixel 8 x 8 Pixel */
634#define ACCELMEMORY (CURSOR_SIZE + PATTERN_SIZE) /* reserved Memory for BITBlt and hw cursor */
635
636void *video_hw_init(void)
637{
638 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
Jason Jin2181b5d2007-07-06 08:33:33 +0800639 u32 *vm;
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100640 char *penv;
641 unsigned long t1, hsynch, vsynch;
642 int bits_per_pixel, i, tmp, vesa_idx = 0, videomode;
643 struct ctfb_res_modes *res_mode;
644 struct ctfb_res_modes var_mode;
Jason Jin2181b5d2007-07-06 08:33:33 +0800645
646 rinfo = malloc(sizeof(struct radeonfb_info));
647
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100648 printf("Video: ");
Jason Jin2181b5d2007-07-06 08:33:33 +0800649 if(radeon_probe(rinfo)) {
650 printf("No radeon video card found!\n");
651 return NULL;
652 }
653
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100654 tmp = 0;
655
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200656 videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100657 /* get video mode via environment */
658 if ((penv = getenv ("videomode")) != NULL) {
659 /* deceide if it is a string */
660 if (penv[0] <= '9') {
661 videomode = (int) simple_strtoul (penv, NULL, 16);
662 tmp = 1;
663 }
664 } else {
665 tmp = 1;
666 }
667 if (tmp) {
668 /* parameter are vesa modes */
669 /* search params */
670 for (i = 0; i < VESA_MODES_COUNT; i++) {
671 if (vesa_modes[i].vesanr == videomode)
672 break;
673 }
674 if (i == VESA_MODES_COUNT) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200675 printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100676 i = 0;
677 }
678 res_mode = (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex];
679 bits_per_pixel = vesa_modes[i].bits_per_pixel;
680 vesa_idx = vesa_modes[i].resindex;
681 } else {
682 res_mode = (struct ctfb_res_modes *) &var_mode;
683 bits_per_pixel = video_get_params (res_mode, penv);
684 }
685
686 /* calculate hsynch and vsynch freq (info only) */
687 t1 = (res_mode->left_margin + res_mode->xres +
688 res_mode->right_margin + res_mode->hsync_len) / 8;
689 t1 *= 8;
690 t1 *= res_mode->pixclock;
691 t1 /= 1000;
692 hsynch = 1000000000L / t1;
693 t1 *= (res_mode->upper_margin + res_mode->yres +
694 res_mode->lower_margin + res_mode->vsync_len);
695 t1 /= 1000;
696 vsynch = 1000000000L / t1;
697
Jason Jin2181b5d2007-07-06 08:33:33 +0800698 /* fill in Graphic device struct */
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100699 sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
700 res_mode->yres, bits_per_pixel, (hsynch / 1000),
701 (vsynch / 1000));
Jason Jin2181b5d2007-07-06 08:33:33 +0800702 printf ("%s\n", pGD->modeIdent);
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100703 pGD->winSizeX = res_mode->xres;
704 pGD->winSizeY = res_mode->yres;
705 pGD->plnSizeX = res_mode->xres;
706 pGD->plnSizeY = res_mode->yres;
Jason Jin2181b5d2007-07-06 08:33:33 +0800707
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100708 switch (bits_per_pixel) {
709 case 24:
710 pGD->gdfBytesPP = 4;
711 pGD->gdfIndex = GDF_32BIT_X888RGB;
712 if (res_mode->xres == 800) {
713 pGD->winSizeX = 832;
714 pGD->plnSizeX = 832;
715 }
716 break;
717 case 16:
718 pGD->gdfBytesPP = 2;
719 pGD->gdfIndex = GDF_16BIT_565RGB;
720 if (res_mode->xres == 800) {
721 pGD->winSizeX = 896;
722 pGD->plnSizeX = 896;
723 }
724 break;
725 default:
726 if (res_mode->xres == 800) {
727 pGD->winSizeX = 1024;
728 pGD->plnSizeX = 1024;
729 }
730 pGD->gdfBytesPP = 1;
731 pGD->gdfIndex = GDF__8BIT_INDEX;
732 break;
733 }
Jason Jin2181b5d2007-07-06 08:33:33 +0800734
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200735 pGD->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
Jason Jin2181b5d2007-07-06 08:33:33 +0800736 pGD->pciBase = rinfo->fb_base_phys;
737 pGD->frameAdrs = rinfo->fb_base_phys;
738 pGD->memSize = 64 * 1024 * 1024;
739
740 /* Cursor Start Address */
741 pGD->dprBase =
742 (pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP) + rinfo->fb_base_phys;
743 if ((pGD->dprBase & 0x0fff) != 0) {
744 /* allign it */
745 pGD->dprBase &= 0xfffff000;
746 pGD->dprBase += 0x00001000;
747 }
748 DPRINT ("Cursor Start %x Pattern Start %x\n", pGD->dprBase,
749 PATTERN_ADR);
750 pGD->vprBase = rinfo->fb_base_phys; /* Dummy */
751 pGD->cprBase = rinfo->fb_base_phys; /* Dummy */
752 /* set up Hardware */
753
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100754 /* Clear video memory (only visible screen area) */
755 i = pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP / 4;
Jason Jin2181b5d2007-07-06 08:33:33 +0800756 vm = (unsigned int *) pGD->pciBase;
757 while (i--)
758 *vm++ = 0;
759 /*SetDrawingEngine (bits_per_pixel);*/
760
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100761 if (rinfo->family == CHIP_FAMILY_RV280)
762 radeon_setmode_9200(vesa_idx, bits_per_pixel);
763 else
764 radeon_setmode();
Jason Jin2181b5d2007-07-06 08:33:33 +0800765
766 return ((void *) pGD);
767}
768
769void video_set_lut (unsigned int index, /* color number */
770 unsigned char r, /* red */
771 unsigned char g, /* green */
772 unsigned char b /* blue */
773 )
774{
775 OUTREG(PALETTE_INDEX, index);
776 OUTREG(PALETTE_DATA, (r << 16) | (g << 8) | b);
777}