9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: David Presotto <presotto@closedmind.org>
To: 9fans@cse.psu.edu
Subject: Re: [9fans] Support for LCD screens for the Radeon driver
Date: Tue,  9 Mar 2004 09:14:47 -0500	[thread overview]
Message-ID: <6d6ceaeedeccf92df0e063ca84bce23a@plan9.bell-labs.com> (raw)
In-Reply-To: <20040303163432.GA14994@ionkov.net>

[-- Attachment #1: Type: text/plain, Size: 1810 bytes --]

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.

[-- Attachment #2: Type: message/rfc822, Size: 33220 bytes --]

[-- Attachment #2.1.1: Type: text/plain, Size: 564 bytes --]

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

[-- Attachment #2.1.2: radeon.c --]
[-- Type: text/plain, Size: 27623 bytes --]


#include <u.h>
#include <libc.h>
#include <bio.h>

#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 */
};


[-- Attachment #2.1.3: radeon_pciids.h --]
[-- Type: text/plain, Size: 2652 bytes --]


// 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
};

  parent reply	other threads:[~2004-03-09 14:14 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-03-03 16:34 Latchesar Ionkov
2004-03-03 16:36 ` Fco.J.Ballesteros
2004-03-04  6:06 ` Kenji Okamoto
2004-03-04  5:22   ` andrey mirtchovski
2004-03-04  6:25     ` Kenji Okamoto
2004-03-04 12:35   ` Latchesar Ionkov
2004-03-04 13:47     ` gdiaz
2004-03-09 14:14 ` David Presotto [this message]
2004-03-04  6:39 Tiit Lankots

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6d6ceaeedeccf92df0e063ca84bce23a@plan9.bell-labs.com \
    --to=presotto@closedmind.org \
    --cc=9fans@cse.psu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).