From: Latchesar Ionkov <lucho@ionkov.net>
To: 9fans@cse.psu.edu
Subject: [9fans] Support for LCD screens for the Radeon driver
Date: Wed, 3 Mar 2004 11:34:32 -0500 [thread overview]
Message-ID: <20040303163432.GA14994@ionkov.net> (raw)
[-- 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
};
next reply other threads:[~2004-03-03 16:34 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-03-03 16:34 Latchesar Ionkov [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20040303163432.GA14994@ionkov.net \
--to=lucho@ionkov.net \
--cc=9fans@cse.psu.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).