
Adds ATI Radeon 9200 support for 1280x1024, 1024x768, 800x600, 640x480 at 24, 16 and 8 bpp. Hope this patch won't screw up X300 and X700 support.
Signed-off-by: Anatolij Gustschin agust@denx.de --- drivers/video/ati_radeon_fb.c | 401 +++++++++++++++++++++++++++++++++++++++-- 1 files changed, 386 insertions(+), 15 deletions(-)
diff --git a/drivers/video/ati_radeon_fb.c b/drivers/video/ati_radeon_fb.c index 0bdaa1c..740a360 100644 --- a/drivers/video/ati_radeon_fb.c +++ b/drivers/video/ati_radeon_fb.c @@ -44,6 +44,7 @@ #include <asm/io.h> #include <malloc.h> #include <video_fb.h> +#include "videomodes.h"
#include <radeon.h> #include "ati_ids.h" @@ -70,6 +71,7 @@ #define PCI_CHIP_RV280_5961 0x5961 #define PCI_CHIP_RV280_5962 0x5962 #define PCI_CHIP_RV280_5964 0x5964 +#define PCI_CHIP_RV280_5C63 0x5C63 #define PCI_CHIP_RV370_5B60 0x5B60 #define PCI_CHIP_RV380_5657 0x5657 #define PCI_CHIP_R420_554d 0x554d @@ -79,6 +81,7 @@ static struct pci_device_id ati_radeon_pci_ids[] = { {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5961}, {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5962}, {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5964}, + {PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5C63}, {PCI_VENDOR_ID_ATI, PCI_CHIP_RV370_5B60}, {PCI_VENDOR_ID_ATI, PCI_CHIP_RV380_5657}, {PCI_VENDOR_ID_ATI, PCI_CHIP_R420_554d}, @@ -90,12 +93,115 @@ static u16 ati_radeon_id_family_table[][2] = { {PCI_CHIP_RV280_5961, CHIP_FAMILY_RV280}, {PCI_CHIP_RV280_5962, CHIP_FAMILY_RV280}, {PCI_CHIP_RV280_5964, CHIP_FAMILY_RV280}, + {PCI_CHIP_RV280_5C63, CHIP_FAMILY_RV280}, {PCI_CHIP_RV370_5B60, CHIP_FAMILY_RV380}, {PCI_CHIP_RV380_5657, CHIP_FAMILY_RV380}, {PCI_CHIP_R420_554d, CHIP_FAMILY_R420}, {0, 0} };
+static struct { + unsigned char idx; + unsigned int val; +} pal_16[] = { + {0x00, 0x00000000}, + {0x00, 0x00000400}, + {0x04, 0x00000400}, + {0x08, 0x00080c08}, + {0x08, 0x00080808}, + {0x10, 0x00101410}, + {0x0c, 0x00080c08}, + {0x18, 0x00181c18}, + {0x10, 0x00101010}, + {0x20, 0x00202420}, + {0x14, 0x00101410}, + {0x28, 0x00292c29}, + {0x18, 0x00181818}, + {0x30, 0x00313431}, + {0x1c, 0x00181c18}, + {0x38, 0x00393c39}, + {0x20, 0x00202020}, + {0x40, 0x00414441}, + {0x24, 0x00202420}, + {0x48, 0x004a4c4a}, + {0x28, 0x00292829}, + {0x50, 0x00525552}, + {0x2c, 0x00292c29}, + {0x58, 0x005a5d5a}, + {0x30, 0x00313031}, + {0x60, 0x00626562}, + {0x34, 0x00313431}, + {0x68, 0x006a6d6a}, + {0x38, 0x00393839}, + {0x70, 0x00737573}, + {0x3c, 0x00393c39}, + {0x78, 0x007b7d7b}, + {0x40, 0x00414041}, + {0x80, 0x00838583}, + {0x44, 0x00414441}, + {0x88, 0x008b8d8b}, + {0x48, 0x004a484a}, + {0x90, 0x00949594}, + {0x4c, 0x004a4c4a}, + {0x98, 0x009c9d9c}, + {0x50, 0x00525052}, + {0xa0, 0x00a4a5a4}, + {0x54, 0x00525552}, + {0xa8, 0x00acaeac}, + {0x58, 0x005a595a}, + {0xb0, 0x00b4b6b4}, + {0x5c, 0x005a5d5a}, + {0xb8, 0x00bdbebd}, + {0x60, 0x00626162}, + {0xc0, 0x00c5c6c5}, + {0x64, 0x00626562}, + {0xc8, 0x00cdcecd}, + {0x68, 0x006a696a}, + {0xd0, 0x00d5d6d5}, + {0x6c, 0x006a6d6a}, + {0xd8, 0x00dedede}, + {0x70, 0x00737173}, + {0xe0, 0x00e6e6e6}, + {0x74, 0x00737573}, + {0xe8, 0x00eeeeee}, + {0x78, 0x007b797b}, + {0xf0, 0x00f6f6f6}, + {0x7c, 0x007b7d7b}, + {0xf8, 0x00ffffff}, + {0x80, 0x00838183}, + {0x84, 0x00838583}, + {0x88, 0x008b898b}, + {0x8c, 0x008b8d8b}, + {0x90, 0x00949194}, + {0x94, 0x00949594}, + {0x98, 0x009c999c}, + {0x9c, 0x009c9d9c}, + {0xa0, 0x00a4a1a4}, + {0xa4, 0x00a4a5a4}, + {0xa8, 0x00acaaac}, + {0xac, 0x00acaeac}, + {0xb0, 0x00b4b2b4}, + {0xb4, 0x00b4b6b4}, + {0xb8, 0x00bdbabd}, + {0xbc, 0x00bdbebd}, + {0xc0, 0x00c5c2c5}, + {0xc4, 0x00c5c6c5}, + {0xc8, 0x00cdcacd}, + {0xcc, 0x00cdcecd}, + {0xd0, 0x00d5d2d5}, + {0xd4, 0x00d5d6d5}, + {0xd8, 0x00dedade}, + {0xdc, 0x00dedede}, + {0xe0, 0x00e6e2e6}, + {0xe4, 0x00e6e6e6}, + {0xe8, 0x00eeeaee}, + {0xec, 0x00eeeeee}, + {0xf0, 0x00f6f2f6}, + {0xf4, 0x00f6f6f6}, + {0xf8, 0x00fffaff}, + {0xfc, 0x00ffffff}, +}; + u16 get_radeon_id_family(u16 device) { int i; @@ -350,6 +456,196 @@ void radeon_setmode(void) radeon_write_pll_regs(rinfo, mode); }
+static void set_pal_16(void) +{ + int i; + + for (i = 0; i < 96; i++) { + OUTREG8(PALETTE_INDEX, pal_16[i].idx); + OUTREG(PALETTE_DATA, pal_16[i].val); + } +} + +static void set_pal_24(void) +{ + int idx, val = 0; + + for (idx = 0; idx < 256; idx++) { + OUTREG8(PALETTE_INDEX, idx); + OUTREG(PALETTE_DATA, val); + val += 0x00010101; + } +} + +void radeon_setmode_9200(int vesa_idx, int bpp) +{ + struct radeon_regs *mode = malloc(sizeof(struct radeon_regs)); + unsigned long dp_gm_cntl; + + mode->crtc_gen_cntl = 0x03000600; + mode->surface_cntl = 0x00a00000; + dp_gm_cntl = 0x100036d2; + mode->crtc_ext_cntl = 0x00008048; + mode->dac_cntl = 0xff002102; + mode->crtc_offset_cntl = 0x00008000; + + if (bpp == 16) { + mode->crtc_gen_cntl = 0x03000400; + dp_gm_cntl = 0x100034d2; + mode->surface_cntl = 0x00500000; + } else if (bpp == 8) { + mode->crtc_gen_cntl = 0x03000200; + dp_gm_cntl = 0x100032d2; + mode->surface_cntl = 0x00000000; + } + + if (vesa_idx == RES_MODE_640x480 && bpp == 8) { + mode->dac_cntl = 0xff002100; + mode->crtc_offset_cntl = 0x00000000; + } + + switch (vesa_idx) { + case RES_MODE_1280x1024: +#if 1 /* @ 60 Hz */ + mode->crtc_h_total_disp = 0x009f00d2; + mode->crtc_h_sync_strt_wid = 0x000e0528; + mode->crtc_v_total_disp = 0x03ff0429; + mode->crtc_v_sync_strt_wid = 0x00030400; + mode->crtc_pitch = 0x00a000a0; + mode->ppll_div_3 = 0x00010060; +#else /* @ 75 Hz */ + mode->crtc_h_total_disp = 0x009f00d2; + mode->crtc_h_sync_strt_wid = 0x00120508; + mode->crtc_v_total_disp = 0x03ff0429; + mode->crtc_v_sync_strt_wid = 0x00030400; + mode->crtc_pitch = 0x00a000a0; + mode->ppll_div_3 = 0x00010078; +#endif + switch (bpp) { + case 24: + mode->surf_info[0] = 0x00a10140; + mode->surf_upper_bound[0] = 0x004fffff; + break; + case 16: + mode->surf_info[0] = 0x005100a0; + mode->surf_upper_bound[0] = 0x0027ffff; + break; + default: /* 8 bpp */ + mode->surf_info[0] = 0x00010050; + mode->surf_upper_bound[0] = 0x0013ffff; + break; + } + break; + case RES_MODE_1024x768: +#if 1 /* @ 60 Hz */ + mode->crtc_h_total_disp = 0x007f00a7; + mode->crtc_h_sync_strt_wid = 0x00910410; + mode->crtc_v_total_disp = 0x02ff0325; + mode->crtc_v_sync_strt_wid = 0x00860302; + mode->crtc_pitch = 0x00800080; + mode->ppll_div_3 = 0x00020074; +#else /* @ 75 Hz */ + mode->crtc_h_total_disp = 0x007f00a3; + mode->crtc_h_sync_strt_wid = 0x000c0408; + mode->crtc_v_total_disp = 0x02ff031f; + mode->crtc_v_sync_strt_wid = 0x00030300; + mode->crtc_pitch = 0x00800080; + mode->ppll_div_3 = 0x0002008c; +#endif + switch (bpp) { + case 24: + mode->surf_info[0] = 0x00a10100; + mode->surf_upper_bound[0] = 0x002fffff; + break; + case 16: + mode->surf_info[0] = 0x00510080; + mode->surf_upper_bound[0] = 0x0017ffff; + break; + default: /* 8 bpp */ + mode->surf_info[0] = 0x00010040; + mode->surf_upper_bound[0] = 0x000bffff; + break; + } + break; + case RES_MODE_800x600: + mode->crtc_h_total_disp = 0x00630083; + mode->crtc_h_sync_strt_wid = 0x00100340; + mode->crtc_v_total_disp = 0x02570273; + mode->crtc_v_sync_strt_wid = 0x00040258; + mode->ppll_div_3 = 0x0003008e; + switch (bpp) { + case 24: + mode->crtc_pitch = 0x00680068; + mode->surf_info[0] = 0x00a100d0; + mode->surf_upper_bound[0] = 0x001edfff; + break; + case 16: + mode->crtc_pitch = 0x00700070; + mode->surf_info[0] = 0x00510070; + mode->surf_upper_bound[0] = 0x00109fff; + break; + default: /* 8 bpp */ + mode->crtc_pitch = 0x00800080; + mode->surf_info[0] = 0x00010040; + mode->surf_upper_bound[0] = 0x00097fff; + break; + } + break; + default: /* RES_MODE_640x480 */ + mode->crtc_h_total_disp = 0x4f0063; + mode->crtc_h_sync_strt_wid = 0x8c02a2; + mode->crtc_v_total_disp = 0x01df020c; + mode->crtc_v_sync_strt_wid = 0x8201ea; + mode->crtc_pitch = 0x00500050; + mode->ppll_div_3 = 0x00030059; + switch (bpp) { + case 24: + mode->surf_info[0] = 0x00a100a0; + mode->surf_upper_bound[0] = 0x0012bfff; + break; + case 16: + mode->surf_info[0] = 0x00510050; + mode->surf_upper_bound[0] = 0x00095fff; + break; + default: /* 8 bpp */ + break; + } + break; + } + + OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); + OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl, + ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS)); + OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING); + OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); + OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); + OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); + OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); + OUTREG(CRTC_OFFSET, 0); + OUTREG(CRTC_OFFSET_CNTL, mode->crtc_offset_cntl); + OUTREG(CRTC_PITCH, mode->crtc_pitch); + + mode->clk_cntl_index = 0x300; + mode->ppll_ref_div = 0xc; + + radeon_write_pll_regs(rinfo, mode); + + OUTREG(SURFACE0_INFO, mode->surf_info[0]); + OUTREG(SURFACE0_LOWER_BOUND, 0); + OUTREG(SURFACE0_UPPER_BOUND, mode->surf_upper_bound[0]); + OUTREG(SURFACE_CNTL, mode->surface_cntl); + + OUTREG(DP_GUI_MASTER_CNTL, dp_gm_cntl); + OUTREG(0x0000325c, 0x0000000f); + + if (bpp == 24) + set_pal_24(); + else if (bpp == 16) + set_pal_16(); + + free(mode); +} + #include "../bios_emulator/include/biosemu.h" extern int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp);
@@ -421,29 +717,101 @@ GraphicDevice ctfb; void *video_hw_init(void) { GraphicDevice *pGD = (GraphicDevice *) & ctfb; - int i; u32 *vm; + char *penv; + unsigned long t1, hsynch, vsynch; + int bits_per_pixel, i, tmp, vesa_idx = 0, videomode; + struct ctfb_res_modes *res_mode; + struct ctfb_res_modes var_mode;
rinfo = malloc(sizeof(struct radeonfb_info));
+ printf("Video: "); if(radeon_probe(rinfo)) { printf("No radeon video card found!\n"); return NULL; }
- /* fill in Graphic device struct */ - sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", 640, - 480, 16, (1000 / 1000), - (2000 / 1000)); - printf ("%s\n", pGD->modeIdent); + tmp = 0; + + videomode = CFG_DEFAULT_VIDEO_MODE; + /* get video mode via environment */ + if ((penv = getenv ("videomode")) != NULL) { + /* deceide if it is a string */ + if (penv[0] <= '9') { + videomode = (int) simple_strtoul (penv, NULL, 16); + tmp = 1; + } + } else { + tmp = 1; + } + if (tmp) { + /* parameter are vesa modes */ + /* search params */ + for (i = 0; i < VESA_MODES_COUNT; i++) { + if (vesa_modes[i].vesanr == videomode) + break; + } + if (i == VESA_MODES_COUNT) { + printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE); + i = 0; + } + res_mode = (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex]; + bits_per_pixel = vesa_modes[i].bits_per_pixel; + vesa_idx = vesa_modes[i].resindex; + } else { + res_mode = (struct ctfb_res_modes *) &var_mode; + bits_per_pixel = video_get_params (res_mode, penv); + }
- pGD->winSizeX = 640; - pGD->winSizeY = 480; - pGD->plnSizeX = 640; - pGD->plnSizeY = 480; + /* calculate hsynch and vsynch freq (info only) */ + t1 = (res_mode->left_margin + res_mode->xres + + res_mode->right_margin + res_mode->hsync_len) / 8; + t1 *= 8; + t1 *= res_mode->pixclock; + t1 /= 1000; + hsynch = 1000000000L / t1; + t1 *= (res_mode->upper_margin + res_mode->yres + + res_mode->lower_margin + res_mode->vsync_len); + t1 /= 1000; + vsynch = 1000000000L / t1;
- pGD->gdfBytesPP = 1; - pGD->gdfIndex = GDF__8BIT_INDEX; + /* fill in Graphic device struct */ + sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres, + res_mode->yres, bits_per_pixel, (hsynch / 1000), + (vsynch / 1000)); + printf ("%s\n", pGD->modeIdent); + pGD->winSizeX = res_mode->xres; + pGD->winSizeY = res_mode->yres; + pGD->plnSizeX = res_mode->xres; + pGD->plnSizeY = res_mode->yres; + + switch (bits_per_pixel) { + case 24: + pGD->gdfBytesPP = 4; + pGD->gdfIndex = GDF_32BIT_X888RGB; + if (res_mode->xres == 800) { + pGD->winSizeX = 832; + pGD->plnSizeX = 832; + } + break; + case 16: + pGD->gdfBytesPP = 2; + pGD->gdfIndex = GDF_16BIT_565RGB; + if (res_mode->xres == 800) { + pGD->winSizeX = 896; + pGD->plnSizeX = 896; + } + break; + default: + if (res_mode->xres == 800) { + pGD->winSizeX = 1024; + pGD->plnSizeX = 1024; + } + pGD->gdfBytesPP = 1; + pGD->gdfIndex = GDF__8BIT_INDEX; + break; + }
pGD->isaBase = CFG_ISA_IO_BASE_ADDRESS; pGD->pciBase = rinfo->fb_base_phys; @@ -464,14 +832,17 @@ void *video_hw_init(void) pGD->cprBase = rinfo->fb_base_phys; /* Dummy */ /* set up Hardware */
- /* Clear video memory */ - i = pGD->memSize / 4; + /* Clear video memory (only visible screen area) */ + i = pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP / 4; vm = (unsigned int *) pGD->pciBase; while (i--) *vm++ = 0; /*SetDrawingEngine (bits_per_pixel);*/
- radeon_setmode(); + if (rinfo->family == CHIP_FAMILY_RV280) + radeon_setmode_9200(vesa_idx, bits_per_pixel); + else + radeon_setmode();
return ((void *) pGD); }