Initial import of radeonfb. Works to some degree on at least some hardware.

Most of the testing was done on MIPS hardware -- it probably needs work before
it will be useful with x86 hardware, and it is probably incompatible with
the X11 server.

"ATI Technologies Inc. ("ATI") has not assisted in the creation of, and
does not endorse, this software.  ATI will not be responsible or liable
for any actual or alleged damage or loss caused by or in connection with
the use of or reliance on this software."

Enjoy!
This commit is contained in:
gdamore 2006-08-16 22:46:44 +00:00
parent 64e85b48bf
commit 0d7e99a27a
6 changed files with 7195 additions and 1 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.pci,v 1.265 2006/08/13 03:34:11 jmcneill Exp $
# $NetBSD: files.pci,v 1.266 2006/08/16 22:46:44 gdamore Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@ -756,6 +756,14 @@ device unichromefb: wsemuldisplaydev, rasops16, rasops32, vcons
attach unichromefb at pci
file dev/pci/unichromefb.c unichromefb needs-flag
# ATI Radeon framebuffer console driver
# (Note: to enable the BIOS parser, add options RADEON_BIOS_INIT to the config)
device radeonfb: wsemuldisplaydev, videomode, rasops32, vcons, splash, iic, i2c_bitbang, ddc_read_edid, edid
attach radeonfb at pci
file dev/pci/radeonfb.c radeonfb
file dev/pci/radeonfb_i2c.c radeonfb
file dev/pci/radeonfb_bios.c radeonfb
# 3Com 3c990
device txp: ether, ifnet, arp
attach txp at pci

3193
sys/dev/pci/radeonfb.c Normal file

File diff suppressed because it is too large Load Diff

619
sys/dev/pci/radeonfb_bios.c Normal file
View File

@ -0,0 +1,619 @@
/* $NetBSD: radeonfb_bios.c,v 1.1 2006/08/16 22:46:45 gdamore Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
* All rights reserved.
*
* Written by Garrett D'Amore for Itronix Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of Itronix Inc. may not be used to endorse
* or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ATI Technologies Inc. ("ATI") has not assisted in the creation of, and
* does not endorse, this software. ATI will not be responsible or liable
* for any actual or alleged damage or loss caused by or in connection with
* the use of or reliance on this software.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: radeonfb_bios.c,v 1.1 2006/08/16 22:46:45 gdamore Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/radeonfbreg.h>
#include <dev/pci/radeonfbvar.h>
#ifdef RADEON_BIOS_INIT
/*
* Globals for the entire BIOS.
*/
#define ROM_HEADER_OFFSET 0x48
#define MAX_REVISION 0x10
#define SINGLE_TABLE_REVISION 0x09
#define MIN_OFFSET 0x60
/*
* Offsets of specific tables.
*/
#define RAGE_REGS1_OFFSET 0x0c
#define RAGE_REGS2_OFFSET 0x4e
#define DYN_CLOCK_OFFSET 0x52
#define PLL_INIT_OFFSET 0x46
#define MEM_CONFIG_OFFSET 0x48
/*
* Values related to generic intialization tables.
*/
#define TABLE_ENTRY_FLAG_MASK 0xe000
#define TABLE_ENTRY_INDEX_MASK 0x1fff
#define TABLE_ENTRY_COMMAND_MASK 0x00ff
#define TABLE_FLAG_WRITE_INDEXED 0x0000
#define TABLE_FLAG_WRITE_DIRECT 0x2000
#define TABLE_FLAG_MASK_INDEXED 0x4000
#define TABLE_FLAG_MASK_DIRECT 0x6000
#define TABLE_FLAG_DELAY 0x8000
#define TABLE_FLAG_SCOMMAND 0xa000
#define TABLE_SCOMMAND_WAIT_MC_BUSY_MASK 0x03
#define TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08
/*
* PLL initialization block values.
*/
#define PLL_FLAG_MASK 0xc0
#define PLL_INDEX_MASK 0x3f
#define PLL_FLAG_WRITE 0x00
#define PLL_FLAG_MASK_BYTE 0x40
#define PLL_FLAG_WAIT 0x80
#define PLL_WAIT_150MKS 1
#define PLL_WAIT_5MS 2
#define PLL_WAIT_MC_BUSY_MASK 3
#define PLL_WAIT_DLL_READY_MASK 4
#define PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5
#ifdef RADEON_BIOS_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif
struct rb_table;
static void rb_validate(struct radeonfb_softc *, struct rb_table *);
static uint16_t rb_find_asic_table(struct radeonfb_softc *, struct rb_table *);
static uint16_t rb_find_mem_reset_table(struct radeonfb_softc *,
struct rb_table *);
static uint16_t rb_find_short_mem_reset_table(struct radeonfb_softc *,
struct rb_table *);
static int rb_load_init_block(struct radeonfb_softc *, struct rb_table *);
static int rb_load_pll_block(struct radeonfb_softc *, struct rb_table *);
static int rb_reset_sdram(struct radeonfb_softc *, struct rb_table *);
static void rb_wait_mc_busy_mask(struct radeonfb_softc *, uint16_t);
static void rb_wait_mem_pwrup_complete(struct radeonfb_softc *, uint16_t);
static void rb_wait_dll_ready_mask(struct radeonfb_softc *, uint16_t);
static void rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc *);
/*
* Generic structure describing the tables.
*/
struct rb_table {
const unsigned char *name;
uint16_t offset;
struct rb_table *parent;
/* validate that the table looks sane */
void (*validate)(struct radeonfb_softc *, struct rb_table *);
/* find looks for the table relative to its "parent" */
uint16_t (*find)(struct radeonfb_softc *, struct rb_table *);
};
/*
* Instances of specific tables.
*/
static struct rb_table rb_rage_regs1_table = {
"rage_regs_1", /* name */
RAGE_REGS1_OFFSET, /* offset */
NULL, /* parent */
rb_validate, /* validate */
NULL, /* find */
};
static struct rb_table rb_rage_regs2_table = {
"rage_regs_2", /* name */
RAGE_REGS2_OFFSET, /* offset */
NULL, /* parent */
rb_validate, /* validate */
NULL, /* find */
};
static struct rb_table rb_dyn_clock_table = {
"dyn_clock", /* name */
DYN_CLOCK_OFFSET, /* offset */
NULL, /* parent */
rb_validate, /* validate */
NULL, /* find */
};
static struct rb_table rb_pll_init_table = {
"pll_init", /* name */
PLL_INIT_OFFSET, /* offset */
NULL, /* parent */
rb_validate, /* validate */
NULL, /* find */
};
static struct rb_table rb_mem_config_table = {
"mem_config", /* name */
MEM_CONFIG_OFFSET, /* offset */
NULL, /* parent */
rb_validate, /* validate */
NULL, /* find */
};
static struct rb_table rb_mem_reset_table = {
"mem_reset", /* name */
0, /* offset */
&rb_mem_config_table, /* parent */
NULL, /* validate */
rb_find_mem_reset_table, /* find */
};
static struct rb_table rb_short_mem_reset_table = {
"short_mem_reset", /* name */
0, /* offset */
&rb_mem_config_table, /* parent */
NULL, /* validate */
rb_find_short_mem_reset_table, /* find */
};
static struct rb_table rb_rage_regs3_table = {
"rage_regs_3", /* name */
0, /* offset */
&rb_rage_regs2_table, /* parent */
NULL, /* validate */
rb_find_asic_table, /* find */
};
static struct rb_table rb_rage_regs4_table = {
"rage_regs_4", /* name */
0, /* offset */
&rb_rage_regs3_table, /* parent */
NULL, /* validate */
rb_find_asic_table, /* find */
};
static struct rb_table *rb_tables[] = {
&rb_rage_regs1_table,
&rb_rage_regs2_table,
&rb_dyn_clock_table,
&rb_pll_init_table,
&rb_mem_config_table,
&rb_mem_reset_table,
&rb_short_mem_reset_table,
&rb_rage_regs3_table,
&rb_rage_regs4_table,
NULL
};
void
rb_validate(struct radeonfb_softc *sc, struct rb_table *tp)
{
uint8_t rev;
rev = GETBIOS8(sc, tp->offset - 1);
if (rev > MAX_REVISION) {
DPRINTF(("%s: bad rev %x of %s\n", XNAME(sc), rev, tp->name));
tp->offset = 0;
return;
}
if (tp->offset < MIN_OFFSET) {
DPRINTF(("%s: wrong pointer to %s!\n", XNAME(sc), tp->name));
tp->offset = 0;
return;
}
}
uint16_t
rb_find_asic_table(struct radeonfb_softc *sc, struct rb_table *tp)
{
uint16_t offset;
uint8_t c;
if ((offset = tp->offset) != 0) {
while ((c = GETBIOS8(sc, offset + 1)) != 0) {
if (c & 0x40)
offset += 10;
else if (c & 0x80)
offset += 4;
else
offset += 6;
}
return offset + 2;
}
return 0;
}
uint16_t
rb_find_mem_reset_table(struct radeonfb_softc *sc, struct rb_table *tp)
{
uint16_t offset;
if ((offset = tp->offset) != 0) {
while (GETBIOS8(sc, offset))
offset++;
offset++;
return offset + 2; /* skip table revision and mask */
}
return 0;
}
uint16_t
rb_find_short_mem_reset_table(struct radeonfb_softc *sc, struct rb_table *tp)
{
if ((tp->offset != 0) && (GETBIOS8(sc, tp->offset - 2) <= 64))
return (tp->offset + GETBIOS8(sc, tp->offset - 3));
return 0;
}
/* helper commands */
void
rb_wait_mc_busy_mask(struct radeonfb_softc *sc, uint16_t count)
{
DPRINTF(("WAIT_MC_BUSY_MASK: %d ", count));
while (count--) {
if (!(radeonfb_getpll(sc, RADEON_CLK_PWRMGT_CNTL) &
RADEON_MC_BUSY_MASK))
break;
}
DPRINTF(("%d\n", count));
}
void
rb_wait_mem_pwrup_complete(struct radeonfb_softc *sc, uint16_t count)
{
DPRINTF(("WAIT_MEM_PWRUP_COMPLETE: %d ", count));
while (count--) {
if ((radeonfb_getindex(sc, RADEON_MEM_STR_CNTL) &
RADEON_MEM_PWRUP_COMPLETE) ==
RADEON_MEM_PWRUP_COMPLETE)
break;
}
DPRINTF(("%d\n", count));
}
void
rb_wait_dll_ready_mask(struct radeonfb_softc *sc, uint16_t count)
{
DPRINTF(("WAIT_DLL_READY_MASK: %d ", count));
while (count--) {
if (radeonfb_getpll(sc, RADEON_CLK_PWRMGT_CNTL) &
RADEON_DLL_READY_MASK)
break;
}
DPRINTF(("%d\n", count));
}
void
rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc *sc)
{
uint32_t pmc;
DPRINTF(("WAIT CHK_SET_CLK_PWRMGT_CNTL24\n"));
pmc = radeonfb_getpll(sc, RADEON_CLK_PWRMGT_CNTL);
if (pmc & RADEON_CLK_PWRMGT_CNTL24) {
radeonfb_maskpll(sc, RADEON_MCLK_CNTL, 0xFFFF0000,
RADEON_SET_ALL_SRCS_TO_PCI);
delay(10000);
radeonfb_putpll(sc, RADEON_CLK_PWRMGT_CNTL,
pmc & ~RADEON_CLK_PWRMGT_CNTL24);
delay(10000);
}
}
/*
* Block initialization routines. These take action based on data in
* the tables.
*/
int
rb_load_init_block(struct radeonfb_softc *sc, struct rb_table *tp)
{
uint16_t offset;
uint16_t value;
if ((tp == NULL) || ((offset = tp->offset) == 0))
return 1;
DPRINTF(("%s: load_init_block processing %s\n", XNAME(sc), tp->name));
while ((value = GETBIOS16(sc, offset)) != 0) {
uint16_t flag = value & TABLE_ENTRY_FLAG_MASK;
uint16_t index = value & TABLE_ENTRY_INDEX_MASK;
uint8_t command = value & TABLE_ENTRY_COMMAND_MASK;
uint32_t ormask;
uint32_t andmask;
uint16_t count;
offset += 2;
switch (flag) {
case TABLE_FLAG_WRITE_INDEXED:
DPRINTF(("WRITE INDEXED: %x %x\n",
index, (uint32_t)GETBIOS32(sc, offset)));
radeonfb_putindex(sc, index, GETBIOS32(sc, offset));
offset += 4;
break;
case TABLE_FLAG_WRITE_DIRECT:
DPRINTF(("WRITE DIRECT: %x %x\n",
index, (uint32_t)GETBIOS32(sc, offset)));
radeonfb_put32(sc, index, GETBIOS32(sc, offset));
offset += 4;
break;
case TABLE_FLAG_MASK_INDEXED:
andmask = GETBIOS32(sc, offset);
offset += 4;
ormask = GETBIOS32(sc, offset);
offset += 4;
DPRINTF(("MASK INDEXED: %x %x %x\n",
index, andmask, ormask));
radeonfb_maskindex(sc, index, andmask, ormask);
break;
case TABLE_FLAG_MASK_DIRECT:
andmask = GETBIOS32(sc, offset);
offset += 4;
ormask = GETBIOS32(sc, offset);
offset += 4;
DPRINTF(("MASK DIRECT: %x %x %x\n",
index, andmask, ormask));
radeonfb_mask32(sc, index, andmask, ormask);
break;
case TABLE_FLAG_DELAY:
/* in the worst case, this would be 16msec */
count = GETBIOS16(sc, offset);
DPRINTF(("DELAY: %d\n", count));
delay(count);
offset += 2;
break;
case TABLE_FLAG_SCOMMAND:
DPRINTF(("SCOMMAND %x\n", command));
switch (command) {
case TABLE_SCOMMAND_WAIT_MC_BUSY_MASK:
count = GETBIOS16(sc, offset);
rb_wait_mc_busy_mask(sc, count);
break;
case TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE:
count = GETBIOS16(sc, offset);
rb_wait_mem_pwrup_complete(sc, count);
break;
}
offset += 2;
break;
}
}
return 0;
}
int
rb_load_pll_block(struct radeonfb_softc *sc, struct rb_table *tp)
{
uint16_t offset;
uint8_t index;
uint8_t shift;
uint32_t andmask;
uint32_t ormask;
if ((tp == NULL) || ((offset = tp->offset) == 0))
return 1;
DPRINTF(("%s: load_pll_block processing %s\n", XNAME(sc), tp->name));
while ((index = GETBIOS8(sc, offset)) != 0) {
offset++;
switch (index & PLL_FLAG_MASK) {
case PLL_FLAG_WAIT:
switch (index & PLL_INDEX_MASK) {
case PLL_WAIT_150MKS:
delay(150);
break;
case PLL_WAIT_5MS:
/* perhaps this should be tsleep? */
delay(5000);
break;
case PLL_WAIT_MC_BUSY_MASK:
rb_wait_mc_busy_mask(sc, 1000);
break;
case PLL_WAIT_DLL_READY_MASK:
rb_wait_dll_ready_mask(sc, 1000);
break;
case PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24:
rb_wait_chk_set_clk_pwrmgt_cntl24(sc);
break;
}
break;
case PLL_FLAG_MASK_BYTE:
shift = GETBIOS8(sc, offset) * 8;
offset++;
andmask =
(((uint32_t)GETBIOS8(sc, offset)) << shift) |
~((uint32_t)0xff << shift);
offset++;
ormask = ((uint32_t)GETBIOS8(sc, offset)) << shift;
offset++;
DPRINTF(("PLL_MASK_BYTE %u %u %x %x\n", index,
shift, andmask, ormask));
radeonfb_maskpll(sc, index, andmask, ormask);
break;
case PLL_FLAG_WRITE:
DPRINTF(("PLL_WRITE %u %x\n", index,
GETBIOS32(sc, offset)));
radeonfb_putpll(sc, index, GETBIOS32(sc, offset));
offset += 4;
break;
}
}
return 0;
}
int
rb_reset_sdram(struct radeonfb_softc *sc, struct rb_table *tp)
{
uint16_t offset;
uint8_t index;
if ((tp == NULL) || ((offset = tp->offset) == 0))
return 1;
DPRINTF(("%s: reset_sdram processing %s\n", XNAME(sc), tp->name));
while ((index = GETBIOS8(sc, offset)) != 0xff) {
offset++;
if (index == 0x0f) {
rb_wait_mem_pwrup_complete(sc, 20000);
} else {
uint32_t ormask;
ormask = GETBIOS16(sc, offset);
offset += 2;
DPRINTF(("INDEX reg RADEON_MEM_SDRAM_MODE_REG %x %x\n",
RADEON_SDRAM_MODE_MASK, ormask));
radeonfb_maskindex(sc, RADEON_MEM_SDRAM_MODE_REG,
RADEON_SDRAM_MODE_MASK, ormask);
ormask = (uint32_t)index << 24;
DPRINTF(("INDEX reg RADEON_MEM_SDRAM_MODE_REG %x %x\n",
RADEON_B3MEM_RESET_MASK, ormask));
radeonfb_maskindex(sc, RADEON_MEM_SDRAM_MODE_REG,
RADEON_B3MEM_RESET_MASK, ormask);
}
}
return 0;
}
/*
* Master entry point to parse and act on table data.
*/
int
radeonfb_bios_init(struct radeonfb_softc *sc)
{
uint16_t revision;
uint16_t scratch;
int i;
struct rb_table *tp;
if (!sc->sc_biossz)
return 1;
scratch = GETBIOS16(sc, ROM_HEADER_OFFSET);
revision = GETBIOS8(sc, scratch);
DPRINTF(("%s: Bios Rev: %d\n", XNAME(sc), revision));
/* First parse pass -- locate tables */
for (i = 0; (tp = rb_tables[i]) != NULL; i++) {
DPRINTF(("%s: parsing table %s\n", XNAME(sc), tp->name));
if (tp->offset != 0) {
uint16_t temp, offset;;
temp = GETBIOS16(sc, ROM_HEADER_OFFSET);
offset = GETBIOS16(sc, temp + tp->offset);
if (offset)
tp->offset = offset;
} else {
tp->offset = tp->find(sc, tp->parent);
}
if (tp->validate)
tp->validate(sc, tp);
if (revision > SINGLE_TABLE_REVISION)
break;
}
if (rb_rage_regs3_table.offset + 1 == rb_pll_init_table.offset) {
rb_rage_regs3_table.offset = 0;
rb_rage_regs4_table.offset = 0;
}
if (rb_rage_regs1_table.offset)
rb_load_init_block(sc, &rb_rage_regs1_table);
if (revision < SINGLE_TABLE_REVISION) {
if (rb_pll_init_table.offset)
rb_load_pll_block(sc, &rb_pll_init_table);
if (rb_rage_regs2_table.offset)
rb_load_init_block(sc, &rb_rage_regs2_table);
if (rb_rage_regs4_table.offset)
rb_load_init_block(sc, &rb_rage_regs4_table);
if (rb_mem_reset_table.offset)
rb_reset_sdram(sc, &rb_mem_reset_table);
if (rb_rage_regs3_table.offset)
rb_load_init_block(sc, &rb_rage_regs3_table);
if (rb_dyn_clock_table.offset)
rb_load_pll_block(sc, &rb_dyn_clock_table);
}
DPRINTF(("%s: BIOS parse done\n", XNAME(sc)));
return 0;
}
#endif

234
sys/dev/pci/radeonfb_i2c.c Normal file
View File

@ -0,0 +1,234 @@
/*-
* Copyright (c) 2006 Itronix Inc.
* All rights reserved.
*
* Written by Garrett D'Amore for Itronix Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of Itronix Inc. may not be used to endorse
* or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ATI Technologies Inc. ("ATI") has not assisted in the creation of, and
* does not endorse, this software. ATI will not be responsible or liable
* for any actual or alleged damage or loss caused by or in connection with
* the use of or reliance on this software.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: radeonfb_i2c.c,v 1.1 2006/08/16 22:46:45 gdamore Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <dev/i2c/i2cvar.h>
#include <dev/i2c/i2c_bitbang.h>
#include <dev/i2c/ddcvar.h>
#include <dev/pci/radeonfbreg.h>
#include <dev/pci/radeonfbvar.h>
/* i2c support */
static int radeonfb_i2c_acquire_bus(void *, int);
static void radeonfb_i2c_release_bus(void *, int);
static int radeonfb_i2c_send_start(void *, int);
static int radeonfb_i2c_send_stop(void *, int);
static int radeonfb_i2c_initiate_xfer(void *, i2c_addr_t, int);
static int radeonfb_i2c_read_byte(void *, uint8_t *, int);
static int radeonfb_i2c_write_byte(void *, uint8_t, int);
/* i2c bit-bang glue */
static void radeonfb_i2cbb_set_bits(void *, uint32_t);
static void radeonfb_i2cbb_set_dir(void *, uint32_t);
static uint32_t radeonfb_i2cbb_read(void *);
/*
* I2C bit-bang operations
*/
void
radeonfb_i2cbb_set_bits(void *cookie, uint32_t bits)
{
struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie;
struct radeonfb_softc *sc = ric->ric_softc;
PATCH32(sc, ric->ric_register, bits,
~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
}
void
radeonfb_i2cbb_set_dir(void *cookie, uint32_t bits)
{
struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie;
struct radeonfb_softc *sc = ric->ric_softc;
PATCH32(sc, ric->ric_register, bits, ~(RADEON_GPIO_EN_0));
}
uint32_t
radeonfb_i2cbb_read(void *cookie)
{
struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie;
struct radeonfb_softc *sc = ric->ric_softc;
/* output bit is 0 shifted, input bit is shifted 8 */
return (GET32(sc, ric->ric_register) >> RADEON_GPIO_Y_SHIFT_0);
}
static const struct i2c_bitbang_ops radeonfb_i2cbb_ops = {
radeonfb_i2cbb_set_bits,
radeonfb_i2cbb_set_dir,
radeonfb_i2cbb_read,
{
RADEON_GPIO_A_0, /* SDA */
RADEON_GPIO_A_1, /* SCL */
RADEON_GPIO_EN_0, /* SDA output */
0, /* SDA input */
}
};
/*
* I2C support
*/
int
radeonfb_i2c_acquire_bus(void *cookie, int flags)
{
struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie;
struct radeonfb_softc *sc = ric->ric_softc;
int i;
/*
* Some hardware seems to have hardware/software combined access
* to the DVI I2C. We want to use software.
*/
if (ric->ric_register == RADEON_GPIO_DVI_DDC) {
/* ask for software access to I2C bus */
SET32(sc, ric->ric_register, RADEON_GPIO_SW_USE);
/*
* wait for the chip to give up access. we don't make
* this a hard timeout, because some hardware might
* not implement this negotiation protocol
*/
for (i = RADEON_TIMEOUT; i; i--) {
if (GET32(sc, ric->ric_register) & RADEON_GPIO_SW_USE)
break;
}
}
/* enable the I2C clock */
SET32(sc, ric->ric_register, RADEON_GPIO_EN_1);
return 0;
}
void
radeonfb_i2c_release_bus(void *cookie, int flags)
{
struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie;
struct radeonfb_softc *sc = ric->ric_softc;
if (ric->ric_register == RADEON_GPIO_DVI_DDC) {
/* we no longer "want" I2C, and we're "done" with it */
CLR32(sc, ric->ric_register, RADEON_GPIO_SW_USE);
SET32(sc, ric->ric_register, RADEON_GPIO_SW_DONE);
}
}
int
radeonfb_i2c_send_start(void *cookie, int flags)
{
return i2c_bitbang_send_start(cookie, flags, &radeonfb_i2cbb_ops);
}
int
radeonfb_i2c_send_stop(void *cookie, int flags)
{
return i2c_bitbang_send_stop(cookie, flags, &radeonfb_i2cbb_ops);
}
int
radeonfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
{
return i2c_bitbang_initiate_xfer(cookie, addr, flags,
&radeonfb_i2cbb_ops);
}
int
radeonfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
{
return i2c_bitbang_read_byte(cookie, valp, flags, &radeonfb_i2cbb_ops);
}
int
radeonfb_i2c_write_byte(void *cookie, uint8_t val, int flags)
{
return i2c_bitbang_write_byte(cookie, val, flags, &radeonfb_i2cbb_ops);
}
void
radeonfb_i2c_init(struct radeonfb_softc *sc)
{
int i;
for (i = 0; i < 4; i++) {
struct i2c_controller *icc = &sc->sc_i2c[i].ric_controller;
sc->sc_i2c[i].ric_softc = sc;
icc->ic_cookie = &sc->sc_i2c[i];
icc->ic_acquire_bus = radeonfb_i2c_acquire_bus;
icc->ic_release_bus = radeonfb_i2c_release_bus;
icc->ic_send_start = radeonfb_i2c_send_start;
icc->ic_send_stop = radeonfb_i2c_send_stop;
icc->ic_initiate_xfer = radeonfb_i2c_initiate_xfer;
icc->ic_read_byte = radeonfb_i2c_read_byte;
icc->ic_write_byte = radeonfb_i2c_write_byte;
}
/* index == ddctype (RADEON_DDC_XX) - 1 */
sc->sc_i2c[0].ric_register = RADEON_GPIO_MONID;
sc->sc_i2c[1].ric_register = RADEON_GPIO_DVI_DDC;
sc->sc_i2c[2].ric_register = RADEON_GPIO_VGA_DDC;
sc->sc_i2c[3].ric_register = RADEON_GPIO_CRT2_DDC;
}
int
radeonfb_i2c_read_edid(struct radeonfb_softc *sc, int ddctype, uint8_t *data)
{
if ((ddctype < 1) || (ddctype > 4))
return EINVAL;
ddctype--;
return (ddc_read_edid(&sc->sc_i2c[ddctype].ric_controller, data, 128));
}

2779
sys/dev/pci/radeonfbreg.h Normal file

File diff suppressed because it is too large Load Diff

361
sys/dev/pci/radeonfbvar.h Normal file
View File

@ -0,0 +1,361 @@
/* $NetBSD: radeonfbvar.h,v 1.1 2006/08/16 22:46:45 gdamore Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
* All rights reserved.
*
* Written by Garrett D'Amore for Itronix Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of Itronix Inc. may not be used to endorse
* or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ATI Technologies Inc. ("ATI") has not assisted in the creation of, and
* does not endorse, this software. ATI will not be responsible or liable
* for any actual or alleged damage or loss caused by or in connection with
* the use of or reliance on this software.
*/
#ifndef _DEV_PCI_RADEONFBVAR_H
#define _DEV_PCI_RADEONFBVAR_H
#include "opt_splash.h"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/device.h>
#include <dev/pci/pcivar.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wsfont/wsfont.h>
#include <dev/rasops/rasops.h>
#include <dev/wscons/wsdisplay_vconsvar.h>
#include <dev/videomode/videomode.h>
#include <dev/videomode/edidvar.h>
#ifdef SPLASHSCREEN
#include <dev/splash/splash.h>
#endif
#include <dev/i2c/i2cvar.h>
/* XXX: change this when we complete the support for multi HEAD */
#define RADEON_NDISPLAYS (1)
#define RADEON_MAXX (2048)
#define RADEON_MAXY (1536)
#define RADEON_MAXBPP (32)
#define RADEON_STRIDEALIGN (64)
#define RADEON_CURSORMAXX (64)
#define RADEON_CURSORMAXY (64)
#define RADEON_PANINCREMENT (1)
struct radeonfb_softc;
struct radeonfb_port {
int rp_number;
int rp_mon_type;
int rp_conn_type;
int rp_dac_type;
int rp_ddc_type;
int rp_tmds_type;
int rp_edid_valid;
struct edid_info rp_edid;
};
/* connector values used by legacy bios */
#define RADEON_CONN_NONE 0
#define RADEON_CONN_PROPRIETARY 1 /* think LVDS ribbon cable */
#define RADEON_CONN_CRT 2
#define RADEON_CONN_DVI_I 3
#define RADEON_CONN_DVI_D 4
#define RADEON_CONN_CTV 5
#define RADEON_CONN_STV 6
#define RADEON_CONN_UNSUPPORTED 7
/* connector values used by atom bios */
#define ATOM_CONN_NONE 0
#define ATOM_CONN_VGA 1
#define ATOM_CONN_DVI_I 2
#define ATOM_CONN_DVI_D 3
#define ATOM_CONN_DVI_A 4
#define ATOM_CONN_STV 5
#define ATOM_CONN_CTV 6
#define ATOM_CONN_LVDS 7
#define ATOM_CONN_DIGITAL 8
#define ATOM_CONN_UNSUPPORTED 9
#define RADEON_DDC_NONE 0
#define RADEON_DDC_MONID 1
#define RADEON_DDC_DVI 2
#define RADEON_DDC_VGA 3
#define RADEON_DDC_CRT2 4
#define RADEON_DAC_UNKNOWN -1
#define RADEON_DAC_PRIMARY 0
#define RADEON_DAC_TVDAC 1
#define RADEON_TMDS_UNKNOWN -1
#define RADEON_TMDS_INT 0
#define RADEON_TMDS_EXT 1
#define RADEON_MT_UNKNOWN -1
#define RADEON_MT_NONE 0
#define RADEON_MT_CRT 1
#define RADEON_MT_LCD 2 /* LVDS */
#define RADEON_MT_DFP 3 /* TMDS */
#define RADEON_MT_CTV 4
#define RADEON_MT_STV 5
struct radeonfb_i2c {
struct radeonfb_softc *ric_softc;
int ric_register;
struct i2c_controller ric_controller;
};
struct radeonfb_crtc {
int rc_number;
struct videomode rc_videomode;
uint16_t rc_xoffset;
uint16_t rc_yoffset;
struct radeonfb_port *rc_port;
};
struct radeonfb_cursor {
int rc_visible;
struct wsdisplay_curpos rc_pos;
struct wsdisplay_curpos rc_hot;
struct wsdisplay_curpos rc_size;
uint32_t rc_cmap[2];
uint8_t rc_image[512]; /* 64x64x1 bit */
uint8_t rc_mask[512]; /* 64x64x1 bit */
};
struct radeonfb_display {
struct radeonfb_softc *rd_softc;
int rd_number; /* 0 .. RADEON_NDISPLAYS */
bus_size_t rd_offset; /* offset within FB memory */
vaddr_t rd_fbptr; /* framebuffer pointer */
vaddr_t rd_curptr; /* cursor data pointer */
size_t rd_curoff; /* cursor offset */
uint16_t rd_bpp;
uint16_t rd_virtx;
uint16_t rd_virty;
uint16_t rd_stride;
uint16_t rd_format; /* chip pixel format */
uint16_t rd_xoffset;
uint16_t rd_yoffset;
int rd_bg; /* background */
int rd_console;
int rd_wsmode;
int rd_ncrtcs;
struct radeonfb_crtc rd_crtcs[2];
struct radeonfb_cursor rd_cursor;
/* XXX: this should probaby be an array for CRTCs */
//struct videomode rd_videomode;
struct wsscreen_list rd_wsscreenlist;
struct wsscreen_descr rd_wsscreens_storage[1];
struct wsscreen_descr *rd_wsscreens;
struct vcons_screen rd_vscreen;
struct vcons_data rd_vd;
#if 0
uint8_t rd_cmap_red[256];
uint8_t rd_cmap_green[256];
uint8_t rd_cmap_blue[256];
#endif
#ifdef SPLASHSCREEN
struct splash_info rd_splash;
#endif
#ifdef SPLASHSCREEN_PROGRESS
struct splash_progress rd_progress;
#endif
};
struct radeon_tmds_pll {
uint32_t rtp_freq;
uint32_t rtp_pll;
};
struct radeonfb_softc {
struct device sc_dev;
uint16_t sc_family;
uint16_t sc_flags;
pcireg_t sc_id;
char sc_devinfo[256];
bus_space_tag_t sc_regt;
bus_space_handle_t sc_regh;
bus_size_t sc_regsz;
bus_addr_t sc_regaddr;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_memh;
bus_size_t sc_memsz;
bus_addr_t sc_memaddr;
/* size of a single display */
int sc_maxx;
int sc_maxy;
int sc_maxbpp;
int sc_fboffset;
int sc_fbsize;
bus_space_tag_t sc_romt;
bus_space_handle_t sc_romh;
bus_size_t sc_romsz;
bus_space_handle_t sc_biosh;
bus_dma_tag_t sc_dmat;
uint16_t sc_refclk;
uint16_t sc_refdiv;
uint32_t sc_minpll;
uint32_t sc_maxpll;
pci_chipset_tag_t sc_pc;
pcitag_t sc_pt;
/* card's idea of addresses, internally */
uint32_t sc_aperbase;
int sc_ndisplays;
struct radeonfb_display sc_displays[RADEON_NDISPLAYS];
int sc_nports;
struct radeonfb_port sc_ports[2];
struct radeon_tmds_pll sc_tmds_pll[4];
struct radeonfb_i2c sc_i2c[4];
uint8_t *sc_bios;
bus_size_t sc_biossz;
char *sc_modebuf;
const char *sc_defaultmode;
};
/* chip families */
#define RADEON_R100 1
#define RADEON_RV100 2
#define RADEON_RS100 3
#define RADEON_RV200 4
#define RADEON_RS200 5
#define RADEON_R200 6
#define RADEON_RV250 7
#define RADEON_RS300 8
#define RADEON_RV280 9
#define RADEON_R300 10
#define RADEON_R350 11
#define RADEON_RV350 12
#define RADEON_RV380 13
#define RADEON_R420 14
#define RADEON_FAMILIES 15
/* feature flags */
#define RFB_MOB (1 << 0) /* Mobility */
#define RFB_NCRTC2 (1 << 1) /* No CRTC2 */
#define RFB_IGP (1 << 2)
#define RFB_R300CG (1 << 3)
#define RFB_SDAC (1 << 4) /* Single DAC */
#define RFB_R300 (1 << 5) /* R300 variants -- newer parts */
#define RFB_RV100 (1 << 6) /* RV100 variants -- previous gen */
#define RFB_ATOM (1 << 7) /* ATOM bios */
#define IS_MOBILITY(sc) ((sc)->sc_flags & RFB_MOB)
#define HAS_CRTC2(sc) (((sc)->sc_flags & RFB_NCRTC2) == 0)
#define IS_R300(sc) ((sc)->sc_flags & RFB_R300)
#define HAS_R300CG(sc) ((sc)->sc_flags & RFB_R300CG)
#define HAS_SDAC(sc) ((sc)->sc_flags & RFB_SDAC)
#define IS_RV100(sc) ((sc)->sc_flags & RFB_RV100)
#define IS_IGP(sc) ((sc)->sc_flags & RFB_IGP)
#define IS_ATOM(sc) ((sc)->sc_flags & RFB_ATOM)
#define RADEON_TIMEOUT 2000000
#define GET32(sc, r) radeonfb_get32(sc, r)
#define PUT32(sc, r, v) radeonfb_put32(sc, r, v)
#define SET32(sc, r, v) PUT32(sc, r, GET32(sc, r) | (v))
#define CLR32(sc, r, v) PUT32(sc, r, GET32(sc, r) & ~(v))
#define PATCH32(sc, r, v, m) PUT32(sc, r, (GET32(sc, r) & (m)) | (v))
#define GETPLL(sc, r) radeonfb_getpll(sc, r)
#define PUTPLL(sc, r, v) radeonfb_putpll(sc, r, v)
#define SETPLL(sc, r, v) PUTPLL(sc, r, GETPLL(sc, r) | (v))
#define CLRPLL(sc, r, v) PUTPLL(sc, r, GETPLL(sc, r) & ~(v))
#define PATCHPLL(sc, r, v, m) PUTPLL(sc, r, (GETPLL(sc, r) & (m)) | (v))
#define GETROM32(sc, r) bus_space_read_4(sc->sc_romt, sc->sc_romh, r)
#define GETROM16(sc, r) bus_space_read_2(sc->sc_romt, sc->sc_romh, r)
#define GETROM8(sc, r) bus_space_read_1(sc->sc_romt, sc->sc_romh, r)
/*
* Some values in BIOS are misaligned...
*/
#define GETBIOS8(sc, r) ((sc)->sc_bios[(r)])
#define GETBIOS16(sc, r) \
((GETBIOS8(sc, (r) + 1) << 8) | GETBIOS8(sc, (r)))
#define GETBIOS32(sc, r) \
((GETBIOS16(sc, (r) + 2) << 16) | GETBIOS16(sc, (r)))
#define XNAME(sc) device_xname(&sc->sc_dev)
#define DIVIDE(x,y) (((x) + (y / 2)) / (y))
uint32_t radeonfb_get32(struct radeonfb_softc *, uint32_t);
void radeonfb_put32(struct radeonfb_softc *, uint32_t, uint32_t);
void radeonfb_mask32(struct radeonfb_softc *, uint32_t, uint32_t, uint32_t);
uint32_t radeonfb_getindex(struct radeonfb_softc *, uint32_t);
void radeonfb_putindex(struct radeonfb_softc *, uint32_t, uint32_t);
void radeonfb_maskindex(struct radeonfb_softc *, uint32_t, uint32_t, uint32_t);
uint32_t radeonfb_getpll(struct radeonfb_softc *, uint32_t);
void radeonfb_putpll(struct radeonfb_softc *, uint32_t, uint32_t);
void radeonfb_maskpll(struct radeonfb_softc *, uint32_t, uint32_t, uint32_t);
#ifdef RADEON_BIOS_INIT
int radeonfb_bios_init(struct radeonfb_softc *);
#endif
void radeonfb_i2c_init(struct radeonfb_softc *);
int radeonfb_i2c_read_edid(struct radeonfb_softc *, int, uint8_t *);
#endif /* _DEV_PCI_RADEONFBVAR_H */