Author: stepan Date: 2006-05-23 00:10:54 +0200 (Tue, 23 May 2006) New Revision: 26
Added: openbios-devel/drivers/obio.h Modified: openbios-devel/drivers/esp.c openbios-devel/drivers/iommu.c openbios-devel/drivers/obio.c Log: drivers part from openbios.patch-15-svn25.bz2
Modified: openbios-devel/drivers/esp.c =================================================================== --- openbios-devel/drivers/esp.c 2006-05-22 10:37:34 UTC (rev 25) +++ openbios-devel/drivers/esp.c 2006-05-22 22:10:54 UTC (rev 26) @@ -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 @@
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 @@ } 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 @@ /* set reg */ PUSH(4); fword("encode-int"); - PUSH(0x08800000); + PUSH(MACIO_ESP); fword("encode-int"); fword("encode+"); PUSH(0x00000010); @@ -407,7 +421,8 @@ 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 @@
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;
Modified: openbios-devel/drivers/iommu.c =================================================================== --- openbios-devel/drivers/iommu.c 2006-05-22 10:37:34 UTC (rev 25) +++ openbios-devel/drivers/iommu.c 2006-05-22 22:10:54 UTC (rev 26) @@ -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 @@
#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 @@ * 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 @@ 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 @@ * 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 @@ 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 (;;) { } }
Modified: openbios-devel/drivers/obio.c =================================================================== --- openbios-devel/drivers/obio.c 2006-05-22 10:37:34 UTC (rev 25) +++ openbios-devel/drivers/obio.c 2006-05-22 22:10:54 UTC (rev 26) @@ -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; + push_str("/obio"); + fword("find-device"); + fword("new-device");
- zs_addr = (unsigned long)map_io(slavio_base + 0x0, 8); - push_str("/obio/zs@0,0"); - fword("find-device"); - - PUSH(zs_addr); + 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"); + 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(0); + fword("encode-int"); + fword("encode+"); + 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(zs_addr); + PUSH((long)&nvram[NVRAM_IDPROM]); + PUSH(32); + fword("encode-bytes"); + push_str("idprom"); + fword("property"); +} + +static void +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(sizeof(zs_addr)); + PUSH(offset); fword("encode-int"); fword("encode+"); - push_str("address"); + 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_obio_open(int *idx) +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"); +}
-NODE_METHODS(ob_obio_node) = { +static void +ob_obio_decodeunit(__attribute__((unused)) int *idx) +{ + fword("decode-unit-sbus"); +} + + +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; }
Added: openbios-devel/drivers/obio.h =================================================================== --- openbios-devel/drivers/obio.h (rev 0) +++ openbios-devel/drivers/obio.h 2006-05-22 22:10:54 UTC (rev 26) @@ -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 */ +