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