9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] Support for LCD screens for the Radeon driver
@ 2004-03-03 16:34 Latchesar Ionkov
  2004-03-03 16:36 ` Fco.J.Ballesteros
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Latchesar Ionkov @ 2004-03-03 16:34 UTC (permalink / raw)
  To: 9fans

[-- Attachment #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: 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 #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
};

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  2004-03-03 16:34 [9fans] Support for LCD screens for the Radeon driver Latchesar Ionkov
@ 2004-03-03 16:36 ` Fco.J.Ballesteros
  2004-03-04  6:06 ` Kenji Okamoto
  2004-03-09 14:14 ` David Presotto
  2 siblings, 0 replies; 9+ messages in thread
From: Fco.J.Ballesteros @ 2004-03-03 16:36 UTC (permalink / raw)
  To: 9fans

Cool
We'll add it to our local setup.
thanks a lot.



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  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
  1 sibling, 1 reply; 9+ messages in thread
From: andrey mirtchovski @ 2004-03-04  5:22 UTC (permalink / raw)
  To: 9fans

>> I added support for LCD screens in the Radeon driver. It only works if the
>> BIOS has panel information defined. 
> 
> What are the actual notebook models for this driver?
> I'm now thinking whether to buy one or not.
> 
> Kenji

go to www.ibm.com and click on products, then notebooks..

all the T and R series laptops have a Radeon 7500 or 9000 (they are
the more expensive ones), the G and X ones have an 'Intel Extreme'.

i have a T30 which is reasonable, just saw a T41 yesterday -- a better
display, thinner and lighter.

three button on each one, so no need for extra mouse...

andrey



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  2004-03-03 16:34 [9fans] Support for LCD screens for the Radeon driver 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 12:35   ` Latchesar Ionkov
  2004-03-09 14:14 ` David Presotto
  2 siblings, 2 replies; 9+ messages in thread
From: Kenji Okamoto @ 2004-03-04  6:06 UTC (permalink / raw)
  To: 9fans

> I added support for LCD screens in the Radeon driver. It only works if the
> BIOS has panel information defined. 

What are the actual notebook models for this driver?
I'm now thinking whether to buy one or not.

Kenji



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  2004-03-04  5:22   ` andrey mirtchovski
@ 2004-03-04  6:25     ` Kenji Okamoto
  0 siblings, 0 replies; 9+ messages in thread
From: Kenji Okamoto @ 2004-03-04  6:25 UTC (permalink / raw)
  To: 9fans

> i have a T30 which is reasonable, just saw a T41 yesterday -- a better
> display, thinner and lighter.

So, the T30 worked fine?

I've thought this driver is for HP series which has a damn mousepad.☺
I looked IBM just for G (too heavy model!) and X series (expensive ones).

Kenji



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  2004-03-04  6:06 ` Kenji Okamoto
  2004-03-04  5:22   ` andrey mirtchovski
@ 2004-03-04 12:35   ` Latchesar Ionkov
  2004-03-04 13:47     ` gdiaz
  1 sibling, 1 reply; 9+ messages in thread
From: Latchesar Ionkov @ 2004-03-04 12:35 UTC (permalink / raw)
  To: 9fans

On Thu, Mar 04, 2004 at 03:06:58PM +0900, Kenji Okamoto said:
> > I added support for LCD screens in the Radeon driver. It only works if the
> > BIOS has panel information defined. 
> 
> What are the actual notebook models for this driver?
> I'm now thinking whether to buy one or not.

I tested it on IBM X31 (Radeon M6 LY).

Thanks,
	Lucho


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  2004-03-04 12:35   ` Latchesar Ionkov
@ 2004-03-04 13:47     ` gdiaz
  0 siblings, 0 replies; 9+ messages in thread
From: gdiaz @ 2004-03-04 13:47 UTC (permalink / raw)
  To: 9fans

hi,

IBM T30 (M7) and VAIO V505 (M6) works too

gabi. 

Quoting Latchesar Ionkov <lucho@ionkov.net>:

> On Thu, Mar 04, 2004 at 03:06:58PM +0900, Kenji Okamoto said:
> > > I added support for LCD screens in the Radeon driver. It only works if
> the
> > > BIOS has panel information defined. 
> > 
> > What are the actual notebook models for this driver?
> > I'm now thinking whether to buy one or not.
> 
> I tested it on IBM X31 (Radeon M6 LY).
> 
> Thanks,
> 	Lucho
> 





^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [9fans] Support for LCD screens for the Radeon driver
  2004-03-03 16:34 [9fans] Support for LCD screens for the Radeon driver Latchesar Ionkov
  2004-03-03 16:36 ` Fco.J.Ballesteros
  2004-03-04  6:06 ` Kenji Okamoto
@ 2004-03-09 14:14 ` David Presotto
  2 siblings, 0 replies; 9+ messages in thread
From: David Presotto @ 2004-03-09 14:14 UTC (permalink / raw)
  To: 9fans

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

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [9fans] Support for LCD screens for the Radeon driver
@ 2004-03-04  6:39 Tiit Lankots
  0 siblings, 0 replies; 9+ messages in thread
From: Tiit Lankots @ 2004-03-04  6:39 UTC (permalink / raw)
  To: 9fans

> I looked IBM just for G (too heavy model!) and X series 

G - G-forces
X - eXpensive 

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2004-03-09 14:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-03-03 16:34 [9fans] Support for LCD screens for the Radeon driver 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
2004-03-04  6:39 Tiit Lankots

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).