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