#include #include #include #include "pci.h" #include "vga.h" #include "radeon.h" #include "radeon_pciids.h" static int debug = 0; #define DBGPRINT if (debug) print /* *********************************************** */ enum { Kilo = 1024, Mega = (Kilo*Kilo), }; enum { DISPLAY_NONE, DISPLAY_CRT, DISPLAY_FP, DISPLAY_LCD, }; /* *********************************************** */ typedef struct Radeon Radeon; struct Radeon { ulong mmio; Pcidev* pci; uchar* bios; ulong fbsize; int display_type; ulong ovr_clr; ulong ovr_wid_top_bottom; ulong ovr_wid_left_right; ulong ov0_scale_cntl; ulong subpic_cntl; ulong viph_control; ulong i2c_cntl_1; ulong rbbm_soft_reset; ulong cap0_trig_cntl; ulong cap1_trig_cntl; ulong gen_int_cntl; ulong bus_cntl; ulong crtc_gen_cntl; ulong crtc_ext_cntl; ulong dac_cntl; ulong crtc_h_total_disp; ulong crtc_h_sync_strt_wid; ulong crtc_v_total_disp; ulong crtc_v_sync_strt_wid; ulong crtc_pitch; ulong crtc_offset; ulong crtc_offset_cntl; ulong htotal_cntl; ulong surface_cntl; int type; ulong fp_horz_stretch; ulong fp_vert_stretch; ulong fp_crtc_h_total_disp; ulong fp_crtc_v_total_disp; ulong fp_h_sync_strt_wid; ulong fp_v_sync_strt_wid; ulong fp_gen_cntl; ulong lvds_gen_cntl; // inited from rom ushort reference_freq, reference_div, xclk; ulong max_pll_freq, min_pll_freq; ulong pll_output_freq; ulong feedback_div; ulong dot_clock_freq; ulong post_div; ulong ppll_ref_div; ulong ppll_div_3; // panel info int xres, yres; int valid; int clock; int hOver_plus, hSync_width, hblank; int vOver_plus, vSync_width, vblank; int pwr_delay; int use_bios_dividers; int ref_divider; int post_divider; int fbk_divider; int hAct_high, vAct_high; }; /* from io.c */ extern char* readbios(long len, long offset); /* *********************************************** */ static void radeon300_workaround(Radeon* radeon); static void radeon_get_bios_panel_info(Radeon* radeon); static void OUTREG8(Radeon* radeon, ulong offset, uchar val) { ((uchar*) (radeon->mmio + offset))[0] = val; } static void OUTREG(Radeon* radeon, ulong offset, ulong val) { ((ulong*) (radeon->mmio + offset))[0] = val; } static ulong INREG(Radeon* radeon, ulong offset) { ulong data; data = ((ulong*) (radeon->mmio + offset))[0]; return data; } static void OUTREGP(Radeon* radeon, ulong offset, ulong val, ulong mask) { ulong tmp; tmp = INREG(radeon, offset); tmp &= mask; tmp |= val; OUTREG(radeon, offset, tmp); } static void OUTPLL(Radeon* radeon, ulong offset, ulong val) { uchar tmp; tmp = (offset & 0x3f) | RADEON_PLL_WR_EN; OUTREG8(radeon, RADEON_CLOCK_CNTL_INDEX, tmp); OUTREG(radeon, RADEON_CLOCK_CNTL_DATA, val); } static ulong INPLL(Radeon* radeon, ulong offset) { ulong data; OUTREG8(radeon, RADEON_CLOCK_CNTL_INDEX, offset & 0x3f); data = INREG(radeon, RADEON_CLOCK_CNTL_DATA); if (radeon->type & ATI_R300) radeon300_workaround(radeon); return data; } static void OUTPLLP(Radeon* radeon, ulong offset, ulong val, ulong mask) { ulong tmp; tmp = INPLL(radeon, offset); tmp &= mask; tmp |= val; OUTPLL(radeon, offset, tmp); } static void radeon300_workaround(Radeon* radeon) { ulong save, tmp; save = INREG(radeon, RADEON_CLOCK_CNTL_INDEX); tmp = save & ~(0x3f | RADEON_PLL_WR_EN); OUTREG(radeon, RADEON_CLOCK_CNTL_INDEX, tmp); tmp = INREG(radeon, RADEON_CLOCK_CNTL_DATA); OUTREG(radeon, RADEON_CLOCK_CNTL_INDEX, save); USED(tmp); } /* *********************************************** */ static void radeon_getbiosparams(Radeon* radeon) { ushort offset; ulong addr; uchar* bios; ushort pib; radeon->bios = nil; addr = 0xC0000; bios = (uchar*)readbios(0x10000, addr); if (bios[0] != 0x55 || bios[1] != 0xAA) { addr = 0xE0000; bios = (uchar*)readbios(0x10000, addr); if (bios[0] != 0x55 || bios[1] != 0xAA) { print("radeon: bios not found\n"); return; } } radeon->bios = bios; offset = RADEON_BIOS16(radeon, RADEON_BIOS_START); pib = RADEON_BIOS16(radeon, offset+0x30); radeon->reference_freq = RADEON_BIOS16(radeon, pib+0x0e); radeon->reference_div = RADEON_BIOS16(radeon, pib+0x10); radeon->min_pll_freq = RADEON_BIOS32(radeon, pib+0x12); radeon->max_pll_freq = RADEON_BIOS32(radeon, pib+0x16); radeon->xclk = RADEON_BIOS16(radeon, pib+0x08); DBGPRINT("radeon: bios=0x%08ulx offset=0x%ux\n", addr, offset); DBGPRINT("radeon: pll_info_block: 0x%ux\n", pib); DBGPRINT("radeon: reference_freq: %ud\n", radeon->reference_freq); DBGPRINT("radeon: reference_div: %ud\n", radeon->reference_div); DBGPRINT("radeon: min_pll_freq: %uld\n", radeon->min_pll_freq); DBGPRINT("radeon: max_pll_freq: %uld\n", radeon->max_pll_freq); DBGPRINT("radeon: xclk: %ud\n", radeon->xclk); if (radeon->display_type == DISPLAY_LCD) { radeon_get_bios_panel_info(radeon); } } static void radeon_get_bios_panel_info(Radeon* radeon) { int fp_bios_start = RADEON_BIOS16(radeon, 0x48); int fpofs = RADEON_BIOS16(radeon, fp_bios_start + 0x40); int i; if (!fpofs) { radeon->xres = radeon->yres = 0; return; } radeon->xres = RADEON_BIOS16(radeon, fpofs + 25); radeon->yres = RADEON_BIOS16(radeon, fpofs + 27); radeon->pwr_delay = RADEON_BIOS16(radeon, fpofs + 44); if (radeon->pwr_delay>2000 || radeon->pwr_delay<=0) { radeon->pwr_delay = 2000; } radeon->ref_divider = RADEON_BIOS16(radeon, fpofs + 46); radeon->post_divider = RADEON_BIOS8(radeon, fpofs + 48); radeon->fbk_divider = RADEON_BIOS16(radeon, fpofs + 49); if (radeon->ref_divider != 0 && radeon->fbk_divider > 3) { radeon->use_bios_dividers = 1; } DBGPRINT("radeon: panel size: %dx%d\n", radeon->xres, radeon->yres); DBGPRINT("radeon: power delay: %d\n", radeon->pwr_delay); for(i = 0; i < 32; i++) { int x, y; int ofs = RADEON_BIOS16(radeon, fpofs + 64 + i * 2); if (ofs == 0) { break; } x = RADEON_BIOS16(radeon, ofs); y = RADEON_BIOS16(radeon, ofs + 2); if (x==radeon->xres && y==radeon->yres) { radeon->hblank = (RADEON_BIOS16(radeon, ofs+17) - RADEON_BIOS16(radeon, ofs + 19)) * 8; radeon->hOver_plus = ((RADEON_BIOS16(radeon, ofs+21) - RADEON_BIOS16(radeon, ofs+19) -1) * 8) & 0x7FFF; radeon->hSync_width = RADEON_BIOS8(radeon, ofs+23) * 8; radeon->vblank = RADEON_BIOS16(radeon, ofs+24) - RADEON_BIOS16(radeon, ofs+26); radeon->vOver_plus = (RADEON_BIOS16(radeon, ofs+28) & 0x7ff) - RADEON_BIOS16(radeon, ofs+26); radeon->vSync_width = (RADEON_BIOS16(radeon, ofs+28) & 0xf800) >> 11; radeon->clock = RADEON_BIOS16(radeon, ofs+9); radeon->hAct_high = 1; radeon->vAct_high = 1; return; } } radeon->xres = radeon->yres = 0; } /* *********************************************** */ static Pcidev* radeonpci(int* type) { static Pcidev *p = nil; struct pciids *ids; if (p != nil) return p; DBGPRINT("radeon: ATI Technologies Inc. " "Radeon [789]xxx drivers (v0.1)\n"); p = pcimatch(nil, ATI_PCIVID, 0); if (p == nil) return nil; for (ids = radeon_pciids; ids->did; ids++) { if (ids->did == p->did) { DBGPRINT("radeon: Found %s\n", ids->name); DBGPRINT("radeon: did:%04ux rid:%02ux\n", p->did, p->rid); if (type) *type = ids->type; return p; } } DBGPRINT("radeon: not found!\n"); return p = nil; } /* *********************************************** */ static void vga_disable(Vga* vga) { Ctlr* c; for(c = vga->link; c; c = c->link) if (strncmp(c->name, "vga", 3) == 0) { c->load = nil; } } /* *********************************************** */ static void radeon_snarf(Vga* vga, Ctlr* ctlr) { Radeon *radeon; Pcidev *p; ulong mmio, tmp; int type; if (vga->private == nil) { vga_disable(vga); vga->private = alloc(sizeof(Radeon)); radeon = vga->private; p = radeonpci(&type); if (p == nil) error("%s: not found\n", ctlr->name); vgactlw("type", ctlr->name); mmio = segattach(0, "radeonmmio", 0, p->mem[2].size); if (mmio == ~0) error("%s: can't attach mmio segment\n", ctlr->name); DBGPRINT("radeon: mmio address: 0x%08ulx [size=0x%x]\n", mmio, p->mem[2].size); radeon->pci = p; radeon->type = type; radeon->mmio = mmio; } radeon = vga->private; radeon->fbsize = INREG(radeon, RADEON_CONFIG_MEMSIZE); vga->vmz = radeon->fbsize; DBGPRINT("radeon: frame buffer size=%uld [%uldMB]\n", radeon->fbsize, radeon->fbsize/Mega); tmp = INREG(radeon, RADEON_FP_GEN_CNTL); if (tmp & RADEON_FP_EN_TMDS) radeon->display_type = DISPLAY_FP; if (radeon->display_type == DISPLAY_NONE && radeon->type > ATI_MOBILITY) { if (INREG(radeon, RADEON_BIOS_4_SCRATCH) & 4 || INREG(radeon, RADEON_LVDS_GEN_CNTL) & RADEON_LVDS_ON) { radeon->display_type = DISPLAY_LCD; } } if (radeon->display_type == DISPLAY_NONE) { radeon->display_type = DISPLAY_CRT; } DBGPRINT("radeon: display type: %d\n", radeon->display_type); radeon_getbiosparams(radeon); radeon->bus_cntl = INREG(radeon, RADEON_BUS_CNTL); DBGPRINT("radeon: PPLL_CNTL=0x%08ulx\n", INPLL(radeon, RADEON_PPLL_CNTL)); if (radeon->display_type != DISPLAY_CRT && radeon->display_type != DISPLAY_LCD) error("unsupported FP Display\n"); if (radeon->display_type == DISPLAY_LCD && radeon->xres == 0) { error("cannot find panel information\n"); } ctlr->flag |= Fsnarf; } /* *********************************************** */ static void options(Vga*, Ctlr* ctlr) { ctlr->flag |= Hlinear|Foptions; } /* *********************************************** */ static int radeondiv(int n, int d) { return (n + (d / 2)) / d; } /* *********************************************** */ static void radeon_init_common_registers(Radeon* radeon) { radeon->ovr_clr = 0; radeon->ovr_wid_left_right = 0; radeon->ovr_wid_top_bottom = 0; radeon->ov0_scale_cntl = 0; radeon->subpic_cntl = 0; radeon->viph_control = 0; radeon->i2c_cntl_1 = 0; radeon->rbbm_soft_reset = 0; radeon->cap0_trig_cntl = 0; radeon->cap1_trig_cntl = 0; if (radeon->bus_cntl & RADEON_BUS_READ_BURST) radeon->bus_cntl |= RADEON_BUS_RD_DISCARD_EN; } /* *********************************************** */ static void radeon_init_crtc_registers(Radeon* radeon, Mode* mode) { int format, dac6bit; int hsync_wid, vsync_wid; int hsync_start; int hTotal, hSyncStart, hSyncEnd, h_sync_pol; int vTotal, vSyncStart, vSyncEnd, v_sync_pol; int hsync_fudge, bpp; int hsync_fudge_crt[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; int hsync_fudge_fp[] = { 2, 2, 0, 0, 5, 5, }; format = 0; bpp = 0; dac6bit = 0; switch (mode->z) { case 6: format = 2; dac6bit = 1; bpp = 8; break; case 8: format = 2; dac6bit = 0; bpp = 8; break; case 15: format = 3; dac6bit = 0; bpp = 16; break; case 16: format = 4; dac6bit = 0; bpp = 16; break; case 24: format = 5; dac6bit = 0; bpp = 24; break; case 32: format = 6; dac6bit = 0; bpp = 32; break; default: error("radeon: unsupported mode depth %d\n", mode->z); } if (radeon->display_type == DISPLAY_CRT) { hsync_fudge = hsync_fudge_crt[format - 1]; } else { hsync_fudge = hsync_fudge_fp[format - 1]; } DBGPRINT("mode->z = %d (format = %d, bpp = %d, dac6bit = %s)\n", mode->z, format, bpp, dac6bit ? "true" : "false"); radeon->crtc_gen_cntl = RADEON_CRTC_EN | RADEON_CRTC_EXT_DISP_EN | (format << 8); radeon->crtc_ext_cntl = RADEON_VGA_ATI_LINEAR | RADEON_XCRT_CNT_EN; if (radeon->display_type == DISPLAY_CRT) { radeon->crtc_ext_cntl |= RADEON_CRTC_CRT_ON; radeon->crtc_gen_cntl |= mode->interlace ? RADEON_CRTC_INTERLACE_EN : 0; } else { radeon->crtc_gen_cntl &= ~(RADEON_CRTC_DBL_SCAN_EN | RADEON_CRTC_INTERLACE_EN); } radeon->dac_cntl = RADEON_DAC_MASK_ALL | RADEON_DAC_VGA_ADR_EN | (dac6bit ? 0 : RADEON_DAC_8BIT_EN); // ----------------------------------------------------------- if (radeon->display_type == DISPLAY_CRT) { hTotal = mode->ht; hSyncStart = mode->shb; hSyncEnd = mode->ehb; h_sync_pol = mode->hsync; vTotal = mode->vt; vSyncStart = mode->vrs; vSyncEnd = mode->vre; v_sync_pol = mode->vsync; } else { hTotal = mode->x + radeon->hblank; hSyncStart = mode->x + radeon->hOver_plus; hSyncEnd = mode->x + radeon->hSync_width; h_sync_pol = !radeon->hAct_high; vTotal = mode->y + radeon->vblank; vSyncStart = mode->y + radeon->vOver_plus; vSyncEnd = mode->y + radeon->vSync_width; v_sync_pol = !radeon->vAct_high; mode->frequency = radeon->clock; // hack } radeon->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | ((((mode->x / 8) - 1) & 0x1ff) << 16)); hsync_wid = (hSyncEnd - hSyncStart) / 8; if (! hsync_wid) hsync_wid = 1; if (hsync_wid > 0x3F) hsync_wid = 0x3F; hsync_start = hSyncStart - 8 + hsync_fudge; DBGPRINT("hsync_start=%d hsync_wid=%d hsync_fudge=%d\n", hsync_start, hsync_wid, hsync_fudge); radeon->crtc_h_sync_strt_wid = ( (hsync_start & 0x1fff) | ((hsync_wid & 0x3f) << 16) | (h_sync_pol ? RADEON_CRTC_H_SYNC_POL : 0)); // ----------------------------------------------------------- radeon->crtc_v_total_disp = (((vTotal - 1) & 0xffff) | ((mode->y - 1) << 16)); vsync_wid = vSyncEnd - vSyncStart; if (! vsync_wid) vsync_wid = 1; radeon->crtc_v_sync_strt_wid = ( ((mode->vrs - 1) & 0xfff) | ((vsync_wid & 0x1f) << 16) | (v_sync_pol ? RADEON_CRTC_V_SYNC_POL : 0)); // ----------------------------------------------------------- radeon->crtc_offset = 0; radeon->crtc_offset_cntl = INREG(radeon, RADEON_CRTC_OFFSET_CNTL); radeon->crtc_pitch = ((mode->x * bpp) + ((bpp * 8) - 1)) / (bpp * 8); radeon->crtc_pitch |= radeon->crtc_pitch << 16; } /* *********************************************** */ static void radeon_init_pll_registers(Radeon* radeon, ulong freq) { struct { int divider; int bitvalue; } *post_div, post_divs[] = { { 1, 0 }, { 2, 1 }, { 4, 2 }, { 8, 3 }, { 3, 4 }, { 16, 5 }, { 6, 6 }, { 12, 7 }, { 0, 0 } }; DBGPRINT("radeon: initpll: freq=%uld\n", freq); if (freq > radeon->max_pll_freq) freq = radeon->max_pll_freq; if (freq * 12 < radeon->min_pll_freq) freq = radeon->min_pll_freq / 12; for (post_div = &post_divs[0]; post_div->divider; ++post_div) { radeon->pll_output_freq = post_div->divider * freq; if (radeon->pll_output_freq >= radeon->min_pll_freq && radeon->pll_output_freq <= radeon->max_pll_freq) break; } radeon->dot_clock_freq = freq; radeon->feedback_div = radeondiv(radeon->reference_div * radeon->pll_output_freq, radeon->reference_freq); radeon->post_div = post_div->divider; DBGPRINT("dc=%uld, of=%uld, fd=%uld, pd=%uld\n", radeon->dot_clock_freq, radeon->pll_output_freq, radeon->feedback_div, radeon->post_div); if (radeon->use_bios_dividers) { radeon->ppll_ref_div = radeon->ref_divider; radeon->ppll_div_3 = radeon->fbk_divider | (radeon->post_divider << 16); } else { radeon->ppll_ref_div = radeon->reference_div; radeon->ppll_div_3 = (radeon->feedback_div | (post_div->bitvalue << 16)); } radeon->htotal_cntl = 0; radeon->surface_cntl = 0; } static void radeon_init_fp_registers(Radeon* radeon, Mode* mode) { int x = mode->x; int y = mode->y; if (x > radeon->xres) { x = radeon->xres; } if (y > radeon->yres) { y = radeon->yres; } radeon->fp_horz_stretch = ((radeon->xres - 1) / 8) << RADEON_HORZ_PANEL_SHIFT; radeon->fp_vert_stretch = (radeon->yres - 1) << RADEON_VERT_PANEL_SHIFT; if (x != radeon->xres) { unsigned int hRatio = radeondiv(x * RADEON_HORZ_STRETCH_RATIO_MAX, radeon->xres); radeon->fp_horz_stretch = (((((unsigned long)hRatio) & RADEON_HORZ_STRETCH_RATIO_MASK)) | (radeon->fp_horz_stretch & (RADEON_HORZ_PANEL_SIZE | RADEON_HORZ_FP_LOOP_STRETCH | RADEON_HORZ_AUTO_RATIO_INC))); radeon->fp_horz_stretch |= (RADEON_HORZ_STRETCH_BLEND | RADEON_HORZ_STRETCH_ENABLE); } radeon->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO; if (y != radeon->yres) { unsigned int vRatio = radeondiv(y * RADEON_VERT_STRETCH_RATIO_MAX, radeon->yres); radeon->fp_vert_stretch = (((((unsigned long)vRatio) & RADEON_VERT_STRETCH_RATIO_MASK)) | (radeon->fp_vert_stretch & (RADEON_VERT_PANEL_SIZE | RADEON_VERT_STRETCH_RESERVED))); radeon->fp_vert_stretch |= (RADEON_VERT_STRETCH_BLEND | RADEON_VERT_STRETCH_ENABLE); } radeon->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN; radeon->fp_crtc_h_total_disp = (((radeon->hblank / 8) & 0x3ff) | (((x / 8) - 1) << 16)); radeon->fp_crtc_v_total_disp = (radeon->vblank & 0xffff) | ((y - 1) << 16); radeon->fp_h_sync_strt_wid = radeon->hOver_plus & 0x1fff | (radeon->crtc_h_sync_strt_wid & (~ 0x1fff)); radeon->fp_v_sync_strt_wid = ((radeon->vOver_plus & 0xfff) | (radeon->crtc_v_sync_strt_wid & (0xfff))); radeon->fp_gen_cntl = INREG(radeon, RADEON_FP_GEN_CNTL) & ~(RADEON_FP_SEL_CRTC2 | RADEON_FP_RMX_HVSYNC_CONTROL_EN | RADEON_FP_DFP_SYNC_SEL | RADEON_FP_CRT_SYNC_SEL | RADEON_FP_CRTC_LOCK_8DOT | RADEON_FP_USE_SHADOW_EN | RADEON_FP_CRTC_USE_SHADOW_VEND | RADEON_FP_CRT_SYNC_ALT); radeon->fp_gen_cntl |= (RADEON_FP_CRTC_DONT_SHADOW_VPAR | RADEON_FP_CRTC_DONT_SHADOW_HEND); radeon->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); radeon->lvds_gen_cntl = INREG(radeon, RADEON_LVDS_GEN_CNTL) | (RADEON_LVDS_ON | RADEON_LVDS_BLON); } /* *********************************************** */ static void radeon_init(Vga* vga, Ctlr* ctlr) { Radeon* radeon; Mode* mode; radeon = vga->private; mode = vga->mode; DBGPRINT("radeon: monitor type = '%s'\n", mode->type); DBGPRINT("radeon: size = '%s'\n", mode->size); DBGPRINT("radeon: chan = '%s'\n", mode->chan); DBGPRINT("radeon: freq=%d deffreq=%d x=%d y=%d z=%d\n", mode->frequency, mode->deffrequency, mode->x, mode->y, mode->z); DBGPRINT("radeon: ht=%d shb=%d ehb=%d shs=%d ehs=%d hsync='%c'\n", mode->ht, mode->shb, mode->ehb, mode->shs, mode->ehs, mode->hsync ? mode->hsync : ' '); DBGPRINT("radeon: vt=%d vrs=%d vre=%d vsync='%c'\n", mode->vt, mode->vrs, mode->vre, mode->vsync ? mode->vsync : ' '); radeon_init_common_registers(radeon); radeon_init_crtc_registers(radeon, mode); if (radeon->display_type != DISPLAY_CRT) { radeon_init_fp_registers(radeon, mode); } radeon_init_pll_registers(radeon, mode->frequency / 10000); ctlr->flag |= (Finit|Ulinear); } /* *********************************************** */ static void radeon_blank(Radeon* radeon) { switch (radeon->display_type) { case DISPLAY_LCD: OUTREGP(radeon, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_DISPLAY_DIS, ~RADEON_LVDS_DISPLAY_DIS); case DISPLAY_CRT: OUTREGP(radeon, RADEON_CRTC_EXT_CNTL, RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS, ~(RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS)); break; } } static void radeon_unblank(Radeon* radeon) { switch (radeon->display_type) { case DISPLAY_LCD: OUTREGP(radeon, RADEON_LVDS_GEN_CNTL, 0, ~RADEON_LVDS_DISPLAY_DIS); case DISPLAY_CRT: OUTREGP(radeon, RADEON_CRTC_EXT_CNTL, RADEON_CRTC_CRT_ON, ~(RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS)); break; } } /* *********************************************** */ static void radeon_load_common_registers(Radeon* radeon) { OUTREG(radeon, RADEON_OVR_CLR, radeon->ovr_clr); OUTREG(radeon, RADEON_OVR_WID_LEFT_RIGHT, radeon->ovr_wid_left_right); OUTREG(radeon, RADEON_OVR_WID_TOP_BOTTOM, radeon->ovr_wid_top_bottom); OUTREG(radeon, RADEON_OV0_SCALE_CNTL, radeon->ov0_scale_cntl); OUTREG(radeon, RADEON_SUBPIC_CNTL, radeon->subpic_cntl); OUTREG(radeon, RADEON_VIPH_CONTROL, radeon->viph_control); OUTREG(radeon, RADEON_I2C_CNTL_1, radeon->i2c_cntl_1); OUTREG(radeon, RADEON_GEN_INT_CNTL, radeon->gen_int_cntl); OUTREG(radeon, RADEON_CAP0_TRIG_CNTL, radeon->cap0_trig_cntl); OUTREG(radeon, RADEON_CAP1_TRIG_CNTL, radeon->cap1_trig_cntl); OUTREG(radeon, RADEON_BUS_CNTL, radeon->bus_cntl); OUTREG(radeon, RADEON_SURFACE_CNTL, radeon->surface_cntl); } /* *********************************************** */ static void radeon_load_crtc_registers(Radeon* radeon) { OUTREG(radeon, RADEON_CRTC_GEN_CNTL, radeon->crtc_gen_cntl); OUTREGP(radeon, RADEON_CRTC_EXT_CNTL, radeon->crtc_ext_cntl, ~(RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS)); OUTREGP(radeon, RADEON_DAC_CNTL, radeon->dac_cntl, RADEON_DAC_RANGE_CNTL | RADEON_DAC_BLANKING); OUTREG(radeon, RADEON_CRTC_H_TOTAL_DISP, radeon->crtc_h_total_disp); OUTREG(radeon, RADEON_CRTC_H_SYNC_STRT_WID, radeon->crtc_h_sync_strt_wid); OUTREG(radeon, RADEON_CRTC_V_TOTAL_DISP, radeon->crtc_v_total_disp); OUTREG(radeon, RADEON_CRTC_V_SYNC_STRT_WID, radeon->crtc_v_sync_strt_wid); OUTREG(radeon, RADEON_CRTC_OFFSET, radeon->crtc_offset); OUTREG(radeon, RADEON_CRTC_OFFSET_CNTL, radeon->crtc_offset_cntl); OUTREG(radeon, RADEON_CRTC_PITCH, radeon->crtc_pitch); } /* *********************************************** */ static void radeon_pllwaitupd(Radeon* radeon) { int i; for (i = 0; i < 10000; i++) { ulong pllreg; pllreg = INPLL(radeon, RADEON_PPLL_REF_DIV); if ((pllreg & RADEON_PPLL_ATOMIC_UPDATE_R) == 0) break; } } /* *********************************************** */ static void radeon_pllwriteupd(Radeon* radeon) { while (1) { ulong pllreg; pllreg = INPLL(radeon, RADEON_PPLL_REF_DIV); if ((pllreg & RADEON_PPLL_ATOMIC_UPDATE_R) == 0) break; } OUTPLLP(radeon, RADEON_PPLL_REF_DIV, RADEON_PPLL_ATOMIC_UPDATE_W, ~RADEON_PPLL_ATOMIC_UPDATE_W); } static void radeon_load_fp_registers(Radeon* radeon) { unsigned long lctl; OUTREG(radeon, RADEON_FP_CRTC_H_TOTAL_DISP, radeon->fp_crtc_h_total_disp); OUTREG(radeon, RADEON_FP_CRTC_V_TOTAL_DISP, radeon->fp_crtc_v_total_disp); OUTREG(radeon, RADEON_FP_H_SYNC_STRT_WID, radeon->fp_h_sync_strt_wid); OUTREG(radeon, RADEON_FP_V_SYNC_STRT_WID, radeon->fp_v_sync_strt_wid); OUTREG(radeon, RADEON_FP_HORZ_STRETCH, radeon->fp_horz_stretch); OUTREG(radeon, RADEON_FP_VERT_STRETCH, radeon->fp_vert_stretch); OUTREG(radeon, RADEON_FP_GEN_CNTL, radeon->fp_gen_cntl); lctl = INREG(radeon, RADEON_LVDS_GEN_CNTL); if ((lctl & (RADEON_LVDS_ON | RADEON_LVDS_BLON)) == (radeon->lvds_gen_cntl & (RADEON_LVDS_ON | RADEON_LVDS_BLON))) { OUTREG(radeon, RADEON_LVDS_GEN_CNTL, radeon->lvds_gen_cntl); } else { unsigned long pctl = INPLL(radeon, RADEON_PIXCLKS_CNTL); OUTPLLP(radeon, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLKS_CNTL); if (! (lctl & (RADEON_LVDS_ON | RADEON_LVDS_BLON))) { OUTREG(radeon, RADEON_LVDS_GEN_CNTL, radeon->lvds_gen_cntl | RADEON_LVDS_BLON); } sleep(radeon->pwr_delay); // ms OUTREG(radeon, RADEON_LVDS_GEN_CNTL, radeon->lvds_gen_cntl); if (pctl) { OUTPLL(radeon, RADEON_PIXCLKS_CNTL, pctl); } } } /* *********************************************** */ static void radeon_load_pll_registers(Radeon* radeon) { OUTPLLP(radeon, RADEON_VCLK_ECP_CNTL, RADEON_VCLK_SRC_SEL_CPUCLK, ~RADEON_VCLK_SRC_SEL_MASK); OUTPLLP(radeon, RADEON_PPLL_CNTL, RADEON_PPLL_RESET | RADEON_PPLL_ATOMIC_UPDATE_EN | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN, ~(RADEON_PPLL_RESET | RADEON_PPLL_ATOMIC_UPDATE_EN | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); OUTREGP(radeon, RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_DIV_SEL, ~RADEON_PLL_DIV_SEL); if (radeon->type & ATI_R300) { DBGPRINT("r300_workaround\n"); if (radeon->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { /* When restoring console mode, use saved PPLL_REF_DIV * setting. */ OUTPLLP(radeon, RADEON_PPLL_REF_DIV, radeon->ppll_ref_div, 0); } else { /* R300 uses ref_div_acc field as real ref divider */ OUTPLLP(radeon, RADEON_PPLL_REF_DIV, (radeon->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), ~R300_PPLL_REF_DIV_ACC_MASK); } } else { OUTPLLP(radeon, RADEON_PPLL_REF_DIV, radeon->ppll_ref_div, ~RADEON_PPLL_REF_DIV_MASK); } OUTPLLP(radeon, RADEON_PPLL_DIV_3, radeon->ppll_div_3, ~RADEON_PPLL_FB3_DIV_MASK); OUTPLLP(radeon, RADEON_PPLL_DIV_3, radeon->ppll_div_3, ~RADEON_PPLL_POST3_DIV_MASK); radeon_pllwriteupd(radeon); radeon_pllwaitupd(radeon); OUTPLL(radeon, RADEON_HTOTAL_CNTL, radeon->htotal_cntl); OUTPLLP(radeon, RADEON_PPLL_CNTL, 0, ~(RADEON_PPLL_RESET | RADEON_PPLL_SLEEP | RADEON_PPLL_ATOMIC_UPDATE_EN | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); if (debug) { Bprint(&stdout, "Wrote: 0x%08ulx 0x%08ulx 0x%08ulx (0x%08ulx)\n", radeon->ppll_ref_div, radeon->ppll_div_3, radeon->htotal_cntl, INPLL(radeon, RADEON_PPLL_CNTL)); Bprint(&stdout, "Wrote: rd=%uld, fd=%uld, pd=%uld\n", radeon->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, radeon->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, (radeon->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); } /* Let the clock to lock */ sleep(5); OUTPLLP(radeon, RADEON_VCLK_ECP_CNTL, RADEON_VCLK_SRC_SEL_PPLLCLK, ~RADEON_VCLK_SRC_SEL_MASK); } /* *********************************************** */ static void radeon_load(Vga* vga, Ctlr* ctlr) { Radeon* radeon; radeon = (Radeon*) vga->private; radeon_blank(radeon); radeon_load_common_registers(radeon); radeon_load_crtc_registers(radeon); // if (radeon->display_type != DISPLAY_CRT) { radeon_load_fp_registers(radeon); // } radeon_load_pll_registers(radeon); radeon_unblank(radeon); // init palette [gamma] if (vga->mode->z > 8) { int i; OUTREG(radeon, RADEON_PALETTE_INDEX, 0); for (i = 0; i < 256; i++) OUTREG(radeon, RADEON_PALETTE_DATA, (i<<16)|(i<<8)|i); } ctlr->flag |= Fload; } /* *********************************************** */ static void dump(Vga* vga, Ctlr* ctlr) { Radeon * radeon; USED(ctlr); radeon = (Radeon*) vga->private; USED(radeon); } /* *********************************************** */ Ctlr radeon = { "radeon", /* name */ radeon_snarf, /* snarf */ options, /* options */ radeon_init, /* init */ radeon_load, /* load */ dump, /* dump */ }; /* *********************************************** */ Ctlr radeonhwgc = { "radeonhwgc", /* name */ 0, /* snarf */ 0, /* options */ 0, /* init */ 0, /* load */ 0, /* dump */ };