--- trunk/src/devices/dev_gt.c 2007/10/08 16:19:23 20 +++ trunk/src/devices/dev_gt.c 2007/10/08 16:21:17 34 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2005 Anders Gavare. All rights reserved. + * Copyright (C) 2003-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,16 +25,13 @@ * SUCH DAMAGE. * * - * $Id: dev_gt.c,v 1.35 2005/11/21 09:17:26 debug Exp $ + * $Id: dev_gt.c,v 1.49 2007/01/05 16:50:08 debug Exp $ * * Galileo Technology GT-64xxx PCI controller. * * GT-64011 Used in Cobalt machines. * GT-64120 Used in evbmips machines (Malta). - * - * TODO: This more or less just a dummy device, so far. It happens to work - * with NetBSD/cobalt and /evbmips, and in some cases it might happen - * to work with Linux as well, but don't rely on it for anything else. + * GT-64260 Used in mvmeppc machines. */ #include @@ -44,9 +41,13 @@ #include "bus_pci.h" #include "cpu.h" #include "devices.h" +#include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" +#include "timer.h" + +#include "gtreg.h" #define TICK_SHIFT 14 @@ -55,35 +56,50 @@ #define PCI_PRODUCT_GALILEO_GT64011 0x4146 /* GT-64011 */ #define PCI_PRODUCT_GALILEO_GT64120 0x4620 /* GT-64120 */ +#define PCI_PRODUCT_GALILEO_GT64260 0x6430 /* GT-64260 */ + struct gt_data { - int irqnr; - int pciirq; - int type; + int type; - struct pci_data *pci_data; + struct timer *timer; + struct interrupt timer0_irq; + int interrupt_hz; + int pending_timer0_interrupts; + + /* Address decode registers: */ + uint32_t decode[GT_N_DECODE_REGS]; + + struct pci_data *pci_data; }; /* - * dev_gt_tick(): + * timer_tick(): + * + * Called d->interrupt_hz times per (real-world) second. */ -void dev_gt_tick(struct cpu *cpu, void *extra) +static void timer_tick(struct timer *timer, void *extra) { - struct gt_data *gt_data = extra; + struct gt_data *d = (struct gt_data *) extra; + d->pending_timer0_interrupts ++; +} + - cpu_interrupt(cpu, gt_data->irqnr); +DEVICE_TICK(gt) +{ + struct gt_data *d = (struct gt_data *) extra; + + if (d->pending_timer0_interrupts > 0) + INTERRUPT_ASSERT(d->timer0_irq); } -/* - * dev_gt_access(): - */ -int dev_gt_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, - unsigned char *data, size_t len, int writeflag, void *extra) +DEVICE_ACCESS(gt) { uint64_t idata = 0, odata = 0; - int i; + int bus, dev, func, reg; + size_t i; struct gt_data *d = extra; if (writeflag == MEM_WRITE) @@ -91,60 +107,94 @@ switch (relative_addr) { - case 0x48: - switch (d->type) { - case PCI_PRODUCT_GALILEO_GT64120: - /* - * This is needed for Linux on Malta, according - * to Alec Voropay. (TODO: Remove this hack when - * things have stabilized.) - */ - if (writeflag == MEM_READ) { - odata = 0x18000000 >> 21; - debug("[ gt: read from 0x48: 0x%08x ]\n", - (int)odata); - } - break; - default: - fatal("[ gt: access to 0x48? (type %i) ]\n", d->type); + case GT_PCI0IOLD_OFS: + case GT_PCI0IOHD_OFS: + case GT_PCI0M0LD_OFS: + case GT_PCI0M0HD_OFS: + case GT_PCI0M1LD_OFS: + case GT_PCI0M1HD_OFS: + case GT_PCI0IOREMAP_OFS: + case GT_PCI0M0REMAP_OFS: + case GT_PCI0M1REMAP_OFS: + if (writeflag == MEM_READ) { + odata = d->decode[relative_addr / 8]; + debug("[ gt: read from offset 0x%x: 0x%x ]\n", + (int)relative_addr, (int)odata); + } else { + d->decode[relative_addr / 8] = idata; + fatal("[ gt: write to offset 0x%x: 0x%x (TODO) ]\n", + (int)relative_addr, (int)idata); + } + break; + + case GT_PCI0_CMD_OFS: + if (writeflag == MEM_WRITE) { + debug("[ gt: write to GT_PCI0_CMD: 0x%08x (TODO) ]\n", + (int)idata); + } else { + debug("[ gt: read from GT_PCI0_CMD (0x%08x) (TODO) ]\n", + (int)odata); } break; - case 0xc18: + case GT_INTR_CAUSE: if (writeflag == MEM_WRITE) { - debug("[ gt: write to 0xc18: 0x%08x ]\n", (int)idata); + debug("[ gt: write to GT_INTR_CAUSE: 0x%08x ]\n", + (int)idata); return 1; } else { - odata = 0xffffffffULL; - /* - * ??? interrupt something... - * - * TODO: Remove this hack when things have stabilized. - */ - odata = 0x00000100; - /* netbsd/cobalt cobalt/machdep.c:cpu_intr() */ + odata = GTIC_T0EXP; + INTERRUPT_DEASSERT(d->timer0_irq); - cpu_interrupt_ack(cpu, d->irqnr); + if (d->pending_timer0_interrupts > 0) + d->pending_timer0_interrupts --; - debug("[ gt: read from 0xc18 (0x%08x) ]\n", (int)odata); + debug("[ gt: read from GT_INTR_CAUSE (0x%08x) ]\n", + (int)odata); } break; - case 0xc34: /* GT_PCI0_INTR_ACK */ + case GT_PCI0_INTR_ACK: odata = cpu->machine->isa_pic_data.last_int; - cpu_interrupt_ack(cpu, 8 + odata); + +fatal("TODO: GT_PCI0_INTR_ACK\n"); + +// cpu_interrupt_ack(cpu, d->pci_irqbase + odata); break; - case 0xcf8: /* PCI ADDR */ - case 0xcfc: /* PCI DATA */ + case GT_TIMER_CTRL: if (writeflag == MEM_WRITE) { - bus_pci_access(cpu, mem, relative_addr, &idata, - len, writeflag, d->pci_data); - } else { - bus_pci_access(cpu, mem, relative_addr, &odata, - len, writeflag, d->pci_data); + if (idata & ENTC0) { + /* TODO: Don't hardcode this. */ + d->interrupt_hz = 100; + if (d->timer == NULL) + d->timer = timer_add(d->interrupt_hz, + timer_tick, d); + else + timer_update_frequency(d->timer, + d->interrupt_hz); + } + } + break; + + case GT_PCI0_CFG_ADDR: + if (cpu->byte_order != EMUL_LITTLE_ENDIAN) { + fatal("[ gt: TODO: big endian PCI access ]\n"); + exit(1); } + bus_pci_decompose_1(idata, &bus, &dev, &func, ®); + bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); break; + + case GT_PCI0_CFG_DATA: + if (cpu->byte_order != EMUL_LITTLE_ENDIAN) { + fatal("[ gt: TODO: big endian PCI access ]\n"); + exit(1); + } + bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? + &odata : &idata, len, writeflag); + break; + default: if (writeflag == MEM_READ) { debug("[ gt: read from addr 0x%x ]\n", @@ -167,18 +217,17 @@ /* * dev_gt_init(): * - * Initialize a GT device. Return a pointer to the pci_data used, so that - * the caller may add PCI devices. First, however, we add the GT device - * itself. + * Initialize a Gallileo PCI controller device. First, the controller itself + * is added to the bus, then a pointer to the bus is returned. */ struct pci_data *dev_gt_init(struct machine *machine, struct memory *mem, - uint64_t baseaddr, int irq_nr, int pciirq, int type) + uint64_t baseaddr, char *timer_irq_path, char *isa_irq_path, int type) { struct gt_data *d; uint64_t pci_portbase = 0, pci_membase = 0; uint64_t isa_portbase = 0, isa_membase = 0; - int isa_irqbase = 0, pci_irqbase = 0; uint64_t pci_io_offset = 0, pci_mem_offset = 0; + char *gt_name = "NO"; d = malloc(sizeof(struct gt_data)); if (d == NULL) { @@ -186,54 +235,76 @@ exit(1); } memset(d, 0, sizeof(struct gt_data)); - d->irqnr = irq_nr; - d->pciirq = pciirq; + + INTERRUPT_CONNECT(timer_irq_path, d->timer0_irq); switch (type) { case 11: /* Cobalt: */ d->type = PCI_PRODUCT_GALILEO_GT64011; + gt_name = "gt64011"; pci_io_offset = 0; pci_mem_offset = 0; pci_portbase = 0x10000000ULL; pci_membase = 0x10100000ULL; - pci_irqbase = 0; isa_portbase = 0x10000000ULL; isa_membase = 0x10100000ULL; - isa_irqbase = 8; break; case 120: /* EVBMIPS (Malta): */ d->type = PCI_PRODUCT_GALILEO_GT64120; + gt_name = "gt64120"; pci_io_offset = 0; pci_mem_offset = 0; pci_portbase = 0x18000000ULL; pci_membase = 0x10000000ULL; - pci_irqbase = 8; isa_portbase = 0x18000000ULL; isa_membase = 0x10000000ULL; - isa_irqbase = 8; break; - default:fatal("dev_gt_init(): type must be 11 or 120.\n"); + case 260: + /* MVMEPPC (mvme5500): */ + d->type = PCI_PRODUCT_GALILEO_GT64260; + gt_name = "gt64260"; + pci_io_offset = 0; + pci_mem_offset = 0; + pci_portbase = 0x18000000ULL; + pci_membase = 0x10000000ULL; + isa_portbase = 0x18000000ULL; + isa_membase = 0x10000000ULL; + break; + default:fatal("dev_gt_init(): unimplemented GT type (%i).\n", type); exit(1); } - d->pci_data = bus_pci_init( - pciirq, pci_io_offset, pci_mem_offset, - pci_portbase, pci_membase, pci_irqbase, - isa_portbase, isa_membase, isa_irqbase); + + /* + * TODO: FIX THESE! Hardcoded numbers = bad. + */ + d->decode[GT_PCI0IOLD_OFS / 8] = pci_portbase >> 21; + d->decode[GT_PCI0IOHD_OFS / 8] = 0x40; + d->decode[GT_PCI0M0LD_OFS / 8] = 0x80; + d->decode[GT_PCI0M0HD_OFS / 8] = 0x3f; + d->decode[GT_PCI0M1LD_OFS / 8] = 0xc1; + d->decode[GT_PCI0M1HD_OFS / 8] = 0x5e; + d->decode[GT_PCI0IOREMAP_OFS / 8] = d->decode[GT_PCI0IOLD_OFS / 8]; + d->decode[GT_PCI0M0REMAP_OFS / 8] = d->decode[GT_PCI0M0LD_OFS / 8]; + d->decode[GT_PCI0M1REMAP_OFS / 8] = d->decode[GT_PCI0M1LD_OFS / 8]; + + d->pci_data = bus_pci_init(machine, + "TODO irq stuff!", pci_io_offset, pci_mem_offset, + pci_portbase, pci_membase, "TODO: pci_irqbase", + isa_portbase, isa_membase, isa_irq_path); /* * According to NetBSD/cobalt: * pchb0 at pci0 dev 0 function 0: Galileo GT-64011 * System Controller, rev 1 */ - bus_pci_add(machine, d->pci_data, mem, 0, 0, 0, - d->type == PCI_PRODUCT_GALILEO_GT64011? "gt64011" : "gt64120"); + bus_pci_add(machine, d->pci_data, mem, 0, 0, 0, gt_name); memory_device_register(mem, "gt", baseaddr, DEV_GT_LENGTH, dev_gt_access, d, DM_DEFAULT, NULL); - machine_add_tickfunction(machine, dev_gt_tick, d, TICK_SHIFT); + machine_add_tickfunction(machine, dev_gt_tick, d, TICK_SHIFT, 0.0); return d->pci_data; }