blob: 5b6c42291cb0c482a29f0b1afd05fe436cc358b5 [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>
Simon Glassc30ea602014-11-14 20:56:28 -070022#include <bios_emul.h>
Jason Jin2181b5d2007-07-06 08:33:33 +080023#include <pci.h>
24#include <asm/processor.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090025#include <linux/errno.h>
Jason Jin2181b5d2007-07-06 08:33:33 +080026#include <asm/io.h>
27#include <malloc.h>
28#include <video_fb.h>
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +010029#include "videomodes.h"
Jason Jin2181b5d2007-07-06 08:33:33 +080030
31#include <radeon.h>
32#include "ati_ids.h"
33#include "ati_radeon_fb.h"
34
35#undef DEBUG
36
37#ifdef DEBUG
38#define DPRINT(x...) printf(x)
39#else
40#define DPRINT(x...) do{}while(0)
41#endif
42
Jason Jin2181b5d2007-07-06 08:33:33 +080043#define MAX_MAPPED_VRAM (2048*2048*4)
44#define MIN_MAPPED_VRAM (1024*768*1)
45
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +010046#define RADEON_BUFFER_ALIGN 0x00000fff
47#define SURF_UPPER_BOUND(x,y,bpp) (((((x) * (((y) + 15) & ~15) * (bpp)/8) + RADEON_BUFFER_ALIGN) \
48 & ~RADEON_BUFFER_ALIGN) - 1)
49#define RADEON_CRT_PITCH(width, bpp) ((((width) * (bpp) + ((bpp) * 8 - 1)) / ((bpp) * 8)) | \
50 ((((width) * (bpp) + ((bpp) * 8 - 1)) / ((bpp) * 8)) << 16))
51
52#define CRTC_H_TOTAL_DISP_VAL(htotal, hdisp) \
53 (((((htotal) / 8) - 1) & 0x3ff) | (((((hdisp) / 8) - 1) & 0x1ff) << 16))
54#define CRTC_HSYNC_STRT_WID_VAL(hsync_srtr, hsync_wid) \
55 (((hsync_srtr) & 0x1fff) | (((hsync_wid) & 0x3f) << 16))
56#define CRTC_V_TOTAL_DISP_VAL(vtotal, vdisp) \
57 ((((vtotal) - 1) & 0xffff) | (((vdisp) - 1) << 16))
58#define CRTC_VSYNC_STRT_WID_VAL(vsync_srtr, vsync_wid) \
59 ((((vsync_srtr) - 1) & 0xfff) | (((vsync_wid) & 0x1f) << 16))
60
Jason Jin2181b5d2007-07-06 08:33:33 +080061/*#define PCI_VENDOR_ID_ATI*/
62#define PCI_CHIP_RV280_5960 0x5960
63#define PCI_CHIP_RV280_5961 0x5961
64#define PCI_CHIP_RV280_5962 0x5962
65#define PCI_CHIP_RV280_5964 0x5964
Anatolij Gustschin1a45d3f2008-02-14 18:22:04 +010066#define PCI_CHIP_RV280_5C63 0x5C63
Jason Jin2181b5d2007-07-06 08:33:33 +080067#define PCI_CHIP_RV370_5B60 0x5B60
68#define PCI_CHIP_RV380_5657 0x5657
69#define PCI_CHIP_R420_554d 0x554d
70
71static struct pci_device_id ati_radeon_pci_ids[] = {
72 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5960},
73 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5961},
74 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5962},
75 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5964},
Anatolij Gustschin1a45d3f2008-02-14 18:22:04 +010076 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5C63},
Jason Jin2181b5d2007-07-06 08:33:33 +080077 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV370_5B60},
78 {PCI_VENDOR_ID_ATI, PCI_CHIP_RV380_5657},
79 {PCI_VENDOR_ID_ATI, PCI_CHIP_R420_554d},
80 {0, 0}
81};
82
83static u16 ati_radeon_id_family_table[][2] = {
84 {PCI_CHIP_RV280_5960, CHIP_FAMILY_RV280},
85 {PCI_CHIP_RV280_5961, CHIP_FAMILY_RV280},
86 {PCI_CHIP_RV280_5962, CHIP_FAMILY_RV280},
87 {PCI_CHIP_RV280_5964, CHIP_FAMILY_RV280},
Anatolij Gustschin1a45d3f2008-02-14 18:22:04 +010088 {PCI_CHIP_RV280_5C63, CHIP_FAMILY_RV280},
Jason Jin2181b5d2007-07-06 08:33:33 +080089 {PCI_CHIP_RV370_5B60, CHIP_FAMILY_RV380},
90 {PCI_CHIP_RV380_5657, CHIP_FAMILY_RV380},
91 {PCI_CHIP_R420_554d, CHIP_FAMILY_R420},
92 {0, 0}
93};
94
95u16 get_radeon_id_family(u16 device)
96{
97 int i;
98 for (i=0; ati_radeon_id_family_table[0][i]; i+=2)
99 if (ati_radeon_id_family_table[0][i] == device)
100 return ati_radeon_id_family_table[0][i + 1];
101 return 0;
102}
103
104struct radeonfb_info *rinfo;
105
106static void radeon_identify_vram(struct radeonfb_info *rinfo)
107{
108 u32 tmp;
109
110 /* framebuffer size */
111 if ((rinfo->family == CHIP_FAMILY_RS100) ||
112 (rinfo->family == CHIP_FAMILY_RS200) ||
113 (rinfo->family == CHIP_FAMILY_RS300)) {
114 u32 tom = INREG(NB_TOM);
115 tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
116
117 radeon_fifo_wait(6);
118 OUTREG(MC_FB_LOCATION, tom);
119 OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
120 OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
121 OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
122
123 /* This is supposed to fix the crtc2 noise problem. */
124 OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
125
126 if ((rinfo->family == CHIP_FAMILY_RS100) ||
127 (rinfo->family == CHIP_FAMILY_RS200)) {
128 /* This is to workaround the asic bug for RMX, some versions
129 of BIOS dosen't have this register initialized correctly.
130 */
131 OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
132 ~CRTC_H_CUTOFF_ACTIVE_EN);
133 }
134 } else {
135 tmp = INREG(CONFIG_MEMSIZE);
Wolfgang Denk96bb2e02007-08-06 02:17:36 +0200136 }
Jason Jin2181b5d2007-07-06 08:33:33 +0800137
138 /* mem size is bits [28:0], mask off the rest */
139 rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
140
141 /*
142 * Hack to get around some busted production M6's
143 * reporting no ram
144 */
145 if (rinfo->video_ram == 0) {
146 switch (rinfo->pdev.device) {
147 case PCI_CHIP_RADEON_LY:
148 case PCI_CHIP_RADEON_LZ:
149 rinfo->video_ram = 8192 * 1024;
150 break;
151 default:
152 break;
153 }
154 }
155
156 /*
157 * Now try to identify VRAM type
158 */
159 if ((rinfo->family >= CHIP_FAMILY_R300) ||
160 (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
161 rinfo->vram_ddr = 1;
162 else
163 rinfo->vram_ddr = 0;
164
165 tmp = INREG(MEM_CNTL);
166 if (IS_R300_VARIANT(rinfo)) {
167 tmp &= R300_MEM_NUM_CHANNELS_MASK;
168 switch (tmp) {
169 case 0: rinfo->vram_width = 64; break;
170 case 1: rinfo->vram_width = 128; break;
171 case 2: rinfo->vram_width = 256; break;
172 default: rinfo->vram_width = 128; break;
173 }
174 } else if ((rinfo->family == CHIP_FAMILY_RV100) ||
175 (rinfo->family == CHIP_FAMILY_RS100) ||
176 (rinfo->family == CHIP_FAMILY_RS200)){
177 if (tmp & RV100_MEM_HALF_MODE)
178 rinfo->vram_width = 32;
179 else
180 rinfo->vram_width = 64;
181 } else {
182 if (tmp & MEM_NUM_CHANNELS_MASK)
183 rinfo->vram_width = 128;
184 else
185 rinfo->vram_width = 64;
186 }
187
188 /* This may not be correct, as some cards can have half of channel disabled
189 * ToDo: identify these cases
190 */
191
Ed Swarthout224dad22010-03-31 15:52:40 -0500192 DPRINT("radeonfb: Found %dk of %s %d bits wide videoram\n",
Jason Jin2181b5d2007-07-06 08:33:33 +0800193 rinfo->video_ram / 1024,
194 rinfo->vram_ddr ? "DDR" : "SDRAM",
195 rinfo->vram_width);
196
197}
198
199static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
200{
201 int i;
202
203 radeon_fifo_wait(20);
204
205#if 0
206 /* Workaround from XFree */
207 if (rinfo->is_mobility) {
Wolfgang Denk96bb2e02007-08-06 02:17:36 +0200208 /* A temporal workaround for the occational blanking on certain laptop
Jason Jin2181b5d2007-07-06 08:33:33 +0800209 * panels. This appears to related to the PLL divider registers
210 * (fail to lock?). It occurs even when all dividers are the same
211 * with their old settings. In this case we really don't need to
212 * fiddle with PLL registers. By doing this we can avoid the blanking
213 * problem with some panels.
Wolfgang Denk96bb2e02007-08-06 02:17:36 +0200214 */
Jason Jin2181b5d2007-07-06 08:33:33 +0800215 if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
216 (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
217 (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
218 /* We still have to force a switch to selected PPLL div thanks to
219 * an XFree86 driver bug which will switch it away in some cases
220 * even when using UseFDev */
221 OUTREGP(CLOCK_CNTL_INDEX,
222 mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
223 ~PPLL_DIV_SEL_MASK);
224 radeon_pll_errata_after_index(rinfo);
225 radeon_pll_errata_after_data(rinfo);
226 return;
227 }
228 }
229#endif
230 if(rinfo->pdev.device == PCI_CHIP_RV370_5B60) return;
231
232 /* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
233 OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
234
235 /* Reset PPLL & enable atomic update */
236 OUTPLLP(PPLL_CNTL,
237 PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
238 ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
239
240 /* Switch to selected PPLL divider */
241 OUTREGP(CLOCK_CNTL_INDEX,
242 mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
243 ~PPLL_DIV_SEL_MASK);
244
245 /* Set PPLL ref. div */
246 if (rinfo->family == CHIP_FAMILY_R300 ||
247 rinfo->family == CHIP_FAMILY_RS300 ||
248 rinfo->family == CHIP_FAMILY_R350 ||
249 rinfo->family == CHIP_FAMILY_RV350) {
250 if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
251 /* When restoring console mode, use saved PPLL_REF_DIV
252 * setting.
253 */
254 OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);
255 } else {
256 /* R300 uses ref_div_acc field as real ref divider */
257 OUTPLLP(PPLL_REF_DIV,
258 (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
259 ~R300_PPLL_REF_DIV_ACC_MASK);
260 }
261 } else
262 OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
263
264 /* Set PPLL divider 3 & post divider*/
265 OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
266 OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
267
268 /* Write update */
269 while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
270 ;
271 OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
272
273 /* Wait read update complete */
274 /* FIXME: Certain revisions of R300 can't recover here. Not sure of
275 the cause yet, but this workaround will mask the problem for now.
276 Other chips usually will pass at the very first test, so the
277 workaround shouldn't have any effect on them. */
278 for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)
279 ;
280
281 OUTPLL(HTOTAL_CNTL, 0);
282
283 /* Clear reset & atomic update */
284 OUTPLLP(PPLL_CNTL, 0,
285 ~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
286
287 /* We may want some locking ... oh well */
288 udelay(5000);
289
290 /* Switch back VCLK source to PPLL */
291 OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
292}
293
294typedef struct {
295 u16 reg;
296 u32 val;
297} reg_val;
298
Wolfgang Denk92254112007-11-18 16:36:27 +0100299#if 0 /* unused ? -> scheduled for removal */
Jason Jin2181b5d2007-07-06 08:33:33 +0800300/* these common regs are cleared before mode setting so they do not
301 * interfere with anything
302 */
303static reg_val common_regs[] = {
304 { OVR_CLR, 0 },
305 { OVR_WID_LEFT_RIGHT, 0 },
306 { OVR_WID_TOP_BOTTOM, 0 },
307 { OV0_SCALE_CNTL, 0 },
308 { SUBPIC_CNTL, 0 },
309 { VIPH_CONTROL, 0 },
310 { I2C_CNTL_1, 0 },
311 { GEN_INT_CNTL, 0 },
312 { CAP0_TRIG_CNTL, 0 },
313 { CAP1_TRIG_CNTL, 0 },
314};
Wolfgang Denk92254112007-11-18 16:36:27 +0100315#endif /* 0 */
Jason Jin2181b5d2007-07-06 08:33:33 +0800316
317void radeon_setmode(void)
318{
Jason Jin2181b5d2007-07-06 08:33:33 +0800319 struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
320
321 mode->crtc_gen_cntl = 0x03000200;
322 mode->crtc_ext_cntl = 0x00008048;
323 mode->dac_cntl = 0xff002100;
324 mode->crtc_h_total_disp = 0x4f0063;
325 mode->crtc_h_sync_strt_wid = 0x8c02a2;
326 mode->crtc_v_total_disp = 0x01df020c;
327 mode->crtc_v_sync_strt_wid = 0x8201ea;
328 mode->crtc_pitch = 0x00500050;
329
330 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
331 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
332 ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
333 OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
334 OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
335 OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
336 OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
337 OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
338 OUTREG(CRTC_OFFSET, 0);
339 OUTREG(CRTC_OFFSET_CNTL, 0);
340 OUTREG(CRTC_PITCH, mode->crtc_pitch);
341
342 mode->clk_cntl_index = 0x300;
343 mode->ppll_ref_div = 0xc;
344 mode->ppll_div_3 = 0x00030059;
345
346 radeon_write_pll_regs(rinfo, mode);
347}
348
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100349static void set_pal(void)
350{
351 int idx, val = 0;
352
353 for (idx = 0; idx < 256; idx++) {
354 OUTREG8(PALETTE_INDEX, idx);
355 OUTREG(PALETTE_DATA, val);
356 val += 0x00010101;
357 }
358}
359
360void radeon_setmode_9200(int vesa_idx, int bpp)
361{
362 struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
363
364 mode->crtc_gen_cntl = CRTC_EN | CRTC_EXT_DISP_EN;
365 mode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON;
366 mode->dac_cntl = DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN;
367 mode->crtc_offset_cntl = CRTC_OFFSET_CNTL__CRTC_TILE_EN;
368
369 switch (bpp) {
370 case 24:
371 mode->crtc_gen_cntl |= 0x6 << 8; /* x888 */
372#if defined(__BIG_ENDIAN)
373 mode->surface_cntl = NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP;
374 mode->surf_info[0] = NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP;
375#endif
376 break;
377 case 16:
378 mode->crtc_gen_cntl |= 0x4 << 8; /* 565 */
379#if defined(__BIG_ENDIAN)
380 mode->surface_cntl = NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP;
381 mode->surf_info[0] = NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP;
382#endif
383 break;
384 default:
385 mode->crtc_gen_cntl |= 0x2 << 8; /* palette */
386 mode->surface_cntl = 0x00000000;
387 break;
388 }
389
390 switch (vesa_idx) {
391 case RES_MODE_1280x1024:
392 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1688,1280);
393 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(1066,1024);
394 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(1025,3);
395#if defined(CONFIG_RADEON_VREFRESH_75HZ)
396 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1288,18);
397 mode->ppll_div_3 = 0x00010078;
398#else /* default @ 60 Hz */
399 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1320,14);
400 mode->ppll_div_3 = 0x00010060;
401#endif
402 /*
403 * for this mode pitch expands to the same value for 32, 16 and 8 bpp,
404 * so we set it here once only.
405 */
406 mode->crtc_pitch = RADEON_CRT_PITCH(1280,32);
407 switch (bpp) {
408 case 24:
409 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1280 * 4 / 16);
410 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,32);
411 break;
412 case 16:
413 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1280 * 2 / 16);
414 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,16);
415 break;
416 default: /* 8 bpp */
417 mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1280 * 1 / 16);
418 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,8);
419 break;
420 }
421 break;
422 case RES_MODE_1024x768:
423#if defined(CONFIG_RADEON_VREFRESH_75HZ)
424 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1312,1024);
425 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1032,12);
426 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(800,768);
427 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(769,3);
428 mode->ppll_div_3 = 0x0002008c;
429#else /* @ 60 Hz */
430 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1344,1024);
431 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1040,17) | CRTC_H_SYNC_POL;
432 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(806,768);
433 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(771,6) | CRTC_V_SYNC_POL;
434 mode->ppll_div_3 = 0x00020074;
435#endif
436 /* also same pitch value for 32, 16 and 8 bpp */
437 mode->crtc_pitch = RADEON_CRT_PITCH(1024,32);
438 switch (bpp) {
439 case 24:
440 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1024 * 4 / 16);
441 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,32);
442 break;
443 case 16:
444 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1024 * 2 / 16);
445 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,16);
446 break;
447 default: /* 8 bpp */
448 mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1024 * 1 / 16);
449 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,8);
450 break;
451 }
452 break;
453 case RES_MODE_800x600:
454 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1056,800);
455#if defined(CONFIG_RADEON_VREFRESH_75HZ)
456 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(808,10);
457 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(625,600);
458 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(601,3);
459 mode->ppll_div_3 = 0x000300b0;
460#else /* @ 60 Hz */
461 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(832,16);
462 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(628,600);
463 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(601,4);
464 mode->ppll_div_3 = 0x0003008e;
465#endif
466 switch (bpp) {
467 case 24:
468 mode->crtc_pitch = RADEON_CRT_PITCH(832,32);
469 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (832 * 4 / 16);
470 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(832,600,32);
471 break;
472 case 16:
473 mode->crtc_pitch = RADEON_CRT_PITCH(896,16);
474 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (896 * 2 / 16);
475 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(896,600,16);
476 break;
477 default: /* 8 bpp */
478 mode->crtc_pitch = RADEON_CRT_PITCH(1024,8);
479 mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1024 * 1 / 16);
480 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,600,8);
481 break;
482 }
483 break;
484 default: /* RES_MODE_640x480 */
485#if defined(CONFIG_RADEON_VREFRESH_75HZ)
486 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(840,640);
487 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(648,8) | CRTC_H_SYNC_POL;
488 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(500,480);
489 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(481,3) | CRTC_V_SYNC_POL;
490 mode->ppll_div_3 = 0x00030070;
491#else /* @ 60 Hz */
492 mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(800,640);
493 mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(674,12) | CRTC_H_SYNC_POL;
494 mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(525,480);
495 mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(491,2) | CRTC_V_SYNC_POL;
496 mode->ppll_div_3 = 0x00030059;
497#endif
498 /* also same pitch value for 32, 16 and 8 bpp */
499 mode->crtc_pitch = RADEON_CRT_PITCH(640,32);
500 switch (bpp) {
501 case 24:
502 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (640 * 4 / 16);
503 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(640,480,32);
504 break;
505 case 16:
506 mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (640 * 2 / 16);
507 mode->surf_upper_bound[0] = SURF_UPPER_BOUND(640,480,16);
508 break;
509 default: /* 8 bpp */
510 mode->crtc_offset_cntl = 0x00000000;
511 break;
512 }
513 break;
514 }
515
516 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl | CRTC_DISP_REQ_EN_B);
517 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
518 (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
519 OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
520 OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
521 OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
522 OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
523 OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
524 OUTREG(CRTC_OFFSET, 0);
525 OUTREG(CRTC_OFFSET_CNTL, mode->crtc_offset_cntl);
526 OUTREG(CRTC_PITCH, mode->crtc_pitch);
527 OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
528
529 mode->clk_cntl_index = 0x300;
530 mode->ppll_ref_div = 0xc;
531
532 radeon_write_pll_regs(rinfo, mode);
533
534 OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
535 ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
536 OUTREG(SURFACE0_INFO, mode->surf_info[0]);
537 OUTREG(SURFACE0_LOWER_BOUND, 0);
538 OUTREG(SURFACE0_UPPER_BOUND, mode->surf_upper_bound[0]);
539 OUTREG(SURFACE_CNTL, mode->surface_cntl);
540
541 if (bpp > 8)
542 set_pal();
543
544 free(mode);
545}
546
Jean-Christophe PLAGNIOL-VILLARDe6b1ec12007-11-20 20:41:48 +0100547#include "../bios_emulator/include/biosemu.h"
Wolfgang Denk92254112007-11-18 16:36:27 +0100548
Jason Jin2181b5d2007-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 Swarthout224dad22010-03-31 15:52:40 -0500567 &rinfo->fb_base_bus);
Jason Jin2181b5d2007-07-06 08:33:33 +0800568 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2,
Ed Swarthout224dad22010-03-31 15:52:40 -0500569 &rinfo->mmio_base_bus);
570 rinfo->fb_base_bus &= 0xfffff000;
571 rinfo->mmio_base_bus &= ~0x04;
Jason Jin2181b5d2007-07-06 08:33:33 +0800572
Ed Swarthout224dad22010-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 Gustschineaf39262010-04-08 15:50:55 +0200575 DPRINT("rinfo->mmio_base = 0x%p bus=0x%x\n",
Ed Swarthout224dad22010-03-31 15:52:40 -0500576 rinfo->mmio_base, rinfo->mmio_base_bus);
Jason Jin2181b5d2007-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 Swarthout9303ab82010-03-31 09:54:28 -0500580 if (!BootVideoCardBIOS(pdev, NULL, 0))
581 return -1;
Jason Jin2181b5d2007-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 Swarthout224dad22010-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 Jin2181b5d2007-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 Jin2181b5d2007-07-06 08:33:33 +0800621 u32 *vm;
Anatolij Gustschin9d9acf22008-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 Jin2181b5d2007-07-06 08:33:33 +0800627
628 rinfo = malloc(sizeof(struct radeonfb_info));
629
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100630 printf("Video: ");
Jason Jin2181b5d2007-07-06 08:33:33 +0800631 if(radeon_probe(rinfo)) {
632 printf("No radeon video card found!\n");
633 return NULL;
634 }
635
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100636 tmp = 0;
637
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200638 videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100639 /* get video mode via environment */
Simon Glass64b723f2017-08-03 12:22:12 -0600640 penv = env_get("videomode");
641 if (penv) {
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100642 /* deceide if it is a string */
643 if (penv[0] <= '9') {
644 videomode = (int) simple_strtoul (penv, NULL, 16);
645 tmp = 1;
646 }
647 } else {
648 tmp = 1;
649 }
650 if (tmp) {
651 /* parameter are vesa modes */
652 /* search params */
653 for (i = 0; i < VESA_MODES_COUNT; i++) {
654 if (vesa_modes[i].vesanr == videomode)
655 break;
656 }
657 if (i == VESA_MODES_COUNT) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200658 printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100659 i = 0;
660 }
661 res_mode = (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex];
662 bits_per_pixel = vesa_modes[i].bits_per_pixel;
663 vesa_idx = vesa_modes[i].resindex;
664 } else {
665 res_mode = (struct ctfb_res_modes *) &var_mode;
666 bits_per_pixel = video_get_params (res_mode, penv);
667 }
668
669 /* calculate hsynch and vsynch freq (info only) */
670 t1 = (res_mode->left_margin + res_mode->xres +
671 res_mode->right_margin + res_mode->hsync_len) / 8;
672 t1 *= 8;
673 t1 *= res_mode->pixclock;
674 t1 /= 1000;
675 hsynch = 1000000000L / t1;
676 t1 *= (res_mode->upper_margin + res_mode->yres +
677 res_mode->lower_margin + res_mode->vsync_len);
678 t1 /= 1000;
679 vsynch = 1000000000L / t1;
680
Jason Jin2181b5d2007-07-06 08:33:33 +0800681 /* fill in Graphic device struct */
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100682 sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
683 res_mode->yres, bits_per_pixel, (hsynch / 1000),
684 (vsynch / 1000));
Jason Jin2181b5d2007-07-06 08:33:33 +0800685 printf ("%s\n", pGD->modeIdent);
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100686 pGD->winSizeX = res_mode->xres;
687 pGD->winSizeY = res_mode->yres;
688 pGD->plnSizeX = res_mode->xres;
689 pGD->plnSizeY = res_mode->yres;
Jason Jin2181b5d2007-07-06 08:33:33 +0800690
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100691 switch (bits_per_pixel) {
692 case 24:
693 pGD->gdfBytesPP = 4;
694 pGD->gdfIndex = GDF_32BIT_X888RGB;
695 if (res_mode->xres == 800) {
696 pGD->winSizeX = 832;
697 pGD->plnSizeX = 832;
698 }
699 break;
700 case 16:
701 pGD->gdfBytesPP = 2;
702 pGD->gdfIndex = GDF_16BIT_565RGB;
703 if (res_mode->xres == 800) {
704 pGD->winSizeX = 896;
705 pGD->plnSizeX = 896;
706 }
707 break;
708 default:
709 if (res_mode->xres == 800) {
710 pGD->winSizeX = 1024;
711 pGD->plnSizeX = 1024;
712 }
713 pGD->gdfBytesPP = 1;
714 pGD->gdfIndex = GDF__8BIT_INDEX;
715 break;
716 }
Jason Jin2181b5d2007-07-06 08:33:33 +0800717
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200718 pGD->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
Ed Swarthout224dad22010-03-31 15:52:40 -0500719 pGD->pciBase = (unsigned int)rinfo->fb_base;
720 pGD->frameAdrs = (unsigned int)rinfo->fb_base;
Jason Jin2181b5d2007-07-06 08:33:33 +0800721 pGD->memSize = 64 * 1024 * 1024;
722
723 /* Cursor Start Address */
Ed Swarthout224dad22010-03-31 15:52:40 -0500724 pGD->dprBase = (pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP) +
725 (unsigned int)rinfo->fb_base;
Jason Jin2181b5d2007-07-06 08:33:33 +0800726 if ((pGD->dprBase & 0x0fff) != 0) {
727 /* allign it */
728 pGD->dprBase &= 0xfffff000;
729 pGD->dprBase += 0x00001000;
730 }
731 DPRINT ("Cursor Start %x Pattern Start %x\n", pGD->dprBase,
732 PATTERN_ADR);
Ed Swarthout224dad22010-03-31 15:52:40 -0500733 pGD->vprBase = (unsigned int)rinfo->fb_base; /* Dummy */
734 pGD->cprBase = (unsigned int)rinfo->fb_base; /* Dummy */
Jason Jin2181b5d2007-07-06 08:33:33 +0800735 /* set up Hardware */
736
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100737 /* Clear video memory (only visible screen area) */
738 i = pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP / 4;
Jason Jin2181b5d2007-07-06 08:33:33 +0800739 vm = (unsigned int *) pGD->pciBase;
740 while (i--)
741 *vm++ = 0;
742 /*SetDrawingEngine (bits_per_pixel);*/
743
Anatolij Gustschin9d9acf22008-02-14 18:19:50 +0100744 if (rinfo->family == CHIP_FAMILY_RV280)
745 radeon_setmode_9200(vesa_idx, bits_per_pixel);
746 else
747 radeon_setmode();
Jason Jin2181b5d2007-07-06 08:33:33 +0800748
749 return ((void *) pGD);
750}
751
752void video_set_lut (unsigned int index, /* color number */
753 unsigned char r, /* red */
754 unsigned char g, /* green */
755 unsigned char b /* blue */
756 )
757{
758 OUTREG(PALETTE_INDEX, index);
759 OUTREG(PALETTE_DATA, (r << 16) | (g << 8) | b);
760}