647 lines
16 KiB
C
647 lines
16 KiB
C
/*
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
* in the LICENSE file.
|
|
*/
|
|
|
|
#include <u.h>
|
|
#include <lib9.h>
|
|
#include <bio.h>
|
|
|
|
#include "pci.h"
|
|
#include "vga.h"
|
|
#include "radeon.h"
|
|
|
|
static int debug = 0;
|
|
|
|
#define DBGPRINT if (debug) print
|
|
|
|
enum {
|
|
Kilo = 1024,
|
|
Mega = Kilo *Kilo,
|
|
};
|
|
|
|
enum {
|
|
DISPLAY_CRT,
|
|
DISPLAY_FP,
|
|
DISPLAY_LCD,
|
|
};
|
|
|
|
typedef struct Radeon Radeon;
|
|
struct Radeon {
|
|
uintptr_t mmio;
|
|
Pcidev *pci;
|
|
uint8_t *bios;
|
|
|
|
uint32_t fbsize;
|
|
int display_type;
|
|
|
|
uint32_t ovr_clr;
|
|
uint32_t ovr_wid_top_bottom;
|
|
uint32_t ovr_wid_left_right;
|
|
uint32_t ov0_scale_cntl;
|
|
uint32_t subpic_cntl;
|
|
uint32_t viph_control;
|
|
uint32_t i2c_cntl_1;
|
|
uint32_t rbbm_soft_reset;
|
|
uint32_t cap0_trig_cntl;
|
|
uint32_t cap1_trig_cntl;
|
|
uint32_t gen_int_cntl;
|
|
uint32_t bus_cntl;
|
|
|
|
uint32_t crtc_gen_cntl;
|
|
uint32_t crtc_ext_cntl;
|
|
uint32_t dac_cntl;
|
|
|
|
uint32_t crtc_h_total_disp;
|
|
uint32_t crtc_h_sync_strt_wid;
|
|
uint32_t crtc_v_total_disp;
|
|
uint32_t crtc_v_sync_strt_wid;
|
|
|
|
uint32_t crtc_pitch;
|
|
|
|
uint32_t crtc_offset;
|
|
uint32_t crtc_offset_cntl;
|
|
|
|
uint32_t htotal_cntl;
|
|
|
|
uint32_t surface_cntl;
|
|
|
|
int r300_workaround;
|
|
|
|
/* inited from rom */
|
|
uint16_t reference_freq;
|
|
uint16_t reference_div;
|
|
uint16_t xclk;
|
|
uint32_t max_pll_freq;
|
|
uint32_t min_pll_freq;
|
|
|
|
uint32_t pll_output_freq;
|
|
uint32_t feedback_div;
|
|
uint32_t dot_clock_freq;
|
|
|
|
uint32_t post_div;
|
|
uint32_t ppll_ref_div;
|
|
uint32_t ppll_div_3;
|
|
};
|
|
|
|
/* from io.c */
|
|
//extern char* readbios(int32_t len, int32_t offset);
|
|
|
|
static void radeon300_workaround(Radeon*radeon);
|
|
|
|
static void
|
|
OUTREG8(Radeon*radeon, uint32_t offset, uint8_t val)
|
|
{
|
|
((uint8_t *)(radeon->mmio + offset))[0] = val;
|
|
}
|
|
|
|
static void
|
|
OUTREG(Radeon*radeon, uint32_t offset, uint32_t val)
|
|
{
|
|
((uint32_t *)(radeon->mmio + offset))[0] = val;
|
|
}
|
|
|
|
static uint32_t
|
|
INREG(Radeon*radeon, uint32_t offset)
|
|
{
|
|
return ((uint32_t *)(radeon->mmio + offset))[0];
|
|
}
|
|
|
|
static void
|
|
OUTREGP(Radeon*radeon, uint32_t offset, uint32_t val, uint32_t mask)
|
|
{
|
|
OUTREG(radeon, offset, (INREG(radeon, offset) & mask) | val);
|
|
}
|
|
|
|
static void
|
|
OUTPLL(Radeon*radeon, uint32_t offset, uint32_t val)
|
|
{
|
|
OUTREG8(radeon, CLOCK_CNTL_INDEX,
|
|
(offset & 0x3f) | PLL_WR_EN);
|
|
OUTREG(radeon, CLOCK_CNTL_DATA, val);
|
|
}
|
|
|
|
static uint32_t
|
|
INPLL(Radeon*radeon, uint32_t offset)
|
|
{
|
|
uint32_t data;
|
|
|
|
OUTREG8(radeon, CLOCK_CNTL_INDEX, offset & 0x3f);
|
|
data = INREG(radeon, CLOCK_CNTL_DATA);
|
|
if (radeon->r300_workaround)
|
|
radeon300_workaround(radeon);
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
OUTPLLP(Radeon*radeon, uint32_t offset, uint32_t val, uint32_t mask)
|
|
{
|
|
OUTPLL(radeon, offset, (INPLL(radeon, offset) & mask) | val);
|
|
}
|
|
|
|
static void
|
|
radeon300_workaround(Radeon*radeon)
|
|
{
|
|
uint32_t save, tmp;
|
|
|
|
save = INREG(radeon, CLOCK_CNTL_INDEX);
|
|
tmp = save & ~(0x3f | PLL_WR_EN);
|
|
OUTREG(radeon, CLOCK_CNTL_INDEX, tmp);
|
|
tmp = INREG(radeon, CLOCK_CNTL_DATA);
|
|
OUTREG(radeon, CLOCK_CNTL_INDEX, save);
|
|
USED(tmp);
|
|
}
|
|
|
|
static void
|
|
radeon_getbiosparams(Radeon*radeon)
|
|
{
|
|
uint32_t addr;
|
|
uint16_t offset, pib;
|
|
uint8_t *bios;
|
|
|
|
radeon->bios = nil;
|
|
addr = 0xC0000;
|
|
bios = (uint8_t *)readbios(0x10000, addr);
|
|
if (bios[0] != 0x55 || bios[1] != 0xAA) {
|
|
addr = 0xE0000;
|
|
bios = (uint8_t *)readbios(0x10000, addr);
|
|
if (bios[0] != 0x55 || bios[1] != 0xAA) {
|
|
print("radeon: bios not found\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
radeon->bios = bios;
|
|
offset = BIOS16(radeon, BIOS_START);
|
|
|
|
pib = BIOS16(radeon, offset + 0x30);
|
|
|
|
radeon->reference_freq = BIOS16(radeon, pib + 0x0e);
|
|
radeon->reference_div = BIOS16(radeon, pib + 0x10);
|
|
radeon->min_pll_freq = BIOS32(radeon, pib + 0x12);
|
|
radeon->max_pll_freq = BIOS32(radeon, pib + 0x16);
|
|
radeon->xclk = 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);
|
|
}
|
|
|
|
static Pcidev *
|
|
radeonpci(int *isr300)
|
|
{
|
|
static Pcidev * p = nil;
|
|
struct pciids *ids;
|
|
|
|
DBGPRINT("radeon: ATI Technologies Inc. Radeon [789]xxx drivers (v0.1)\n");
|
|
while ((p = pcimatch(p, ATI_PCIVID, 0)) != 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 (isr300)
|
|
*isr300 = ids->type == ATI_R300;
|
|
return p;
|
|
}
|
|
DBGPRINT("radeon: not found!\n");
|
|
return 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
|
|
snarf(Vga *vga, Ctlr *ctlr)
|
|
{
|
|
int isr300;
|
|
uint32_t tmp;
|
|
uintptr_t mmio;
|
|
Pcidev *p;
|
|
Radeon *radeon;
|
|
|
|
if (vga->private == nil) {
|
|
vga_disable(vga);
|
|
|
|
vga->private = alloc(sizeof(Radeon));
|
|
radeon = vga->private;
|
|
|
|
p = radeonpci(&isr300);
|
|
if (p == nil)
|
|
error("%s: not found\n", ctlr->name);
|
|
|
|
vgactlw("type", ctlr->name);
|
|
|
|
mmio = (uintptr_t)segattach(0, "radeonmmio", (void *)0,
|
|
p->mem[2].size);
|
|
if (mmio == ~0)
|
|
error("%s: can't attach mmio segment\n", ctlr->name);
|
|
|
|
DBGPRINT("radeon: mmio address: %08#p [size=%#x]\n",
|
|
(void *)mmio, p->mem[2].size);
|
|
|
|
radeon->pci = p;
|
|
radeon->r300_workaround = isr300;
|
|
radeon->mmio = mmio;
|
|
}
|
|
|
|
radeon = vga->private;
|
|
radeon->fbsize = INREG(radeon, CONFIG_MEMSIZE);
|
|
vga->vmz = radeon->fbsize;
|
|
DBGPRINT("radeon: frame buffer size=%uld [%uldMB]\n",
|
|
radeon->fbsize, radeon->fbsize / Mega);
|
|
|
|
tmp = INREG(radeon, FP_GEN_CNTL);
|
|
if (tmp & FP_EN_TMDS)
|
|
radeon->display_type = DISPLAY_FP;
|
|
else
|
|
radeon->display_type = DISPLAY_CRT;
|
|
|
|
DBGPRINT("radeon: display type: %s\n",
|
|
radeon->display_type == DISPLAY_CRT? "CRT": "FLAT PANEL");
|
|
|
|
if (radeon->display_type != DISPLAY_CRT)
|
|
error("unsupported NON CRT Display\n");
|
|
|
|
radeon_getbiosparams(radeon);
|
|
radeon->bus_cntl = INREG(radeon, BUS_CNTL);
|
|
DBGPRINT("radeon: PPLL_CNTL=0x%08ulx\n", INPLL(radeon, PPLL_CNTL));
|
|
ctlr->flag |= Fsnarf;
|
|
}
|
|
|
|
static void
|
|
options(Vga* 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 & BUS_READ_BURST)
|
|
radeon->bus_cntl |= BUS_RD_DISCARD_EN;
|
|
}
|
|
|
|
static void
|
|
radeon_init_crtc_registers(Radeon*radeon, Mode*mode)
|
|
{
|
|
int format, dac6bit, hsync_wid, vsync_wid, hsync_start, hsync_fudge;
|
|
int bpp;
|
|
static int hsync_fudge_default[] = {
|
|
0x00, 0x12, 0x09, 0x09, 0x06, 0x05,
|
|
};
|
|
|
|
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);
|
|
}
|
|
hsync_fudge = hsync_fudge_default[format-1];
|
|
|
|
DBGPRINT("mode->z = %d (format = %d, bpp = %d, dac6bit = %s)\n",
|
|
mode->z, format, bpp, dac6bit? "true": "false");
|
|
|
|
radeon->crtc_gen_cntl = CRTC_EN | CRTC_EXT_DISP_EN | format << 8 |
|
|
(mode->interlace? CRTC_INTERLACE_EN: 0);
|
|
radeon->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON;
|
|
radeon->dac_cntl = DAC_MASK_ALL | DAC_VGA_ADR_EN |
|
|
(dac6bit? 0: DAC_8BIT_EN);
|
|
|
|
radeon->crtc_h_total_disp = ((mode->ht/8 - 1) & 0x3ff) |
|
|
((mode->x/8 - 1) & 0x1ff) << 16;
|
|
|
|
hsync_wid = (mode->ehb - mode->shb) / 8;
|
|
if (hsync_wid == 0)
|
|
hsync_wid = 1;
|
|
|
|
hsync_start = mode->shb - 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 | (mode->hsync? CRTC_H_SYNC_POL: 0));
|
|
radeon->crtc_v_total_disp = ((mode->vt - 1) & 0xffff) |
|
|
(mode->y - 1) << 16;
|
|
|
|
vsync_wid = mode->vre - mode->vrs;
|
|
if (!vsync_wid)
|
|
vsync_wid = 1;
|
|
|
|
radeon->crtc_v_sync_strt_wid = (((mode->vrs - 1) & 0xfff) |
|
|
(vsync_wid & 0x1f) << 16 | (mode->vsync? CRTC_V_SYNC_POL: 0));
|
|
radeon->crtc_offset = 0;
|
|
radeon->crtc_offset_cntl = INREG(radeon, CRTC_OFFSET_CNTL);
|
|
radeon->crtc_pitch = (mode->x * bpp + bpp * 8 - 1) / (bpp * 8);
|
|
radeon->crtc_pitch |= radeon->crtc_pitch << 16;
|
|
}
|
|
|
|
struct divider {
|
|
int divider;
|
|
int bitvalue;
|
|
};
|
|
|
|
static void
|
|
radeon_init_pll_registers(Radeon*radeon, uint32_t freq)
|
|
{
|
|
struct divider *post_div;
|
|
static struct divider 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);
|
|
|
|
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
|
|
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);
|
|
radeon_init_pll_registers(radeon, mode->frequency / 10000);
|
|
ctlr->flag |= Finit | Ulinear;
|
|
}
|
|
|
|
static void
|
|
radeon_blank(Radeon*radeon)
|
|
{
|
|
OUTREGP(radeon, CRTC_EXT_CNTL,
|
|
CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS,
|
|
~(CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS));
|
|
}
|
|
|
|
static void
|
|
radeon_unblank(Radeon*radeon)
|
|
{
|
|
OUTREGP(radeon, CRTC_EXT_CNTL, CRTC_CRT_ON,
|
|
~(CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS));
|
|
}
|
|
|
|
static void
|
|
radeon_load_common_registers(Radeon*radeon)
|
|
{
|
|
OUTREG(radeon, OVR_CLR, radeon->ovr_clr);
|
|
OUTREG(radeon, OVR_WID_LEFT_RIGHT, radeon->ovr_wid_left_right);
|
|
OUTREG(radeon, OVR_WID_TOP_BOTTOM, radeon->ovr_wid_top_bottom);
|
|
OUTREG(radeon, OV0_SCALE_CNTL, radeon->ov0_scale_cntl);
|
|
OUTREG(radeon, SUBPIC_CNTL, radeon->subpic_cntl);
|
|
OUTREG(radeon, VIPH_CONTROL, radeon->viph_control);
|
|
OUTREG(radeon, I2C_CNTL_1, radeon->i2c_cntl_1);
|
|
OUTREG(radeon, GEN_INT_CNTL, radeon->gen_int_cntl);
|
|
OUTREG(radeon, CAP0_TRIG_CNTL, radeon->cap0_trig_cntl);
|
|
OUTREG(radeon, CAP1_TRIG_CNTL, radeon->cap1_trig_cntl);
|
|
OUTREG(radeon, BUS_CNTL, radeon->bus_cntl);
|
|
OUTREG(radeon, SURFACE_CNTL, radeon->surface_cntl);
|
|
}
|
|
|
|
static void
|
|
radeon_load_crtc_registers(Radeon*radeon)
|
|
{
|
|
OUTREG(radeon, CRTC_GEN_CNTL, radeon->crtc_gen_cntl);
|
|
OUTREGP(radeon, CRTC_EXT_CNTL, radeon->crtc_ext_cntl,
|
|
CRTC_VSYNC_DIS | CRTC_HSYNC_DIS | CRTC_DISPLAY_DIS);
|
|
OUTREGP(radeon, DAC_CNTL, radeon->dac_cntl,
|
|
DAC_RANGE_CNTL | DAC_BLANKING);
|
|
OUTREG(radeon, CRTC_H_TOTAL_DISP, radeon->crtc_h_total_disp);
|
|
OUTREG(radeon, CRTC_H_SYNC_STRT_WID, radeon->crtc_h_sync_strt_wid);
|
|
OUTREG(radeon, CRTC_V_TOTAL_DISP, radeon->crtc_v_total_disp);
|
|
OUTREG(radeon, CRTC_V_SYNC_STRT_WID, radeon->crtc_v_sync_strt_wid);
|
|
OUTREG(radeon, CRTC_OFFSET, radeon->crtc_offset);
|
|
OUTREG(radeon, CRTC_OFFSET_CNTL, radeon->crtc_offset_cntl);
|
|
OUTREG(radeon, CRTC_PITCH, radeon->crtc_pitch);
|
|
}
|
|
|
|
static void
|
|
radeon_pllwaitupd(Radeon*radeon)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 10000; i++)
|
|
if (!(INPLL(radeon, PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R))
|
|
break;
|
|
}
|
|
|
|
static void
|
|
radeon_pllwriteupd(Radeon*radeon)
|
|
{
|
|
while (INPLL(radeon, PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
|
|
;
|
|
OUTPLLP(radeon, PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
|
|
}
|
|
|
|
static void
|
|
radeon_load_pll_registers(Radeon*radeon)
|
|
{
|
|
OUTPLLP(radeon, VCLK_ECP_CNTL,
|
|
VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
|
|
OUTPLLP(radeon, PPLL_CNTL,
|
|
PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
|
|
~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
|
|
OUTREGP(radeon, CLOCK_CNTL_INDEX, PLL_DIV_SEL, ~PLL_DIV_SEL);
|
|
if (radeon->r300_workaround) {
|
|
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, PPLL_REF_DIV, radeon->ppll_ref_div, 0);
|
|
else
|
|
/* R300 uses ref_div_acc field as real ref divider */
|
|
OUTPLLP(radeon, PPLL_REF_DIV,
|
|
radeon->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT,
|
|
~R300_PPLL_REF_DIV_ACC_MASK);
|
|
} else
|
|
OUTPLLP(radeon, PPLL_REF_DIV, radeon->ppll_ref_div,
|
|
~PPLL_REF_DIV_MASK);
|
|
|
|
OUTPLLP(radeon, PPLL_DIV_3, radeon->ppll_div_3, ~PPLL_FB3_DIV_MASK);
|
|
OUTPLLP(radeon, PPLL_DIV_3, radeon->ppll_div_3, ~PPLL_POST3_DIV_MASK);
|
|
|
|
radeon_pllwriteupd(radeon);
|
|
radeon_pllwaitupd(radeon);
|
|
|
|
OUTPLL(radeon, HTOTAL_CNTL, radeon->htotal_cntl);
|
|
OUTPLLP(radeon, PPLL_CNTL, 0,
|
|
~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN |
|
|
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, PPLL_CNTL));
|
|
Bprint(&stdout, "Wrote: rd=%uld, fd=%uld, pd=%uld\n",
|
|
radeon->ppll_ref_div & PPLL_REF_DIV_MASK,
|
|
radeon->ppll_div_3 & PPLL_FB3_DIV_MASK,
|
|
(radeon->ppll_div_3 & PPLL_POST3_DIV_MASK) >> 16);
|
|
}
|
|
|
|
/* Let the clock to lock */
|
|
sleep(5);
|
|
|
|
OUTPLLP(radeon, VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
|
|
}
|
|
|
|
static void
|
|
load(Vga*vga, Ctlr*ctlr)
|
|
{
|
|
Radeon *radeon;
|
|
|
|
radeon = (Radeon *) vga->private;
|
|
radeon_blank(radeon);
|
|
radeon_load_common_registers(radeon);
|
|
radeon_load_crtc_registers(radeon);
|
|
radeon_load_pll_registers(radeon);
|
|
radeon_unblank(radeon);
|
|
|
|
/* init palette [gamma] */
|
|
if (vga->mode->z > 8) {
|
|
int i;
|
|
|
|
OUTREG(radeon, PALETTE_INDEX, 0);
|
|
for (i = 0; i < 256; i++)
|
|
OUTREG(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",
|
|
snarf,
|
|
options,
|
|
init,
|
|
load,
|
|
dump,
|
|
};
|
|
Ctlr radeonhwgc = {
|
|
"radeonhwgc",
|
|
0, /* snarf */
|
|
0, /* options */
|
|
0, /* init */
|
|
0, /* load */
|
|
0, /* dump */
|
|
};
|