From: M. R. B. <mr...@us...> - 2001-03-13 10:26:49
|
Update of /cvsroot/linuxdc/linux/arch/sh/kernel In directory usw-pr-cvs1:/tmp/cvs-serv20485/arch/sh/kernel Modified Files: pci_gaps.c Log Message: PCI is fixed. New TODO.dc file Index: pci_gaps.c =================================================================== RCS file: /cvsroot/linuxdc/linux/arch/sh/kernel/pci_gaps.c,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -r1.1 -r1.2 *** pci_gaps.c 2001/03/11 11:10:33 1.1 --- pci_gaps.c 2001/03/13 10:28:47 1.2 *************** *** 10,20 **** * Low-level access to the GAPS PCI bridge (found on Sega's Broadband * Adapter). ! */ ! ! /* ! * Much of the GAPS PCI code is adapted from Jason R. Thorpe's and Marcus * Comstedt's NetBSD Dreamcast port at http://www.netbsd.org/Ports/dreamcast/ * * The rest is templated from pci_st40.c by David J. Mckay. */ --- 10,24 ---- * Low-level access to the GAPS PCI bridge (found on Sega's Broadband * Adapter). ! * ! * Some of the GAPS PCI code is adapted from Jason R. Thorpe's and Marcus * Comstedt's NetBSD Dreamcast port at http://www.netbsd.org/Ports/dreamcast/ * * The rest is templated from pci_st40.c by David J. Mckay. + * + * The GAPS (whatever that stands for) PCI "bridge" is unique as it only + * supports one device, Sega's Broadband Adapter (RealTek RTL8139C). It + * also doesn't follow normal PCI conventions, so all resource allocation, + * etc. must be handled in here (e.g. no PCI helper functions). This allows + * for numerous shortcuts in bus and device initialization. */ *************** *** 35,62 **** #include <asm/pci.h> ! #define GAPSPCI_BASE_ADDR 0xa1001400 ! #define GAPSPCI_PCI_ADDR 0xa1001600 ! #define GAPSPCI_DEVICE_ADDR 0x01001700 #define GAPSPCI_DMA_BASE 0x01840000 ! #define GAPSPCI_DMA_SIZE 32768 #define GAPSPCI_INIT_MAGIC 0x5a14a501 ! /* ! * We only support one device. That means that any other "detected" devices ! * are spurious, and we want to act like they never happened. ! * XXX - This is evil hackery, is there a better way to prevent the kernel ! * from scanning all possible slots? ! */ ! #define CHECK_DEVFN do { \ ! if (dev->devfn != 0) return PCIBIOS_DEVICE_NOT_FOUND; \ ! } while (0) static int gapspci_read_config_byte(struct pci_dev *dev,int where,u8 *val) { ! CHECK_DEVFN; ! *val = readb(GAPSPCI_PCI_ADDR + where); ! return PCIBIOS_SUCCESSFUL; } --- 39,68 ---- #include <asm/pci.h> ! #define GAPSPCI_REG_BASE 0xa1001400 /* Accessed from CPU space */ ! #define GAPSPCI_PCI_BASE 0xa1001600 /* '' '' */ ! #define GAPSPCI_DEVICE_BASE 0x01001700 #define GAPSPCI_DMA_BASE 0x01840000 ! #define GAPSPCI_DMA_SIZE 0x8000 ! #define GAPSPCI_DMA_END (GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE) #define GAPSPCI_INIT_MAGIC 0x5a14a501 ! #define GAPSPCI_REG_IMR (GAPSPCI_REG_BASE + 0x14) ! #define GAPSPCI_REG_STATUS (GAPSPCI_REG_BASE + 0x18) ! #define GAPSPCI_REG_UNKN_20 (GAPSPCI_REG_BASE + 0x20) ! #define GAPSPCI_REG_UNKN_24 (GAPSPCI_REG_BASE + 0x24) ! #define GAPSPCI_REG_DMASTART (GAPSPCI_REG_BASE + 0x28) ! #define GAPSPCI_REG_DMAEND (GAPSPCI_REG_BASE + 0x2c) ! #define GAPSPCI_REG_UNKN_34 (GAPSPCI_REG_BASE + 0x34) ! ! #define GAPSPCI_IRQ 11 + #define GAPSPCI_REG_IMR 0xa05f6924 + #define GAPSPCI_IRQ_ENA (1<<3) + static int gapspci_read_config_byte(struct pci_dev *dev,int where,u8 *val) { ! *val = readb(GAPSPCI_PCI_BASE + where); return PCIBIOS_SUCCESSFUL; } *************** *** 65,71 **** u16 * val) { ! CHECK_DEVFN; ! *val = readw(GAPSPCI_PCI_ADDR + where); ! return PCIBIOS_SUCCESSFUL; } --- 71,75 ---- u16 * val) { ! *val = readw(GAPSPCI_PCI_BASE + where); return PCIBIOS_SUCCESSFUL; } *************** *** 74,88 **** * Special case: since we only support one device (the BBA), if the kernel * is accessing the BAR we just return the address of the BBA. */ static int gapspci_read_config_dword(struct pci_dev *dev, int where, u32 * val) { - CHECK_DEVFN; if (where == PCI_BASE_ADDRESS_1) { ! *val = GAPSPCI_DEVICE_ADDR; } else { ! *val = readl(GAPSPCI_PCI_ADDR + where); } - return PCIBIOS_SUCCESSFUL; } --- 78,94 ---- * Special case: since we only support one device (the BBA), if the kernel * is accessing the BAR we just return the address of the BBA. + * + * XXX - Technically, since we aren't mapping devices PCI-style, we could + * remove the check for PCI(0x14). But until I'm sure no other obscure spot + * does resource mapping, it'll stay :) */ static int gapspci_read_config_dword(struct pci_dev *dev, int where, u32 * val) { if (where == PCI_BASE_ADDRESS_1) { ! *val = GAPSPCI_DEVICE_BASE; } else { ! *val = readl(GAPSPCI_PCI_BASE + where); } return PCIBIOS_SUCCESSFUL; } *************** *** 91,97 **** u8 val) { ! CHECK_DEVFN; ! writeb(val, GAPSPCI_PCI_ADDR + where); ! return PCIBIOS_SUCCESSFUL; } --- 97,101 ---- u8 val) { ! writeb(val, GAPSPCI_PCI_BASE + where); return PCIBIOS_SUCCESSFUL; } *************** *** 101,107 **** u16 val) { ! CHECK_DEVFN; ! writew(val, GAPSPCI_PCI_ADDR + where); ! return PCIBIOS_SUCCESSFUL; } --- 105,109 ---- u16 val) { ! writew(val, GAPSPCI_PCI_BASE + where); return PCIBIOS_SUCCESSFUL; } *************** *** 110,122 **** * Special case: only one device is supported, so don't allow writes to the * BAR. */ static int gapspci_write_config_dword(struct pci_dev *dev, int where, u32 val) { ! CHECK_DEVFN; ! if (where == PCI_BASE_ADDRESS_1 && val != 0x01000000) { ! ; ! } else { ! writel(val, GAPSPCI_PCI_ADDR + where); } --- 112,123 ---- * Special case: only one device is supported, so don't allow writes to the * BAR. + * + * XXX - See gapspci_read_config_dword. */ static int gapspci_write_config_dword(struct pci_dev *dev, int where, u32 val) { ! if (where != PCI_BASE_ADDRESS_1) { ! writel(val, GAPSPCI_PCI_BASE + where); } *************** *** 134,146 **** - /* Everything hangs off this */ - static struct pci_bus *pci_root_bus; - - - static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) - { - return PCI_SLOT(dev->devfn); - } - /* * Interrupt handling: reuse the IRQ9 routines from setup_powervr2dc.c. --- 135,138 ---- *************** *** 149,155 **** */ - #define GAPSPCI_REG_IMR 0xa05f6924 - #define GAPSPCI_IRQ_ENA (1<<3) - static inline void disable_gapspci_irq(unsigned int irq) { --- 141,144 ---- *************** *** 162,165 **** --- 151,160 ---- } + /* + * XXX - This doesn't feel "right" (just disabling irq 11). Also, for some + * reason the ethernet driver is having trouble receiving and decoding frames. + * Is there a timing or latency issue going on? This needs to be looked into + * ASAP. + */ static void ack_gapspci_irq(unsigned int irq) { *************** *** 175,179 **** { enable_gapspci_irq(irq); - return 0; } --- 170,173 ---- *************** *** 194,200 **** }; - #define GAPSPCI_IRQ 11 - /* We only support one IRQ */ static int __init map_gapspci_irq(struct pci_dev *dev, u8 slot, u8 pin) { --- 188,195 ---- }; /* We only support one IRQ */ + + static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) { return 0; } + static int __init map_gapspci_irq(struct pci_dev *dev, u8 slot, u8 pin) { *************** *** 216,243 **** ranges->mem_end -= bus->resource[1]->start; } ! #define GAPSPCI_REG_UNKN_14 (GAPSPCI_BASE_ADDR + 0x14) ! #define GAPSPCI_REG_STATUS (GAPSPCI_BASE_ADDR + 0x18) ! #define GAPSPCI_REG_UNKN_20 (GAPSPCI_BASE_ADDR + 0x20) ! #define GAPSPCI_REG_UNKN_24 (GAPSPCI_BASE_ADDR + 0x24) ! #define GAPSPCI_REG_DMASTART (GAPSPCI_BASE_ADDR + 0x28) ! #define GAPSPCI_REG_DMAEND (GAPSPCI_BASE_ADDR + 0x2c) ! #define GAPSPCI_REG_UNKN_34 (GAPSPCI_BASE_ADDR + 0x34) /* ! * Initialize the GAPS PCI bridge. GAPS initialization code adapted from ! * Dan Potter's BB1 code. */ void __init gaps_init_pci(void) { struct pci_dev *dev; u16 tmp = 10000; ! if (strncmp((const char*)GAPSPCI_BASE_ADDR, "GAPSPCI_BRIDGE_2", 16)) { return; } ! printk("Sega GAPS PCI bridge found at 0x%08x\n", GAPSPCI_BASE_ADDR); /* Bring the GAPS online */ --- 211,263 ---- ranges->mem_end -= bus->resource[1]->start; } + + static struct pci_bus *pci_root_bus; + + /* + * Do a quick setup of the single PCI device. + */ + static struct pci_dev __init *gapspci_setup_device(struct pci_bus *bus) + { + static struct pci_dev *dev, dev0; + u32 tmp; ! /* Here, all defaults are zero and we try to minimize I/O. */ ! memset(&dev0, 0, sizeof(dev0)); ! dev = &dev0; ! dev->bus = bus; ! tmp = readl(GAPSPCI_PCI_BASE + PCI_VENDOR_ID); ! dev->vendor = tmp & 0xffff; ! dev->device = (tmp >> 16) & 0xffff; ! dev->dma_mask = 0xffffffff; ! dev->irq = GAPSPCI_IRQ; ! sprintf(dev->slot_name, "00:00.0"); ! sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); ! pci_name_device(dev); ! ! /* Make the device visible */ ! list_add_tail(&dev->global_list, &pci_devices); ! list_add_tail(&dev->bus_list, &bus->devices); + return dev; + } + /* ! * Initialize the GAPS PCI bridge. Note that we manually setup the PCI root ! * bus and the lone device that occupies it. This is to avoid calling kernel ! * PCI helper functions such as pci_scan_bus() that recursively scan for more ! * PCI devices, buses, and bridges than actually exist. */ void __init gaps_init_pci(void) { + struct pci_bus *b; struct pci_dev *dev; u16 tmp = 10000; ! if (strncmp((const char*)GAPSPCI_REG_BASE, "GAPSPCI_BRIDGE_2", 16)) { return; } ! printk("Sega GAPS PCI bridge found at 0x%08x\n", GAPSPCI_REG_BASE); /* Bring the GAPS online */ *************** *** 254,318 **** writel(GAPSPCI_DMA_BASE, GAPSPCI_REG_DMASTART); writel(GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE, GAPSPCI_REG_DMAEND); ! writel(1, GAPSPCI_REG_UNKN_14); writel(1, GAPSPCI_REG_UNKN_34); ! writew(0xf900, GAPSPCI_PCI_ADDR + PCI_STATUS); ! writel(0, GAPSPCI_PCI_ADDR + PCI_ROM_ADDRESS); ! writeb(0, GAPSPCI_PCI_ADDR + PCI_INTERRUPT_LINE); ! writeb(0xf0, GAPSPCI_PCI_ADDR + PCI_LATENCY_TIMER); ! tmp = readw(0xa1000004); ! writew(0x0006, GAPSPCI_PCI_ADDR + PCI_COMMAND); ! writel(0x01000000, GAPSPCI_PCI_ADDR + PCI_BASE_ADDRESS_1); ! tmp = readb(GAPSPCI_PCI_ADDR + 0x50); /* ??? - undocumented */ ! irq_desc[GAPSPCI_IRQ].handler = &gapspci_int; ! /* Initialize the bus and scan for devices */ ! pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); ! /* Manually assign resources */ ! /* PIO and MMIO mean the same thing here */ ! dev = pci_find_slot(0, PCI_DEVFN(0, 0)); ! dev->resource[0].start = P2SEGADDR(GAPSPCI_DEVICE_ADDR); ! dev->resource[0].end = P2SEGADDR(GAPSPCI_DEVICE_ADDR + 0xff); dev->resource[0].flags = IORESOURCE_IO; ! dev->resource[1].start = P2SEGADDR(GAPSPCI_DEVICE_ADDR); ! dev->resource[1].end = P2SEGADDR(GAPSPCI_DEVICE_ADDR + 0xff); dev->resource[1].flags = IORESOURCE_MEM; pci_fixup_irqs(no_swizzle, map_gapspci_irq); - } int pcibios_enable_device(struct pci_dev *dev) { ! u16 cmd, old_cmd; ! int idx; ! struct resource *r; ! pci_read_config_word(dev, PCI_COMMAND, &cmd); ! old_cmd = cmd; ! for (idx = 0; idx < 6; idx++) { ! r = dev->resource + idx; ! if (!r->start && r->end) { ! printk(KERN_ERR ! "PCI: Device %s not available because" ! " of resource collisions\n", ! dev->slot_name); ! return -EINVAL; ! } ! if (r->flags & IORESOURCE_IO) ! cmd |= PCI_COMMAND_IO; ! if (r->flags & IORESOURCE_MEM) ! cmd |= PCI_COMMAND_MEMORY; ! } ! if (cmd != old_cmd) { ! printk("PCI: enabling device %s (%04x -> %04x)\n", ! dev->slot_name, old_cmd, cmd); ! pci_write_config_word(dev, PCI_COMMAND, cmd); ! } ! return 0; } --- 274,312 ---- writel(GAPSPCI_DMA_BASE, GAPSPCI_REG_DMASTART); writel(GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE, GAPSPCI_REG_DMAEND); ! writel(0, GAPSPCI_REG_IMR); writel(1, GAPSPCI_REG_UNKN_34); ! /* Setup the PCI bus within the kernel */ ! b = pci_alloc_primary_bus(0); ! b->ops = &pci_config_ops; ! pci_root_bus = b; ! dev = gapspci_setup_device(b); ! /* This is the only other initialization needed for PCI :) */ ! writel(0x01000000, GAPSPCI_PCI_BASE + PCI_BASE_ADDRESS_1); ! irq_desc[GAPSPCI_IRQ].handler = &gapspci_int; ! /* I/O ranges - these are the same for both PIO and MMIO modes. */ ! dev->resource[0].start = P2SEGADDR(GAPSPCI_DEVICE_BASE); ! dev->resource[0].end = P2SEGADDR(GAPSPCI_DEVICE_BASE + 0xff); dev->resource[0].flags = IORESOURCE_IO; ! dev->resource[1].start = P2SEGADDR(GAPSPCI_DEVICE_BASE); ! dev->resource[1].end = P2SEGADDR(GAPSPCI_DEVICE_BASE + 0xff); dev->resource[1].flags = IORESOURCE_MEM; pci_fixup_irqs(no_swizzle, map_gapspci_irq); } int pcibios_enable_device(struct pci_dev *dev) { + u16 cmd; ! printk("PCI: enabling device %s\n", dev->slot_name); pci_read_config_word(dev, PCI_COMMAND, &cmd); ! pci_write_config_word(dev, PCI_COMMAND, (cmd | PCI_COMMAND_MASTER | ! PCI_COMMAND_IO)); + return 0; } *************** *** 329,346 **** struct resource *res, int resource) { - - unsigned long where, size; - u32 reg; - - printk("PCI: Assigning %3s %08lx to %s\n", - res->flags & IORESOURCE_IO ? "IO" : "MEM", - res->start, dev->name); - - where = PCI_BASE_ADDRESS_0 + resource * 4; - size = res->end - res->start; - - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32) (res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); } --- 323,326 ---- *************** *** 349,382 **** { printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); ! /*pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);*/ } /* ! * XXX - GAPS does have 32K of DMA memory, its allocation needs to be ! * implemented here... */ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t * dma_handle) { ! void *ret; ! int gfp = GFP_ATOMIC; ! ! ret = (void *) __get_free_pages(gfp, get_order(size)); ! ! if (ret != NULL) { ! /* Is it neccessary to do the memset? */ ! memset(ret, 0, size); ! *dma_handle = virt_to_bus(ret); } /* We must flush the cache before we pass it on to the device */ flush_cache_all(); ! return P2SEGADDR(ret); } void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { ! unsigned long p1addr=P1SEGADDR((unsigned long)vaddr); ! ! free_pages(p1addr, get_order(size)); } --- 329,373 ---- { printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); ! pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } + + /* + * Another benefit of being lonely is that you can take all of the 32K DMA + * provided by GAPS in one fell swoop - these are only called from the RealTek + * driver's open() and close() routines, so they only need to go up and down + * (currently). + * + * XXX - Will this ever need to change? + */ + + static u32 dma_ptr = GAPSPCI_DMA_BASE; + /* ! * Allocate a single range of PCI DMA and return a pointer to its address in ! * both bus space and CPU space. */ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t * dma_handle) { ! if ((dma_ptr + size) < GAPSPCI_DMA_END) { ! *dma_handle = dma_ptr; ! dma_ptr += size; ! } else { ! dma_handle = NULL; ! return NULL; } + /* We must flush the cache before we pass it on to the device */ flush_cache_all(); ! return (void *) P2SEGADDR(*dma_handle); } + /* + * Free the memory allocated by pci_alloc_consistent(). + */ void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { ! dma_ptr -= size; } |