From mboxrd@z Thu Jan 1 00:00:00 1970 Message-ID: <6d6ceaeedeccf92df0e063ca84bce23a@plan9.bell-labs.com> From: David Presotto To: 9fans@cse.psu.edu Subject: Re: [9fans] Support for LCD screens for the Radeon driver In-Reply-To: <20040303163432.GA14994@ionkov.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="upas-bdaswwphppkwfdovyhfnvaswhy" Date: Tue, 9 Mar 2004 09:14:47 -0500 Topicbox-Message-UUID: 25a5bdec-eacd-11e9-9e20-41e7f4b1d025 This is a multi-part message in MIME format. --upas-bdaswwphppkwfdovyhfnvaswhy Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit On Wed Mar 3 11:35:53 EST 2004, lucho@ionkov.net wrote: > Hi, > > I added support for LCD screens in the Radeon driver. It only works if the > BIOS has panel information defined. I didn't test it for resolutions > different than the default for the display. I am attaching the two files > that are changed. You need the rest from > http://mapage.noos.fr/phillipe.anel/plan9rxxx.html. > > The driver does not support DFP panels, only LCD. I don't have DFP, so I > didn't bother to add support for something that I can't test. > > BTW, is there any reason for this driver to not be included in the distribution? It hasn't been added because, as far as I know, it hasn't been submitted. Perhaps a note on the license here. We don't consider anything a contribution unless you make it clear that something is. - If you email us a file or bug fixes to stick into the distribution we consider that clear intent. - if you actually say 'this is a contribution under the LPL' that's even better. I'ld prefer to see that in stuff that's genuinely new. Anything you write yourself you can release under as many licenses as you like. We are making a leap of faith that the code isn't ripped off from something released under another license (like the GPL). We do generally look at things and try to ascertain that but, not having seen all gnu code, we could miss things. If something is covered by another license, that's OK, but we'ld want to keep it separate in any distribution we do and add that license to its directory. If it passes our somewhat questionable taste, we'll stick it in the distribution. If it doesn't people are still free to call it a contribution (or not) and distribute it from some other site. At the moment 'we' comprises rsc, presotto, and jmk. --upas-bdaswwphppkwfdovyhfnvaswhy Content-Type: message/rfc822 Content-Disposition: inline Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Wed Mar 3 11:35:44 EST 2004 Received: from mail.cse.psu.edu ([130.203.4.6]) by plan9; Wed Mar 3 11:35:25 EST 2004 Received: by mail.cse.psu.edu (CSE Mail Server, from userid 60001) id BA97419F1B; Wed, 3 Mar 2004 11:35:21 -0500 (EST) Received: from psuvax1.cse.psu.edu (psuvax1.cse.psu.edu [130.203.4.6]) by mail.cse.psu.edu (CSE Mail Server) with ESMTP id 3871F19ECD; Wed, 3 Mar 2004 11:35:11 -0500 (EST) X-Original-To: 9fans@cse.psu.edu Delivered-To: 9fans@cse.psu.edu Received: by mail.cse.psu.edu (CSE Mail Server, from userid 60001) id 6F83719C3B; Wed, 3 Mar 2004 11:34:35 -0500 (EST) Received: from rwcrmhc11.comcast.net (rwcrmhc11.comcast.net [204.127.198.35]) by mail.cse.psu.edu (CSE Mail Server) with ESMTP id 2C38119EAF for <9fans@cse.psu.edu>; Wed, 3 Mar 2004 11:34:31 -0500 (EST) Received: from moria.ionkov.net ([68.38.117.182]) by comcast.net (rwcrmhc11) with ESMTP id <200403031634280130058dkbe>; Wed, 3 Mar 2004 16:34:29 +0000 Received: by moria.ionkov.net (Postfix, from userid 500) id E4CAF4622BF; Wed, 3 Mar 2004 11:34:32 -0500 (EST) From: Latchesar Ionkov To: 9fans@cse.psu.edu Message-ID: <20040303163432.GA14994@ionkov.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="IJpNTDwzlM2Ie8A6" Content-Disposition: inline User-Agent: Mutt/1.4.1i Subject: [9fans] Support for LCD screens for the Radeon driver Sender: 9fans-admin@cse.psu.edu Errors-To: 9fans-admin@cse.psu.edu X-BeenThere: 9fans@cse.psu.edu X-Mailman-Version: 2.0.11 Precedence: bulk Reply-To: 9fans@cse.psu.edu List-Id: Fans of the OS Plan 9 from Bell Labs <9fans.cse.psu.edu> List-Archive: Date: Wed, 3 Mar 2004 11:34:32 -0500 X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on psuvax1.cse.psu.edu X-Spam-Status: No, hits=0.3 required=5.0 tests=UPPERCASE_25_50 autolearn=no version=2.63 X-Spam-Level: --IJpNTDwzlM2Ie8A6 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, I added support for LCD screens in the Radeon driver. It only works if the BIOS has panel information defined. I didn't test it for resolutions different than the default for the display. I am attaching the two files that are changed. You need the rest from http://mapage.noos.fr/phillipe.anel/plan9rxxx.html. The driver does not support DFP panels, only LCD. I don't have DFP, so I didn't bother to add support for something that I can't test. BTW, is there any reason for this driver to not be included in the distribution? Thanks, Lucho --IJpNTDwzlM2Ie8A6 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="radeon.c" #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 */ }; --IJpNTDwzlM2Ie8A6 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="radeon_pciids.h" // ATI Technologies Inc #define ATI_PCIVID 0x1002 struct pciids { ushort did; int type; char* name; }; enum { ATI_R300, ATI_RV250, ATI_R250, ATI_RV200, ATI_R200, ATI_RV100, ATI_R100, ATI_MOBILITY, ATI_M6, ATI_M7, ATI_M9, }; struct pciids radeon_pciids[] = { // ATI_M6, LY // ATI_M6, LZ 0x4c57, ATI_M7, "Radeon Mobility M7 LW [Radeon Mobility 7500]", 0x4c58, ATI_M7, "Radeon RV200 LX [Mobility FireGL 7800 M7]", 0x4c59, ATI_M6, "Radeon Mobility M6 LY", 0x4c64, ATI_M9, "Radeon R250 Ld [Radeon Mobility 9000 M9]", 0x4c65, ATI_M9, "Radeon R250 Le [Radeon Mobility 9000 M9]", 0x4c66, ATI_M9, "Radeon R250 Lf [Radeon Mobility 9000 M9]", 0x4c67, ATI_M9, "Radeon R250 Lg [Radeon Mobility 9000 M9]", 0x5159, ATI_RV100, "Radeon RV100 QY [Radeon 7000/VE]", 0x515a, ATI_RV100, "Radeon RV100 QZ [Radeon 7000/VE]", 0x5144, ATI_R100, "Radeon R100 QD [Radeon 7200]", 0x5145, ATI_R100, "Radeon R100 QE", 0x5146, ATI_R100, "Radeon R100 QF", 0x5147, ATI_R100, "Radeon R100 QG", 0x5148, ATI_R200, "Radeon R200 QH [Radeon 8500]", 0x5149, ATI_R200, "Radeon R200 QI", 0x514a, ATI_R200, "Radeon R200 QJ", 0x514b, ATI_R200, "Radeon R200 QK", 0x514c, ATI_R200, "Radeon R200 QL [Radeon 8500 LE]", 0x514d, ATI_R200, "Radeon R200 QM [Radeon 9100]", 0x514e, ATI_R200, "Radeon R200 QN [Radeon 8500LE]", 0x514f, ATI_R200, "Radeon R200 QO [Radeon 8500LE]", 0x5168, ATI_R200, "Radeon R200 Qh", 0x5169, ATI_R200, "Radeon R200 Qi", 0x516a, ATI_R200, "Radeon R200 Qj", 0x516b, ATI_R200, "Radeon R200 Qk", 0x516c, ATI_R200, "Radeon R200 Ql", 0x5157, ATI_RV200, "Radeon RV200 QW [Radeon 7500]", 0x5158, ATI_RV200, "Radeon RV200 QX [Radeon 7500]", 0x4964, ATI_RV250, "Radeon R250 Id [Radeon 9000]", 0x4965, ATI_RV250, "Radeon R250 Ie [Radeon 9000]", 0x4966, ATI_RV250, "Radeon R250 If [Radeon 9000]", 0x4967, ATI_RV250, "Radeon R250 Ig [Radeon 9000]", 0x4144, ATI_R300, "Radeon R300 AD [Radeon 9500 Pro]", 0x4145, ATI_R300, "Radeon R300 AE [Radeon 9500 Pro]", 0x4146, ATI_R300, "Radeon R300 AF [Radeon 9500 Pro]", 0x4147, ATI_R300, "Radeon R300 AG [FireGL Z1/X1]", 0x4e44, ATI_R300, "Radeon R300 ND [Radeon 9700]", 0x4e45, ATI_R300, "Radeon R300 NE [Radeon 9700]", 0x4e46, ATI_R300, "Radeon R300 NF [Radeon 9700]", 0x4e47, ATI_R300, "Radeon R300 NG [FireGL X1]", 0x4e64, ATI_R300, "Radeon R300 [Radeon 9700 Pro] (Secondary)", 0x4e65, ATI_R300, "Radeon R300 [Radeon 9700] (Secondary)", 0x4e66, ATI_R300, "Radeon R300 [Radeon 9700] (Secondary)", 0x4e67, ATI_R300, "Radeon R300 [FireGL X1] (Secondary)", 0 }; --IJpNTDwzlM2Ie8A6-- --upas-bdaswwphppkwfdovyhfnvaswhy--