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