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