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