drivers part from openbios.patch-15-svn25.bz2

git-svn-id: svn://coreboot.org/openbios/openbios-devel@26 f158a5a8-5612-0410-a976-696ce0be7e32
This commit is contained in:
Stefan Reinauer
2006-05-22 22:10:54 +00:00
parent 2759b42cc1
commit 9bff6c0d34
4 changed files with 630 additions and 41 deletions

View File

@@ -25,8 +25,9 @@
#include "asm/dma.h"
#include "esp.h"
#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */
#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
#define MACIO_ESPDMA 0x08400000 /* ESP DMA controller */
#define MACIO_ESP 0x08800000 /* ESP SCSI */
#define BUFSIZE 4096
#define REGISTER_NAMED_NODE( name, path ) do { \
@@ -294,16 +295,14 @@ NODE_METHODS(ob_sd) = {
static int
espdma_init(struct esp_dma *espdma)
espdma_init(unsigned long base, struct esp_dma *espdma)
{
void *p;
espdma->regs = (void *)map_io(base + MACIO_ESPDMA, 0x10);
/* Hardcode everything for MrCoffee. */
if ((p = (void *)map_io(PHYS_JJ_ESPDMA, 0x10)) == 0) {
if (espdma->regs == 0) {
DPRINTF("espdma_init: cannot map registers\n");
return -1;
}
espdma->regs = p;
DPRINTF("dma1: ");
@@ -340,6 +339,21 @@ espdma_init(struct esp_dma *espdma)
}
DPRINTF("\n");
push_str("/iommu/sbus/espdma");
fword("find-device");
/* set reg */
PUSH(4);
fword("encode-int");
PUSH(MACIO_ESPDMA);
fword("encode-int");
fword("encode+");
PUSH(0x00000010);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
return 0;
}
@@ -358,7 +372,7 @@ ob_esp_initialize(__attribute__((unused)) esp_private_t **esp)
/* set reg */
PUSH(4);
fword("encode-int");
PUSH(0x08800000);
PUSH(MACIO_ESP);
fword("encode-int");
fword("encode+");
PUSH(0x00000010);
@@ -407,7 +421,8 @@ add_alias(const char *device, const char *alias)
fword("property");
}
int ob_esp_init(void)
int
ob_esp_init(unsigned long base)
{
int id, diskcount = 0, cdcount = 0, *counter_ptr;
char nodebuff[256], aliasbuff[256];
@@ -423,11 +438,11 @@ int ob_esp_init(void)
global_esp = esp;
if (espdma_init(&esp->espdma) != 0) {
if (espdma_init(base, &esp->espdma) != 0) {
return -1;
}
/* Get the IO region */
esp->ll = (void *)map_io(PHYS_JJ_ESP, sizeof(struct esp_regs));
esp->ll = (void *)map_io(base + MACIO_ESP, sizeof(struct esp_regs));
if (esp->ll == 0) {
DPRINTF("Can't map ESP registers\n");
return -1;

View File

@@ -18,7 +18,6 @@
#include "pgtsrmmu.h"
#include "iommu.h"
#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ)
#define LOWMEMSZ 32 * 1024 * 1024
@@ -61,7 +60,8 @@ struct iommu ciommu;
#define NCTX_SWIFT 0x100
static void iommu_init(struct iommu *t);
static void iommu_init(struct iommu *t, unsigned long base);
static void
iommu_invalidate(struct iommu_regs *regs) {
regs->tlbflush = 0;
@@ -199,11 +199,72 @@ map_io(unsigned pa, int size)
* Switch page tables.
*/
void
init_mmu_swift(void)
init_mmu_swift(unsigned long base)
{
extern unsigned int qemu_mem_size;
unsigned int addr, i;
unsigned long pa, va;
push_str("/memory");
fword("find-device");
PUSH(0);
fword("encode-int");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(qemu_mem_size);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
PUSH(0);
fword("encode-int");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(va2pa((unsigned long)&_data) - 1);
fword("encode-int");
fword("encode+");
push_str("available");
fword("property");
push_str("/virtual-memory");
fword("find-device");
PUSH(0);
fword("encode-int");
PUSH(base);
fword("encode-int");
fword("encode+");
PUSH(0x300);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
PUSH(0);
fword("encode-int");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(va2pa((unsigned long)&_start) - 1);
fword("encode-int");
fword("encode+");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(va2pa((unsigned long)&_iomem));
fword("encode-int");
fword("encode+");
PUSH(-va2pa((unsigned long)&_iomem));
fword("encode-int");
fword("encode+");
push_str("available");
fword("property");
mem_init(&cio, (char *)&_end, (char *)&_iomem);
context_table = mem_zalloc(&cmem, NCTX_SWIFT * sizeof(int), NCTX_SWIFT * sizeof(int));
@@ -249,7 +310,7 @@ init_mmu_swift(void)
srmmu_set_context(0);
srmmu_set_ctable_ptr(va2pa((unsigned long)context_table));
srmmu_flush_whole_tlb();
iommu_init(&ciommu);
iommu_init(&ciommu, base);
}
/*
* XXX This is a problematic interface. We alloc _memory_ which is uncached.
@@ -311,7 +372,7 @@ dvma_alloc(int size, unsigned int *pphys)
* the routine is higher in food chain.
*/
static void
iommu_init(struct iommu *t)
iommu_init(struct iommu *t, unsigned long base)
{
unsigned int *ptab;
int ptsize;
@@ -319,7 +380,7 @@ iommu_init(struct iommu *t)
unsigned int impl, vers;
unsigned int tmp;
if ((regs = map_io(PHYS_JJ_IOMMU, sizeof(struct iommu_regs))) == 0) {
if ((regs = map_io(base, sizeof(struct iommu_regs))) == 0) {
DPRINTF("Cannot map IOMMU\n");
for (;;) { }
}

View File

@@ -17,69 +17,395 @@
#include "libc/vsprintf.h"
#include "openbios/drivers.h"
#include "openbios/nvram.h"
#include "obio.h"
#define REGISTER_NAMED_NODE( name, path ) do { \
bind_new_node( name##_flags_, name##_size_, \
path, name##_m, sizeof(name##_m)/sizeof(method_t)); \
} while(0)
/* DECLARE data structures for the nodes. */
DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
static void
ob_zs_init(unsigned long slavio_base)
ob_new_obio_device(const char *name, const char *type)
{
unsigned long zs_addr;
zs_addr = (unsigned long)map_io(slavio_base + 0x0, 8);
push_str("/obio/zs@0,0");
push_str("/obio");
fword("find-device");
PUSH(zs_addr);
fword("new-device");
push_str(name);
fword("device-name");
if (type) {
push_str(type);
fword("device-type");
}
}
static unsigned long
ob_reg(unsigned long base, unsigned long offset, unsigned long size, int map)
{
PUSH(0);
fword("encode-int");
PUSH(sizeof(zs_addr));
PUSH(offset);
fword("encode-int");
fword("encode+");
push_str("address");
PUSH(size);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
zs_addr = (unsigned long)map_io(slavio_base + 0x00100000, 8);
push_str("/obio/zs@0,100000");
fword("find-device");
PUSH(zs_addr);
if (map) {
unsigned long addr;
addr = (unsigned long)map_io(base + offset, size);
PUSH(addr);
fword("encode-int");
PUSH(4);
fword("encode-int");
fword("encode+");
push_str("address");
fword("property");
return addr;
}
return 0;
}
static void
ob_intr(int intr)
{
PUSH(intr);
fword("encode-int");
PUSH(sizeof(zs_addr));
PUSH(0);
fword("encode-int");
fword("encode+");
push_str("address");
push_str("intr");
fword("property");
}
static void
ob_zs_init(unsigned long base, unsigned long offset, int intr, int slave, int keyboard)
{
ob_new_obio_device("zs", "serial");
ob_reg(base, offset, ZS_REGS, 1);
PUSH(slave);
fword("encode-int");
push_str("slave");
fword("property");
if (keyboard) {
PUSH(-1);
fword("encode-int");
push_str("keyboard");
fword("property");
PUSH(-1);
fword("encode-int");
push_str("mouse");
fword("property");
}
ob_intr(intr);
fword("finish-device");
}
static char *nvram;
struct qemu_nvram_v1 nv_info;
void
arch_nvram_get(char *data)
{
memcpy(data, nvram, NVRAM_SIZE);
}
void
arch_nvram_put(char *data)
{
memcpy(nvram, data, NVRAM_SIZE);
}
int
arch_nvram_size(void)
{
return NVRAM_SIZE;
}
static void
ob_nvram_init(unsigned long base, unsigned long offset)
{
extern uint32_t kernel_image;
extern uint32_t kernel_size;
extern uint32_t cmdline;
extern uint32_t cmdline_size;
extern char boot_device;
ob_new_obio_device("eeprom", NULL);
nvram = (char *)ob_reg(base, offset, NVRAM_SIZE, 1);
memcpy(&nv_info, nvram, sizeof(nv_info));
printk("Nvram id %s, version %d\n", nv_info.id_string, nv_info.version);
if (strcmp(nv_info.id_string, "QEMU_BIOS") || nv_info.version != 1) {
printk("Unknown nvram, freezing!\n");
for (;;);
}
kernel_image = nv_info.kernel_image;
kernel_size = nv_info.kernel_size;
cmdline = nv_info.cmdline;
cmdline_size = nv_info.cmdline_size;
boot_device = nv_info.boot_device;
push_str("mk48t08");
fword("model");
fword("finish-device");
push_str("/");
fword("find-device");
PUSH((long)&nvram[NVRAM_IDPROM]);
PUSH(32);
fword("encode-bytes");
push_str("idprom");
fword("property");
}
static void
ob_obio_open(int *idx)
ob_fd_init(unsigned long base, unsigned long offset, int intr)
{
ob_new_obio_device("SUNW,fdtwo", "block");
ob_reg(base, offset, FD_REGS, 0);
ob_intr(intr);
fword("finish-device");
}
static void
ob_sconfig_init(unsigned long base, unsigned long offset)
{
ob_new_obio_device("slavioconfig", NULL);
ob_reg(base, offset, SCONFIG_REGS, 0);
fword("finish-device");
}
static void
ob_auxio_init(unsigned long base, unsigned long offset)
{
ob_new_obio_device("auxio", NULL);
ob_reg(base, offset, AUXIO_REGS, 0);
fword("finish-device");
}
static void
ob_power_init(unsigned long base, unsigned long offset, int intr)
{
ob_new_obio_device("power", NULL);
ob_reg(base, offset, POWER_REGS, 0);
ob_intr(intr);
fword("finish-device");
}
static void
ob_counter_init(unsigned long base, unsigned long offset)
{
volatile struct sun4m_timer_regs *regs;
ob_new_obio_device("counter", NULL);
PUSH(0);
fword("encode-int");
PUSH(offset);
fword("encode-int");
fword("encode+");
PUSH(COUNTER_REGS);
fword("encode-int");
fword("encode+");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(offset + 0x10000);
fword("encode-int");
fword("encode+");
PUSH(COUNTER_REGS);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
fword("finish-device");
regs = map_io(base + offset, sizeof(*regs));
regs->l10_timer_limit = (((1000000/100) + 1) << 10);
regs->cpu_timers[0].l14_timer_limit = 0;
}
static void
ob_interrupt_init(unsigned long base, unsigned long offset)
{
volatile struct sun4m_intregs *regs;
ob_new_obio_device("interrupt", NULL);
PUSH(0);
fword("encode-int");
PUSH(offset);
fword("encode-int");
fword("encode+");
PUSH(INTERRUPT_REGS);
fword("encode-int");
fword("encode+");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(offset + 0x10000);
fword("encode-int");
fword("encode+");
PUSH(INTERRUPT_REGS);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
fword("finish-device");
regs = map_io(base + offset, sizeof(*regs));
regs->set = ~SUN4M_INT_MASKALL;
regs->cpu_intregs[0].clear = ~0x17fff;
}
static void
ob_obio_open(__attribute__((unused))int *idx)
{
int ret=1;
RET ( -ret );
}
static void
ob_obio_close(int *idx)
ob_obio_close(__attribute__((unused))int *idx)
{
selfword("close-deblocker");
}
static void
ob_obio_initialize(int *idx)
ob_obio_initialize(__attribute__((unused))int *idx)
{
push_str("/");
fword("find-device");
fword("new-device");
push_str("obio");
fword("device-name");
push_str("hierarchical");
fword("device-type");
PUSH(2);
fword("encode-int");
push_str("#address-cells");
fword("property");
PUSH(1);
fword("encode-int");
push_str("#size-cells");
fword("property");
fword("finish-device");
}
static void
ob_set_obio_ranges(unsigned long base)
{
push_str("/obio");
fword("find-device");
PUSH(0);
fword("encode-int");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(0);
fword("encode-int");
fword("encode+");
PUSH(base);
fword("encode-int");
fword("encode+");
PUSH(SLAVIO_SIZE);
fword("encode-int");
fword("encode+");
push_str("ranges");
fword("property");
}
static void
ob_obio_decodeunit(__attribute__((unused)) int *idx)
{
fword("decode-unit-sbus");
}
NODE_METHODS(ob_obio_node) = {
static void
ob_obio_encodeunit(__attribute__((unused)) int *idx)
{
fword("encode-unit-sbus");
}
NODE_METHODS(ob_obio) = {
{ NULL, ob_obio_initialize },
{ "open", ob_obio_open },
{ "close", ob_obio_close },
{ "encode-unit", ob_obio_encodeunit },
{ "decode-unit", ob_obio_decodeunit },
};
int ob_obio_init(unsigned long slavio_base)
int
ob_obio_init(unsigned long slavio_base)
{
//printk("Initializing OBIO devices...\n");
ob_zs_init(slavio_base);
#if 0 // XXX
REGISTER_NAMED_NODE(ob_obio, "/obio");
device_end();
ob_set_obio_ranges(slavio_base);
#endif
ob_zs_init(slavio_base, SLAVIO_ZS, ZS_INTR, 1, 1);
ob_zs_init(slavio_base, SLAVIO_ZS1, ZS_INTR, 0, 0);
ob_nvram_init(slavio_base, SLAVIO_NVRAM);
ob_fd_init(slavio_base, SLAVIO_FD, FD_INTR);
ob_sconfig_init(slavio_base, SLAVIO_SCONFIG);
ob_auxio_init(slavio_base, SLAVIO_AUXIO);
ob_power_init(slavio_base, SLAVIO_POWER, POWER_INTR);
ob_counter_init(slavio_base, SLAVIO_COUNTER);
ob_interrupt_init(slavio_base, SLAVIO_INTERRUPT);
return 0;
}

187
drivers/obio.h Normal file
View File

@@ -0,0 +1,187 @@
/* Addresses, interrupt numbers, register sizes */
#define SLAVIO_ZS 0x00000000
#define SLAVIO_ZS1 0x00100000
#define ZS_INTR 0x2c
#define ZS_REGS 8
#define SLAVIO_NVRAM 0x00200000
#define NVRAM_SIZE 0x2000
#define NVRAM_IDPROM 0x1fd8
#define SLAVIO_FD 0x00400000
#define FD_REGS 15
#define FD_INTR 0x2b
#define SLAVIO_SCONFIG 0x00800000
#define SCONFIG_REGS 1
#define SLAVIO_AUXIO 0x00900000
#define AUXIO_REGS 1
#define SLAVIO_POWER 0x00910000
#define POWER_REGS 1
#define POWER_INTR 0x22
#define SLAVIO_COUNTER 0x00d00000
#define COUNTER_REGS 0x10
#define SLAVIO_INTERRUPT 0x00e00000
#define INTERRUPT_REGS 0x10
#define SLAVIO_SIZE 0x01000000
struct qemu_nvram_v1 {
char id_string[16];
uint32_t version;
uint32_t nvram_size; // not used in Sun4m
char unused1[8];
char arch[12];
char smp_cpus;
char unused2;
char nographic;
uint32_t ram_size;
char boot_device;
char unused3[3];
uint32_t kernel_image;
uint32_t kernel_size;
uint32_t cmdline;
uint32_t cmdline_size;
uint32_t initrd_image;
uint32_t initrd_size;
uint32_t nvram_image;
uint16_t width;
uint16_t height;
uint16_t depth;
char unused4[158];
uint16_t crc;
};
#define SUN4M_NCPUS 16
#define PAGE_SIZE 4096
/* linux/include/asm-sparc/timer.h */
/* A sun4m has two blocks of registers which are probably of the same
* structure. LSI Logic's L64851 is told to _decrement_ from the limit
* value. Aurora behaves similarly but its limit value is compacted in
* other fashion (it's wider). Documented fields are defined here.
*/
/* As with the interrupt register, we have two classes of timer registers
* which are per-cpu and master. Per-cpu timers only hit that cpu and are
* only level 14 ticks, master timer hits all cpus and is level 10.
*/
#define SUN4M_PRM_CNT_L 0x80000000
#define SUN4M_PRM_CNT_LVALUE 0x7FFFFC00
struct sun4m_timer_percpu_info {
__volatile__ unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
__volatile__ unsigned int l14_cur_count;
/* This register appears to be write only and/or inaccessible
* on Uni-Processor sun4m machines.
*/
__volatile__ unsigned int l14_limit_noclear; /* Data access error is here */
__volatile__ unsigned int cntrl; /* =1 after POST on Aurora */
__volatile__ unsigned char space[PAGE_SIZE - 16];
};
struct sun4m_timer_regs {
struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
volatile unsigned int l10_timer_limit;
volatile unsigned int l10_cur_count;
/* Again, this appears to be write only and/or inaccessible
* on uni-processor sun4m machines.
*/
volatile unsigned int l10_limit_noclear;
/* This register too, it must be magic. */
volatile unsigned int foobar;
volatile unsigned int cfg; /* equals zero at boot time... */
};
/*
* Registers of hardware timer in sun4m.
*/
struct sun4m_timer_percpu {
volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
volatile unsigned int l14_cur_count;
};
struct sun4m_timer_global {
volatile unsigned int l10_timer_limit;
volatile unsigned int l10_cur_count;
};
/* linux/include/asm-sparc/irq.h */
/* These registers are used for sending/receiving irqs from/to
* different cpu's.
*/
struct sun4m_intreg_percpu {
unsigned int tbt; /* Interrupts still pending for this cpu. */
/* These next two registers are WRITE-ONLY and are only
* "on bit" sensitive, "off bits" written have NO affect.
*/
unsigned int clear; /* Clear this cpus irqs here. */
unsigned int set; /* Set this cpus irqs here. */
unsigned char space[PAGE_SIZE - 12];
};
/*
* djhr
* Actually the clear and set fields in this struct are misleading..
* according to the SLAVIO manual (and the same applies for the SEC)
* the clear field clears bits in the mask which will ENABLE that IRQ
* the set field sets bits in the mask to DISABLE the IRQ.
*
* Also the undirected_xx address in the SLAVIO is defined as
* RESERVED and write only..
*
* DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
* sun4m machines, for MP the layout makes more sense.
*/
struct sun4m_intregs {
struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
unsigned int tbt; /* IRQ's that are still pending. */
unsigned int irqs; /* Master IRQ bits. */
/* Again, like the above, two these registers are WRITE-ONLY. */
unsigned int clear; /* Clear master IRQ's by setting bits here. */
unsigned int set; /* Set master IRQ's by setting bits here. */
/* This register is both READ and WRITE. */
unsigned int undirected_target; /* Which cpu gets undirected irqs. */
};
/* Dave Redman (djhr@tadpole.co.uk)
* The sun4m interrupt registers.
*/
#define SUN4M_INT_ENABLE 0x80000000
#define SUN4M_INT_E14 0x00000080
#define SUN4M_INT_E10 0x00080000
#define SUN4M_HARD_INT(x) (0x000000001 << (x))
#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
#define SUN4M_INT_REALTIME 0x00080000 /* system timer */
#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */
#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */
#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */