#config PCI_EPIC
# bool "EPIC/SAGA PCI support"
# depends on PCI
+# default y
+# help
+# Say Y here for V-class PCI, DMA/IOMMU, IRQ subsystem support.
config SUPERIO
bool "SuperIO (SuckyIO) support"
CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64);
#endif
} else {
- panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n",
- __FUNCTION__, pages_needed);
+ panic("%s: %s() Too many pages to map. pages_needed: %ld\n",
+ __FILE__, __FUNCTION__, pages_needed);
}
- panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n",
+ panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__,
__FUNCTION__);
resource_found:
CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64);
#endif
} else {
- panic(__FILE__ ":%s() Too many pages to unmap.\n",
+ panic("%s:%s() Too many pages to unmap.\n", __FILE__,
__FUNCTION__);
}
}
ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->pdir_size));
if(NULL == ioc->pdir_base) {
- panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
+ panic("%s:%s() could not allocate I/O Page Table\n", __FILE__,
+ __FUNCTION__);
}
memset(ioc->pdir_base, 0, ioc->pdir_size);
ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->res_size));
if(NULL == ioc->res_map) {
- panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__);
+ panic("%s:%s() could not allocate resource map\n", __FILE__,
+ __FUNCTION__);
}
memset(ioc->res_map, 0, ioc->res_size);
if (!ioc) {
parent = &iomem_resource;
- } else if ((ioc->mmio_region->start <= dev->hpa) &&
- (dev->hpa < ioc->mmio_region->end)) {
+ } else if ((ioc->mmio_region->start <= res->start) &&
+ (res->end <= ioc->mmio_region->end)) {
parent = ioc->mmio_region;
- } else if (((ioc->mmio_region + 1)->start <= dev->hpa) &&
- (dev->hpa < (ioc->mmio_region + 1)->end)) {
+ } else if (((ioc->mmio_region + 1)->start <= res->start) &&
+ (res->end <= (ioc->mmio_region + 1)->end)) {
parent = ioc->mmio_region + 1;
} else {
return -EBUSY;
static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *val)
{
- struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->dev));
+ struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
unsigned long base_addr = d->hba.base_addr;
static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val)
{
- struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->dev));
+ struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3);
unsigned long base_addr = d->hba.base_addr;
dino_card_setup(struct pci_bus *bus, unsigned long base_addr)
{
int i;
- struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->dev));
+ struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
struct resource *res;
char name[128];
int size;
res = &dino_dev->hba.lmmio_space;
res->flags = IORESOURCE_MEM;
- size = snprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->dev->bus_id);
+ size = snprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->bridge->bus_id);
res->name = kmalloc(size+1, GFP_KERNEL);
if(res->name)
strcpy((char *)res->name, name);
struct list_head *ln, *tmp_ln;
printk(KERN_ERR "Dino: cannot attach bus %s\n",
- bus->dev->bus_id);
+ bus->bridge->bus_id);
/* kill the bus, we can't do anything with it */
list_for_each_safe(ln, tmp_ln, &bus->devices) {
struct pci_dev *dev = pci_dev_b(ln);
{
struct list_head *ln;
struct pci_dev *dev;
- struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->dev));
+ struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
DBG(KERN_WARNING "%s(0x%p) bus %d sysdata 0x%p\n",
- __FUNCTION__, bus, bus->secondary, bus->dev->platform_data);
+ __FUNCTION__, bus, bus->secondary, bus->bridge->platform_data);
/* Firmware doesn't set up card-mode dino, so we have to */
if (is_card_dino(&dino_dev->hba.dev->id)) {
} else if(bus->parent == NULL) {
/* must have a dino above it, reparent the resources
* into the dino window */
+ int i;
+ struct resource *res = &dino_dev->hba.lmmio_space;
+
bus->resource[0] = &(dino_dev->hba.io_space);
- bus->resource[1] = &(dino_dev->hba.lmmio_space);
+ for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
+ if(res[i].flags == 0)
+ break;
+ bus->resource[i+1] = &res[i];
+ }
+
} else if(bus->self) {
int i;
pci_read_bridge_bases(bus);
- for(i = 0; i < PCI_NUM_RESOURCES; i++) {
+ for(i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
if((bus->self->resource[i].flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
continue;
* care about an expansion rom on parisc, since it
* usually contains (x86) bios code) */
dev->resource[PCI_ROM_RESOURCE].flags = 0;
- dev->resource[PCI_ROM_RESOURCE].start = 0;
- dev->resource[PCI_ROM_RESOURCE].end = 0;
if(dev->irq == 255) {
+#define DINO_FIX_UNASSIGNED_INTERRUPTS
#ifdef DINO_FIX_UNASSIGNED_INTERRUPTS
/* This code tries to assign an unassigned
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 1, dev->irq);
- dev->irq += dino_dev->dino_region->data.irqbase
+ dev->irq += dino_dev->dino_region->data.irqbase;
printk(KERN_WARNING "Device %s has undefined IRQ, setting to %d\n", dev->slot_name, irq_pin);
#else
dev->irq = 65535;
static int __init
dino_bridge_init(struct dino_device *dino_dev, const char *name)
{
- unsigned long io_addr, bpos;
- int result;
- struct resource *res;
+ unsigned long io_addr;
+ int result, i, count=0;
+ struct resource *res, *prevres = NULL;
/*
* Decoding IO_ADDR_EN only works for Built-in Dino
* since PDC has already initialized this.
return -ENODEV;
}
- for (bpos = 0; (io_addr & (1 << bpos)) == 0; bpos++)
- ;
-
res = &dino_dev->hba.lmmio_space;
- res->flags = IORESOURCE_MEM;
+ for (i = 0; i < 32; i++) {
+ unsigned long start, end;
+
+ if((io_addr & (1 << i)) == 0)
+ continue;
- res->start = (unsigned long)(signed int)(0xf0000000 | (bpos << 23));
- res->end = res->start + 8 * 1024 * 1024 - 1;
+ start = (unsigned long)(signed int)(0xf0000000 | (i << 23));
+ end = start + 8 * 1024 * 1024 - 1;
- result = ccio_request_resource(dino_dev->hba.dev, res);
- if (result < 0) {
- printk(KERN_ERR "%s: failed to claim PCI Bus address space!\n", name);
- return result;
+ DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count,
+ start, end);
+
+ if(prevres && prevres->end + 1 == start) {
+ prevres->end = end;
+ } else {
+ if(count >= DINO_MAX_LMMIO_RESOURCES) {
+ printk(KERN_ERR "%s is out of resource windows for range %d (0x%lx-0x%lx)\n", name, count, start, end);
+ break;
+ }
+ prevres = res;
+ res->start = start;
+ res->end = end;
+ res->flags = IORESOURCE_MEM;
+ res->name = kmalloc(64, GFP_KERNEL);
+ if(res->name)
+ snprintf((char *)res->name, 64, "%s LMMIO %d",
+ name, count);
+ res++;
+ count++;
+ }
}
+ res = &dino_dev->hba.lmmio_space;
+
+ for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
+ if(res[i].flags == 0)
+ break;
+
+ result = ccio_request_resource(dino_dev->hba.dev, &res[i]);
+ if (result < 0) {
+ printk(KERN_ERR "%s: failed to claim PCI Bus address space %d (0x%lx-0x%lx)!\n", name, i, res[i].start, res[i].end);
+ return result;
+ }
+ }
return 0;
}
res = &dino_dev->hba.io_space;
if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) {
res->name = "Dino I/O Port";
- dino_dev->hba.lmmio_space.name = "Dino LMMIO";
} else {
res->name = "Cujo I/O Port";
- dino_dev->hba.lmmio_space.name = "Cujo LMMIO";
}
res->start = HBA_PORT_BASE(dino_dev->hba.hba_num);
res->end = res->start + (HBA_PORT_SPACE_SIZE - 1);
+/*
+ * EISA "eeprom" support routines
+ *
+ * Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
{
struct vector_info *vi = (struct vector_info *)dev_id;
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
- int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline;
+ int irq_num = vi->iosapic->isi_region->data.irqbase + vi->irqline;
DBG("iosapic_interrupt(): irq %d line %d eoi %p\n",
- irq, vi->vi_irqline, vi->vi_eoi_addr);
+ irq, vi->irqline, vi->eoi_addr);
/* FIXME: Need to mask/unmask? processor IRQ is already masked... */
- do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs);
+ do_irq(&vi->iosapic->isi_region->action[vi->irqline], irq_num, regs);
/*
** PCI only supports level triggered in order to share IRQ lines.
** I/O SAPIC must always issue EOI.
*/
- IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data);
+ IOSAPIC_EOI(vi->eoi_addr, vi->eoi_data);
return IRQ_HANDLED;
}
struct vector_info *vi;
int isi_line; /* line used by device */
int tmp;
- int return_irq;
-#ifdef CONFIG_SUPERIO
- int superio_irq = -1;
-#endif
if (NULL == isi) {
printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
}
#ifdef CONFIG_SUPERIO
+ /*
+ * HACK ALERT! (non-compliant PCI device support)
+ *
+ * All SuckyIO interrupts are routed through the PIC's on function 1.
+ * But SuckyIO OHCI USB controller gets an IRT entry anyway because
+ * it advertises INT D for INT_PIN. Use that IRT entry to get the
+ * SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*).
+ */
if (is_superio_device(pcidev)) {
- superio_irq = superio_fixup_irq(pcidev);
- if (superio_irq == -1)
- return(-1);
-
- if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) {
-
- /*
- * SuperIO USB controller has an irt entry.
- * Only let the USB controller hookup the rest
- * of the interrupt routing when it comes through.
- * Note that interrupts for all three functions
- * actually come through the PIC's on function 1!
- */
-
- pcidev->irq = superio_irq;
- return superio_irq;
- }
+ /* We must call superio_fixup_irq() to register the pdev */
+ pcidev->irq = superio_fixup_irq(pcidev);
+
+ /* Don't return if need to program the IOSAPIC's IRT... */
+ if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
+ return pcidev->irq;
}
#endif /* CONFIG_SUPERIO */
/* lookup IRT entry for isi/slot/pin set */
irte = iosapic_xlate_pin(isi, pcidev);
if (NULL == irte) {
+ printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
+ pci_name(pcidev));
return(-1);
}
DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",
irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr);
isi_line = irte->dest_iosapic_intin;
+ pcidev->irq = isi->isi_region->data.irqbase + isi_line;
/* get vector info for this input line */
ASSERT(NULL != isi->isi_vector);
vi = &(isi->isi_vector[isi_line]);
DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi);
- vi->vi_irte = irte;
+
+ /* If this IRQ line has already been setup, skip it */
+ if (vi->irte)
+ return pcidev->irq;
+
+ vi->irte = irte;
/* Allocate processor IRQ */
- vi->vi_txn_irq = txn_alloc_irq();
+ vi->txn_irq = txn_alloc_irq();
/* XXX/FIXME The txn_alloc_irq() code and related code should be moved
** to enable_irq(). That way we only allocate processor IRQ bits
** Right now we assign an IRQ to every PCI device present regardless
** of whether it's used or not.
*/
- if (vi->vi_txn_irq < 0)
+ if (vi->txn_irq < 0)
panic("I/O sapic: couldn't get TXN IRQ\n");
/* enable_irq() will use txn_* to program IRdT */
- vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq);
- vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);
- ASSERT(vi->vi_txn_data < 256); /* matches 8 above */
+ vi->txn_addr = txn_alloc_addr(vi->txn_irq);
+ vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
+ ASSERT(vi->txn_data < 256); /* matches 8 above */
- tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0,
- vi->vi_name, vi);
+ tmp = request_irq(vi->txn_irq, iosapic_interrupt, 0,
+ vi->name, vi);
ASSERT(tmp == 0);
- vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
- vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);
+ vi->eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
+ vi->eoi_data = cpu_to_le32(vi->irqline);
ASSERT(NULL != isi->isi_region);
- /* pcidev->irq still needs to be virtualized. */
-
- return_irq = isi->isi_region->data.irqbase + isi_line;
-
-#ifdef CONFIG_SUPERIO
- if (superio_irq != -1) {
- superio_inform_irq(return_irq);
- return_irq = superio_irq;
- }
-#endif
- pcidev->irq = return_irq;
DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
- PCI_SLOT(pcidev->devfn),
- PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq);
+ PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->irq),
+ pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
- return return_irq;
+ return pcidev->irq;
}
static void
iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
{
- struct iosapic_info *isp = vi->vi_ios;
- u8 idx = vi->vi_irqline;
+ struct iosapic_info *isp = vi->iosapic;
+ u8 idx = vi->irqline;
/* point the window register to the lower word */
WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT);
static void
iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1)
{
- struct iosapic_info *isp = vi->vi_ios;
+ struct iosapic_info *isp = vi->iosapic;
ASSERT(NULL != isp);
ASSERT(0 != isp->isi_hpa);
DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n",
- vi->vi_irqline,
+ vi->irqline,
isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW,
dp0, dp1);
/* point the window register to the lower word */
- WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
+ WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* Read the window register to flush the writes down to HW */
dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* point the window register to the higher word */
- WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
+ WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->irqline), isp->isi_hpa+IOSAPIC_REG_SELECT);
WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW);
/* Read the window register to flush the writes down to HW */
iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
{
u32 mode = 0;
- struct irt_entry *p = vi->vi_irte;
- ASSERT(NULL != vi->vi_irte);
+ struct irt_entry *p = vi->irte;
+ ASSERT(NULL != vi->irte);
if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
mode |= IOSAPIC_IRDT_PO_LOW;
** PA doesn't support EXTINT or LPRIO bits.
*/
- ASSERT(vi->vi_txn_data);
- *dp0 = mode | (u32) vi->vi_txn_data;
+ ASSERT(vi->txn_data);
+ *dp0 = mode | (u32) vi->txn_data;
/*
** Extracting id_eid isn't a real clean way of getting it.
if (is_pdc_pat()) {
/*
** PAT PDC just hands it to us "right".
- ** vi_txn_addr comes from cpu_data[x].txn_addr.
+ ** txn_addr comes from cpu_data[x].txn_addr.
*/
- *dp1 = (u32) (vi->vi_txn_addr);
+ *dp1 = (u32) (vi->txn_addr);
} else {
/*
** eg if base_addr == 0xfffa0000),
** eid 0x0ff00000 -> 0x00ff0000
** id 0x000ff000 -> 0xff000000
*/
- *dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) |
- (((u32)vi->vi_txn_addr & 0x000ff000) << 12);
+ *dp1 = (((u32)vi->txn_addr & 0x0ff00000) >> 4) |
+ (((u32)vi->txn_addr & 0x000ff000) << 12);
}
DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1);
}
IOSAPIC_UNLOCK(&iosapic_lock);
/* disable ISR for parent */
- disable_irq(vi->vi_txn_irq);
+ disable_irq(vi->txn_irq);
}
u32 d0, d1;
ASSERT(NULL != vi);
- ASSERT(NULL != vi->vi_irte);
+ ASSERT(NULL != vi->irte);
/* data is initialized by fixup_irq */
- ASSERT(0 < vi->vi_txn_irq);
- ASSERT(0UL != vi->vi_txn_data);
+ ASSERT(0 < vi->txn_irq);
+ ASSERT(0UL != vi->txn_data);
iosapic_set_irt_data(vi, &d0, &d1);
iosapic_wr_irt_entry(vi, d0, d1);
#ifdef DEBUG_IOSAPIC_IRT
{
- u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
- printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
- while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
+ u32 *t = (u32 *) ((ulong) vi->eoi_addr & ~0xffUL);
+ printk("iosapic_enable_irq(): regs %p", vi->eoi_addr);
+ while (t < vi->eoi_addr) printk(" %x", READ_U32(t++));
printk("\n");
}
printk("iosapic_enable_irq(): sel ");
{
- struct iosapic_info *isp = vi->vi_ios;
+ struct iosapic_info *isp = vi->iosapic;
for (d0=0x10; d0<0x1e; d0++) {
/* point the window register to the lower word */
** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is
** asserted.
*/
- IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data);
+ IOSAPIC_EOI(vi->eoi_addr, vi->eoi_data);
}
** Initialize vector array
*/
for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
- vip->vi_irqline = (unsigned char) cnt;
- vip->vi_ios = isi;
- sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt);
+ vip->irqline = (unsigned char) cnt;
+ vip->iosapic = isi;
+ sprintf(vip->name, "%s-L%d", isi->isi_name, cnt);
}
isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
{
ASSERT(NULL != vi);
- printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->vi_irqline, vi);
- printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status);
- printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq);
- printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr);
- printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data);
- printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr);
- printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data);
+ printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
+ printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status);
+ printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq);
+ printk(KERN_DEBUG "\t\ttxn_addr: %lx\n", vi->txn_addr);
+ printk(KERN_DEBUG "\t\ttxn_data: %lx\n", vi->txn_data);
+ printk(KERN_DEBUG "\t\teoi_addr: %p\n", vi->eoi_addr);
+ printk(KERN_DEBUG "\t\teoi_data: %x\n", vi->eoi_data);
}
+/*
+ * Private structs/constants for PARISC IOSAPIC support
+ *
+ * Copyright (C) 2000 Hewlett Packard (Grant Grundler)
+ * Copyright (C) 2000,2003 Grant Grundler (grundler at parisc-linux.org)
+ * Copyright (C) 2002 Matthew Wilcox (willy at parisc-linux.org)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
/*
** This file is private to iosapic driver.
** If stuff needs to be used by another driver, move it to a common file.
#endif
struct vector_info {
- struct iosapic_info *vi_ios; /* I/O SAPIC this vector is on */
- struct irt_entry *vi_irte; /* IRT entry */
- u32 *vi_eoi_addr; /* precalculate EOI reg address */
- u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */
- int vi_txn_irq; /* virtual IRQ number for processor */
- ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */
- ulong vi_txn_data; /* IA64: vector PA: EIR bit */
- u8 vi_status; /* status/flags */
- u8 vi_irqline; /* INTINn(IRQ) */
- char vi_name[32]; /* user visible identity */
+ struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */
+ struct irt_entry *irte; /* IRT entry */
+ u32 *eoi_addr; /* precalculate EOI reg address */
+ u32 eoi_data; /* IA64: ? PA: swapped txn_data */
+ int txn_irq; /* virtual IRQ number for processor */
+ ulong txn_addr; /* IA64: id_eid PA: partial HPA */
+ ulong txn_data; /* IA64: vector PA: EIR bit */
+ u8 status; /* status/flags */
+ u8 irqline; /* INTINn(IRQ) */
+ char name[32]; /* user visible identity */
};
void *iosapic_obj;
#ifdef __LP64__
- unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */
- unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */
unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */
#endif
static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data)
{
- struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->dev));
+ struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 tok = LBA_CFG_TOK(local_bus, devfn);
with risk we will miss PCI bus errors. */
*data = lba_rd_cfg(d, tok, pos, size);
DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data);
- return(*data == ~0UL);
+ return(*data == ~0U);
}
if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d)))
static int lba_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data)
{
- struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->dev));
+ struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge));
u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary;
u32 tok = LBA_CFG_TOK(local_bus,devfn);
{
struct list_head *ln;
#ifdef FBB_SUPPORT
- u16 fbb_enable = PCI_STATUS_FAST_BACK;
u16 status;
#endif
- struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->dev));
+ struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
- bus, bus->secondary, bus->dev->platform_data);
+ bus, bus->secondary, bus->bridge->platform_data);
/*
** Properly Setup MMIO resources for this bus.
** pci_alloc_primary_bus() mangles this.
*/
- if (NULL == bus->self) {
+ if (bus->self) {
+ /* PCI-PCI Bridge */
+ pci_read_bridge_bases(bus);
+ } else {
+ /* Host-PCI Bridge */
int err;
DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
BUG();
lba_dump_res(&ioport_resource, 2);
}
+
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) {
BUG();
lba_dump_res(&iomem_resource, 2);
}
- bus->resource[0] = &(ldev->hba.io_space);
- bus->resource[1] = &(ldev->hba.lmmio_space);
- } else {
- /* KLUGE ALERT!
- ** PCI-PCI Bridge resource munging.
- ** This hack should go away in the near future.
- ** It's based on the Alpha port.
- */
- int i;
- u16 cmd;
-
- for (i = 0; i < 4; i++) {
- bus->resource[i] =
- &bus->self->resource[PCI_BRIDGE_RESOURCES+i];
- bus->resource[i]->name = bus->name;
+#ifdef __LP64__
+ if (ldev->hba.gmmio_space.flags) {
+ err = request_resource(&iomem_resource, &(ldev->hba.gmmio_space));
+ if (err < 0) {
+ BUG();
+ lba_dump_res(&iomem_resource, 2);
+ }
+ bus->resource[2] = &(ldev->hba.gmmio_space);
}
-#if 0
- bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
-#else
- bus->resource[0]->flags |= IORESOURCE_IO;
#endif
- bus->resource[1]->flags |= IORESOURCE_MEM;
- bus->resource[2]->flags = 0; /* Don't support prefetchable */
- bus->resource[3]->flags = 0; /* not used */
-
- /*
- ** If the PPB is enabled (ie already configured) then
- ** just read those values.
- */
- (void) pci_read_config_word(bus->self, PCI_COMMAND, &cmd);
- if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
- pci_read_bridge_bases(bus);
- } else {
- /* Not configured.
- ** For now, propagate HBA limits to the bus;
- ** PCI will adjust them later.
- */
- bus->resource[0]->end = ldev->hba.io_space.end;
- bus->resource[1]->end = ldev->hba.lmmio_space.end;
- }
- /* Turn off downstream PF memory address range by default */
- bus->resource[2]->start = 1024*1024;
- bus->resource[2]->end = bus->resource[2]->start - 1;
+ /* advertize Host bridge resources to PCI bus */
+ bus->resource[0] = &(ldev->hba.io_space);
+ bus->resource[1] = &(ldev->hba.lmmio_space);
}
-
list_for_each(ln, &bus->devices) {
int i;
struct pci_dev *dev = pci_dev_b(ln);
DBG("lba_fixup_bus() %s\n", pci_name(dev));
/* Virtualize Device/Bridge Resources. */
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
struct resource *res = &dev->resource[i];
/* If resource not allocated - skip it */
** No one on the bus can be allowed to use them.
*/
(void) pci_read_config_word(dev, PCI_STATUS, &status);
- fbb_enable &= status;
+ bus->bridge_ctl &= ~(status & PCI_STATUS_FAST_BACK);
#endif
#ifdef __LP64__
lba_dev->hba.bus_num.start = p->start;
lba_dev->hba.bus_num.end = p->end;
break;
+
case PAT_LMMIO:
/* used to fix up pre-initialized MEM BARs */
lba_dev->hba.lmmio_space_offset = p->start - io->start;
r->flags = IORESOURCE_MEM;
r->parent = r->sibling = r->child = NULL;
break;
+
case PAT_GMMIO:
- printk(KERN_WARNING MODULE_NAME
- " range[%d] : ignoring GMMIO (0x%lx)\n",
- i, p->start);
- lba_dev->gmmio_base = p->start;
+ /* MMIO space > 4GB phys addr; for 64-bit BAR */
+ r = &(lba_dev->hba.gmmio_space);
+ r->name = "LBA GMMIO";
+ r->start = p->start;
+ r->end = p->end;
+ r->flags = IORESOURCE_MEM;
+ r->parent = r->sibling = r->child = NULL;
break;
+
case PAT_NPIOP:
printk(KERN_WARNING MODULE_NAME
" range[%d] : ignoring NPIOP (0x%lx)\n",
i, p->start);
break;
+
case PAT_PIOP:
/*
** Postable I/O port space is per PCI host adapter.
+ ** base of 64MB PIOP region
*/
-
- /* save base of 64MB PIOP region */
lba_dev->iop_base = p->start;
r = &(lba_dev->hba.io_space);
r->flags = IORESOURCE_IO;
r->parent = r->sibling = r->child = NULL;
break;
+
default:
printk(KERN_WARNING MODULE_NAME
" range[%d] : unknown pat range type (0x%lx)\n",
#endif /* DEBUG_LBA_PAT */
#ifdef __LP64__
-#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
+/*
+ * FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
+ * Only N-Class and up can really make use of Get slot status.
+ * maybe L-class too but I've never played with it there.
+ */
#endif
/* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */
*
* (c) Copyright 2000 Red Hat Software
* (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
- * (c) Copyright 2001-2003 Helge Deller <deller@gmx.de>
+ * (c) Copyright 2001-2004 Helge Deller <deller@gmx.de>
* (c) Copyright 2001 Randolph Chung <tausq@debian.org>
*
* This program is free software; you can redistribute it and/or modify
static int led_diskio = 1;
static int led_lanrxtx = 1;
static char lcd_text[32];
+static char lcd_text_default[] = "Linux " UTS_RELEASE;
#if 0
#define DPRINTK(x) printk x
break;
case LED_HASLCD:
+ while (*cur && cur[strlen(cur)-1] == '\n')
+ cur[strlen(cur)-1] = 0;
if (*cur == 0)
- {
- /* reset to default */
- lcd_print("Linux " UTS_RELEASE);
- }
- else
- {
- /* chop off trailing \n.. if the user gives multiple
- * \n then it's all their fault.. */
- if (*cur && cur[strlen(cur)-1] == '\n')
- cur[strlen(cur)-1] = 0;
- lcd_print(cur);
- }
+ cur = lcd_text_default;
+ lcd_print(cur);
break;
default:
return 0;
#define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
-#if HZ==100
- #define NORMALIZED_COUNT(count) (count)
-#else
- #define NORMALIZED_COUNT(count) (count/(HZ/100))
-#endif
+#define NORMALIZED_COUNT(count) (count/(HZ/100))
static void led_tasklet_func(unsigned long unused)
{
printk(KERN_INFO "LCD display at %p,%p registered\n",
LCD_CMD_REG , LCD_DATA_REG);
led_func_ptr = led_LCD_driver;
- lcd_print( "Linux " UTS_RELEASE );
+ lcd_print( lcd_text_default );
led_type = LED_HASLCD;
break;
#define MODULE_NAME "SBA"
+#ifdef CONFIG_PROC_FS
+/* depends on proc fs support. But costs CPU performance */
+#undef SBA_COLLECT_STATS
+#endif
+
/*
** The number of debug flags is a clue - this code is fragile.
** Don't even think about messing with it unless you have
} saved[DELAYED_RESOURCE_CNT];
#endif
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
#define SBA_SEARCH_SAMPLE 0x100
unsigned long avg_search[SBA_SEARCH_SAMPLE];
unsigned long avg_idx; /* current index into avg_search */
sba_alloc_range(struct ioc *ioc, size_t size)
{
unsigned int pages_needed = size >> IOVP_SHIFT;
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
unsigned long cr_start = mfctl(16);
#endif
unsigned long pide;
if (pide >= (ioc->res_size << 3)) {
pide = sba_search_bitmap(ioc, pages_needed);
if (pide >= (ioc->res_size << 3))
- panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
+ panic("%s: I/O MMU @ %lx is out of mapping resources\n",
+ __FILE__, ioc->ioc_hpa);
}
#ifdef ASSERT_PDIR_SANITY
(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
ioc->res_bitshift );
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
{
unsigned long cr_end = mfctl(16);
unsigned long tmp = cr_end - cr_start;
__FUNCTION__, (uint) iova, size,
bits_not_wanted, m, pide, res_ptr, *res_ptr);
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->used_pages -= bits_not_wanted;
#endif
sba_check_pdir(ioc,"Check before sba_map_single()");
#endif
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->msingle_calls++;
ioc->msingle_pages += size >> IOVP_SHIFT;
#endif
spin_lock_irqsave(&ioc->res_lock, flags);
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->usingle_calls++;
ioc->usingle_pages += size >> IOVP_SHIFT;
#endif
printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
nents,
(unsigned long) sg_dma_address(startsg), cnt,
- sg_virt_address(startsg), startsg->length
+ sg_virt_addr(startsg), startsg->length
);
#else
DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
cnt += dma_offset;
dma_offset=0; /* only want offset on first chunk */
cnt = ROUNDUP(cnt, IOVP_SIZE);
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->msg_pages += cnt >> IOVP_SHIFT;
#endif
do {
}
#endif
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->msg_calls++;
#endif
ioc = GET_IOC(dev);
ASSERT(ioc);
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->usg_calls++;
#endif
while (sg_dma_len(sglist) && nents--) {
sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
-#ifdef CONFIG_PROC_FS
+#ifdef SBA_COLLECT_STATS
ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
ioc->usingle_calls--; /* kluge since call is unmap_sg() */
#endif
int num_ioc;
u64 ioc_ctl;
+ if (!is_pdc_pat()) {
+ /* Shutdown the USB controller on Astro-based workstations.
+ ** Once we reprogram the IOMMU, the next DMA performed by
+ ** USB will HPMC the box.
+ */
+ pdc_io_reset_devices();
+
+ /*
+ ** XXX May need something more sophisticated to deal
+ ** with DMA from LAN. Maybe use page zero boot device
+ ** as a handle to talk to PDC about which device to
+ ** shutdown. This also needs to work for is_pdc_pat().
+ */
+ }
+
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
if (NULL == sba_dev->ioc[i].res_map)
{
- panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ );
+ panic("%s:%s() could not allocate resource map\n",
+ __FILE__, __FUNCTION__ );
}
memset(sba_dev->ioc[i].res_map, 0, res_size);
struct sba_device *sba_dev = sba_list;
struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
+#ifdef SBA_COLLECT_STATS
unsigned long i = 0, avg = 0, min, max;
+#endif
sprintf(buf, "%s rev %d.%d\n",
sba_dev->name,
(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
total_pages);
+ sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
+ buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
+
+#ifdef SBA_COLLECT_STATS
sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf,
total_pages - ioc->used_pages, ioc->used_pages,
(int) (ioc->used_pages * 100 / total_pages));
-
- sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
- buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
min = max = ioc->avg_search[0];
for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
buf, ioc->usg_calls, ioc->usg_pages,
(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+#endif
return strlen(buf);
}
* (C) Copyright 2000 Linuxcare Canada, Inc.
* (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
* (C) Copyright 2000 Alex deVries <alex@linuxcare.com>
- * (C) Copyright 2001 John Marvin <jsm@fc.hp.com>
+ * (C) Copyright 2001 John Marvin <jsm fc hp com>
+ * (C) Copyright 2003 Grant Grundler <grundler parisc-linux org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
#include <asm/irq.h>
#include <asm/superio.h>
-static struct superio_device sio_dev = {
- .iosapic_irq = -1
-};
-
+static struct superio_device sio_dev;
-#undef DEBUG_INIT
-void
-superio_inform_irq(int irq)
-{
- if (sio_dev.iosapic_irq != -1) {
- printk(KERN_ERR "SuperIO: superio_inform_irq called twice! (more than one SuperIO?)\n");
- BUG();
- return;
- }
+#undef DEBUG_SUPERIO_INIT
- sio_dev.iosapic_irq = irq;
-}
+#ifdef DEBUG_SUPERIO_INIT
+#define DBG_INIT(x...) printk(x)
+#else
+#define DBG_INIT(x...)
+#endif
static irqreturn_t
superio_interrupt(int irq, void *devp, struct pt_regs *regs)
}
/* Call the appropriate device's interrupt */
-
do_irq(&sio->irq_region->action[local_irq],
sio->irq_region->data.irqbase + local_irq,
regs);
{
struct pci_dev *pdev = sio->lio_pdev;
u16 word;
- u8 i;
- if (!pdev || sio->iosapic_irq == -1) {
- printk(KERN_ERR "All SuperIO functions not found!\n");
- BUG();
+ if (sio->suckyio_irq_enabled)
return;
- }
+
+ if (!pdev) BUG();
+ if (!sio->usb_pdev) BUG();
+
+ /* use the IRQ iosapic found for USB INT D... */
+ pdev->irq = sio->usb_pdev->irq;
+
+ /* ...then properly fixup the USB to point at suckyio PIC */
+ sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);
printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
- pci_name(pdev),sio->iosapic_irq);
+ pci_name(pdev),pdev->irq);
/* Find our I/O devices */
- pci_read_config_word (pdev, SIO_SP1BAR, &sio->sp1_base);
+ pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
sio->sp1_base &= ~1;
printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base);
- pci_read_config_word (pdev, SIO_SP2BAR, &sio->sp2_base);
+ pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base);
sio->sp2_base &= ~1;
printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base);
- pci_read_config_word (pdev, SIO_PPBAR, &sio->pp_base);
+ pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base);
sio->pp_base &= ~1;
printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base);
- pci_read_config_word (pdev, SIO_FDCBAR, &sio->fdc_base);
+ pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base);
sio->fdc_base &= ~1;
printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base);
- pci_read_config_word (pdev, SIO_ACPIBAR, &sio->acpi_base);
+ pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base);
sio->acpi_base &= ~1;
printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base);
pci_read_config_word (pdev, PCI_COMMAND, &word);
word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
pci_write_config_word (pdev, PCI_COMMAND, word);
+
pci_set_master (pdev);
+ pci_enable_device(pdev);
- /* Next project is programming the onboard interrupt
- * controllers. PDC hasn't done this for us, since it's using
- * polled I/O.
+ /*
+ * Next project is programming the onboard interrupt controllers.
+ * PDC hasn't done this for us, since it's using polled I/O.
+ *
+ * XXX Use dword writes to avoid bugs in Elroy or Suckyio Config
+ * space access. PCI is by nature a 32-bit bus and config
+ * space can be sensitive to that.
*/
- /* Set PIC interrupts to edge triggered */
- pci_write_config_byte (pdev, TRIGGER_1, 0x0);
- pci_write_config_byte (pdev, TRIGGER_2, 0x0);
-
- /* Disable all interrupt routing */
- for (i = IR_LOW ; i < IR_HIGH ; i++)
- pci_write_config_byte (pdev, i, 0x0);
+ /* 0x64 - 0x67 :
+ DMA Rtg 2
+ DMA Rtg 3
+ DMA Chan Ctl
+ TRIGGER_1 == 0x82 USB & IDE level triggered, rest to edge
+ */
+ pci_write_config_dword (pdev, 0x64, 0x82000000U);
+
+ /* 0x68 - 0x6b :
+ TRIGGER_2 == 0x00 all edge triggered (not used)
+ CFG_IR_SER == 0x43 SerPort1 = IRQ3, SerPort2 = IRQ4
+ CFG_IR_PF == 0x65 ParPort = IRQ5, FloppyCtlr = IRQ6
+ CFG_IR_IDE == 0x07 IDE1 = IRQ7, reserved
+ */
+ pci_write_config_dword (pdev, TRIGGER_2, 0x07654300U);
+
+ /* 0x6c - 0x6f :
+ CFG_IR_INTAB == 0x00
+ CFG_IR_INTCD == 0x10 USB = IRQ1
+ CFG_IR_PS2 == 0x00
+ CFG_IR_FXBUS == 0x00
+ */
+ pci_write_config_dword (pdev, CFG_IR_INTAB, 0x00001000U);
+
+ /* 0x70 - 0x73 :
+ CFG_IR_USB == 0x00 not used. USB is connected to INTD.
+ CFG_IR_ACPI == 0x00 not used.
+ DMA Priority == 0x4c88 Power on default value. NFC.
+ */
+ pci_write_config_dword (pdev, CFG_IR_USB, 0x4c880000U);
/* PIC1 Initialization Command Word register programming */
outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */
- outb (0x00,IC_PIC1+1); /* ICW2: N/A */
+ outb (0x00,IC_PIC1+1); /* ICW2: interrupt vector table - not used */
outb (0x04,IC_PIC1+1); /* ICW3: Cascade */
outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */
outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */
/* Write master mask reg */
-
outb (0xff,IC_PIC1+1);
- /* Set up interrupt routing */
-
- pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */
- pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */
- pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */
- pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE1 on IRQ7 */
-
- /* Set USB and IDE to level triggered interrupts, rest to edge */
- pci_write_config_byte (pdev, TRIGGER_1, 0x82); /* IRQ 1 and 7 */
-
/* Setup USB power regulation */
outb(1, sio->acpi_base + USB_REG_CR);
if (inb(sio->acpi_base + USB_REG_CR) & 1)
else
printk(KERN_ERR "USB regulator not initialized!\n");
- pci_enable_device(pdev);
-
- if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT,
- "SuperIO",(void *)sio)) {
+ if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT,
+ "SuperIO", (void *)sio)) {
printk(KERN_ERR "SuperIO: could not get irq\n");
BUG();
return;
}
- sio->iosapic_irq_enabled = 1;
-
+ sio->suckyio_irq_enabled = 1;
}
+
static void
superio_disable_irq(void *dev, int local_irq)
{
static void
superio_enable_irq(void *dev, int local_irq)
{
- struct superio_device *sio = (struct superio_device *)dev;
u8 r8;
if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
- printk(KERN_ERR "SuperIO: Illegal irq number.\n");
+ printk(KERN_ERR "SuperIO: Illegal irq number (%d).\n", local_irq);
BUG();
return;
}
- /*
- * It's possible that we haven't initialized the legacy IO
- * function yet. If not, do it now.
- */
-
- if (!sio->iosapic_irq_enabled)
- superio_init(sio);
-
/* Unmask interrupt */
-
r8 = inb(IC_PIC1+1);
r8 &= ~(1 << local_irq);
outb (r8,IC_PIC1+1);
}
+
static void
superio_mask_irq(void *dev, int local_irq)
{
.unmask_irq = superio_unmask_irq
};
-#ifdef DEBUG_INIT
+#ifdef DEBUG_SUPERIO_INIT
static unsigned short expected_device[3] = {
PCI_DEVICE_ID_NS_87415,
PCI_DEVICE_ID_NS_87560_LIO,
{
int local_irq;
-#ifdef DEBUG_INIT
+#ifdef DEBUG_SUPERIO_INIT
int fn;
fn = PCI_FUNC(pcidev->devfn);
local_irq = IDE_IRQ;
break;
case PCI_DEVICE_ID_NS_87560_LIO: /* Function 1 */
- sio_dev.lio_pdev = pcidev; /* save for later initialization */
+ sio_dev.lio_pdev = pcidev; /* save for superio_init() */
return -1;
case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */
+ sio_dev.usb_pdev = pcidev; /* save for superio_init() */
local_irq = USB_IRQ;
break;
default:
{
#ifdef CONFIG_SERIAL_8250
int retval;
+ extern void serial8250_console_init(void); /* drivers/serial/8250.c */
if (!sio_dev.irq_region)
return; /* superio not present */
- if (!sio_dev.iosapic_irq_enabled)
- superio_init(&sio_dev);
+ if (!serial) {
+ printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n");
+ return;
+ }
serial[0].iobase = sio_dev.sp1_base;
- retval = early_serial_setup(&serial[0]);
+ serial[0].irq = sio_dev.irq_region->data.irqbase + SP1_IRQ;
- if (retval < 0)
+ retval = early_serial_setup(&serial[0]);
+ if (retval < 0) {
printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n");
+ return;
+ }
+
+ serial8250_console_init();
serial[1].iobase = sio_dev.sp2_base;
+ serial[1].irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
retval = early_serial_setup(&serial[1]);
if (retval < 0)
#endif /* CONFIG_SERIAL_8250 */
}
-EXPORT_SYMBOL(superio_serial_init);
-
-#ifdef CONFIG_PARPORT_PC
-void __devinit
+static void __devinit
superio_parport_init(void)
{
- if (!sio_dev.irq_region)
- return; /* superio not present */
-
- if (!sio_dev.iosapic_irq_enabled)
- superio_init(&sio_dev);
-
- if (!parport_pc_probe_port(sio_dev.pp_base,
- 0 /*base_hi*/,
- sio_dev.irq_region->data.irqbase + PAR_IRQ,
- PARPORT_DMA_NONE /* dma */,
- NULL /*struct pci_dev* */))
+#ifdef CONFIG_PARPORT_PC
+ if (!parport_pc_probe_port(sio_dev.pp_base,
+ 0 /*base_hi*/,
+ sio_dev.irq_region->data.irqbase + PAR_IRQ,
+ PARPORT_DMA_NONE /* dma */,
+ NULL /*struct pci_dev* */) )
printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n");
-}
-
-EXPORT_SYMBOL(superio_parport_init);
#endif /* CONFIG_PARPORT_PC */
+}
int
static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
-#ifdef DEBUG_INIT
- printk("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
+
+ /*
+ ** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
+ ** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
+ ** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
+ */
+ DBG_INIT("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
pci_name(dev),
dev->vendor, dev->device,
dev->subsystem_vendor, dev->subsystem_device,
dev->class);
-/*
-** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
-** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
-** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
-*/
-#endif
- /* superio_fixup_irq(dev); */
+ superio_init(&sio_dev);
- if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {
-#ifdef CONFIG_PARPORT_PC
+ if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) { /* Function 1 */
superio_parport_init();
-#endif
-#ifdef CONFIG_SERIAL_8250
superio_serial_init();
-#endif
- /* REVISIT : superio_fdc_init() ? */
+ /* REVISIT XXX : superio_fdc_init() ? */
return 0;
+ } else if (dev->device == PCI_DEVICE_ID_NS_87415) { /* Function 0 */
+ DBG_INIT("superio_probe: ignoring IDE 87415\n");
+ } else if (dev->device == PCI_DEVICE_ID_NS_87560_USB) { /* Function 2 */
+ DBG_INIT("superio_probe: ignoring USB OHCI controller\n");
} else {
- /* don't claim this device; let whatever either driver
- * do it
- */
- return -1;
+ DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n");
}
+
+ /* Let appropriate other driver claim this device. */
+ return -ENODEV;
}
static struct pci_device_id superio_tbl[] = {
pci_unregister_driver(&superio_driver);
}
-/* Make late initcall to ensure the serial and tty layers are initialised
- * before we start superio.
- *
- * FIXME: does this break the superio console?
- */
+
module_init(superio_modinit);
module_exit(superio_exit);
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/slab.h>
+#include <linux/delay.h> /* for udelay */
#include <asm/io.h>
#include <asm/parisc-device.h>
#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
-#define UART_NR 8
-struct mux_card {
- struct uart_port ports[UART_NR];
- struct uart_driver drv;
- struct mux_card *next;
-};
-
-static struct mux_card mux_card_head = {
- .next = NULL,
+#define MUX_NR 256
+static unsigned int port_cnt = 0;
+static struct uart_port mux_ports[MUX_NR];
+
+static struct uart_driver mux_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "ttyB",
+ .dev_name = "ttyB",
+ .major = MUX_MAJOR,
+ .minor = 0,
+ .nr = MUX_NR,
};
static struct timer_list mux_timer;
return;
}
- count = (port->fifosize >> 1) - UART_GET_FIFO_CNT(port);
+ count = (port->fifosize) - UART_GET_FIFO_CNT(port);
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
} while(--count > 0);
+ while(UART_GET_FIFO_CNT(port))
+ udelay(1);
+
if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
static void mux_poll(unsigned long unused)
{
int i;
- struct mux_card *card = &mux_card_head;
- while(card) {
- for(i = 0; i < UART_NR; ++i) {
- if(!card->ports[i].info)
- continue;
+ for(i = 0; i < port_cnt; ++i) {
+ if(!mux_ports[i].info)
+ continue;
- mux_read(&card->ports[i]);
- mux_write(&card->ports[i]);
- }
- card = card->next;
+ mux_read(&mux_ports[i]);
+ mux_write(&mux_ports[i]);
}
+
mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
}
#ifdef CONFIG_SERIAL_MUX_CONSOLE
+static void mux_console_write(struct console *co, const char *s, unsigned count)
+{
+ while(count--)
+ pdc_iodc_putc(*s++);
+}
+
+static int mux_console_setup(struct console *co, char *options)
+{
+ return 0;
+}
+
+struct tty_driver *mux_console_device(struct console *co, int *index)
+{
+ *index = co->index;
+ return mux_driver.tty_driver;
+}
+
static struct console mux_console = {
.name = "ttyB",
- .flags = CON_PRINTBUFFER,
+ .write = mux_console_write,
+ .device = mux_console_device,
+ .setup = mux_console_setup,
+ .flags = CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
.index = 0,
};
+
#define MUX_CONSOLE &mux_console
#else
#define MUX_CONSOLE NULL
*/
static int __init mux_probe(struct parisc_device *dev)
{
- int i, j, ret, ports, port_cnt = 0;
- u8 iodc_data[8];
+ int i, status, ports;
+ u8 iodc_data[32];
unsigned long bytecnt;
struct uart_port *port;
- struct mux_card *card = &mux_card_head;
- ret = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 8);
- if(ret != PDC_OK) {
+ status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32);
+ if(status != PDC_OK) {
printk(KERN_ERR "Serial mux: Unable to read IODC.\n");
return 1;
}
ports = GET_MUX_PORTS(iodc_data);
- printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.2\n",
- ports);
-
- if(!card->drv.nr) {
- init_timer(&mux_timer);
- mux_timer.function = mux_poll;
- } else {
- port_cnt += UART_NR;
- while(card->next) {
- card = card->next;
- port_cnt += UART_NR;
- }
- }
-
- for(i = 0; i < ports / UART_NR; ++i) {
- if(card->drv.nr) {
- card->next = kmalloc(sizeof(struct mux_card), GFP_KERNEL);
- if(!card->next) {
- printk(KERN_ERR "Serial mux: Unable to allocate memory.\n");
- return 1;
- }
- memset(card->next, '\0', sizeof(struct mux_card));
- card = card->next;
- }
+ printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports);
- card->drv.owner = THIS_MODULE;
- card->drv.driver_name = "ttyB";
- card->drv.dev_name = "ttyB";
- card->drv.major = MUX_MAJOR;
- card->drv.minor = port_cnt;
- card->drv.nr = UART_NR;
- card->drv.cons = MUX_CONSOLE;
+ if(!port_cnt) {
+ mux_driver.cons = MUX_CONSOLE;
- ret = uart_register_driver(&card->drv);
- if(ret) {
+ status = uart_register_driver(&mux_driver);
+ if(status) {
printk(KERN_ERR "Serial mux: Unable to register driver.\n");
return 1;
}
- for(j = 0; j < UART_NR; ++j) {
- port = &card->ports[j];
-
- port->iobase = 0;
- port->mapbase = dev->hpa + MUX_OFFSET + (j * MUX_LINE_OFFSET);
- port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET);
- port->iotype = SERIAL_IO_MEM;
- port->type = PORT_MUX;
- port->irq = SERIAL_IRQ_NONE;
- port->uartclk = 0;
- port->fifosize = MUX_FIFO_SIZE;
- port->ops = &mux_pops;
- port->flags = UPF_BOOT_AUTOCONF;
- port->line = j;
- ret = uart_add_one_port(&card->drv, port);
- BUG_ON(ret);
- }
- port_cnt += UART_NR;
+ init_timer(&mux_timer);
+ mux_timer.function = mux_poll;
+ }
+
+ for(i = 0; i < ports; ++i, ++port_cnt) {
+ port = &mux_ports[port_cnt];
+ port->iobase = 0;
+ port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET);
+ port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET);
+ port->iotype = SERIAL_IO_MEM;
+ port->type = PORT_MUX;
+ port->irq = SERIAL_IRQ_NONE;
+ port->uartclk = 0;
+ port->fifosize = MUX_FIFO_SIZE;
+ port->ops = &mux_pops;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->line = port_cnt;
+ status = uart_add_one_port(&mux_driver, port);
+ BUG_ON(status);
}
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+ register_console(&mux_console);
+#endif
return 0;
}
MODULE_DEVICE_TABLE(parisc, mux_tbl);
-static struct parisc_driver mux_driver = {
+static struct parisc_driver serial_mux_driver = {
.name = "Serial MUX",
.id_table = mux_tbl,
.probe = mux_probe,
*/
static int __init mux_init(void)
{
- return register_parisc_driver(&mux_driver);
+ return register_parisc_driver(&serial_mux_driver);
}
/**
static void __exit mux_exit(void)
{
int i;
- struct mux_card *card = &mux_card_head;
- for (i = 0; i < UART_NR; i++) {
- uart_remove_one_port(&card->drv, &card->ports[i]);
+ for (i = 0; i < port_cnt; i++) {
+ uart_remove_one_port(&mux_driver, &mux_ports[i]);
}
- uart_unregister_driver(&card->drv);
+ uart_unregister_driver(&mux_driver);
}
module_init(mux_init);
static void __init
sti_dump_rom(struct sti_rom *rom)
{
- printk(KERN_INFO "STI id %04x-%04x, conforms to spec rev. %d.%02x\n",
+ printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n",
rom->graphics_id[0],
rom->graphics_id[1],
rom->revno[0] >> 4,
rom->revno[0] & 0x0f);
- DPRINTK((" supports %d monitors\n", rom->num_mons));
- DPRINTK((" font start %08x\n", rom->font_start));
- DPRINTK((" region list %08x\n", rom->region_list));
- DPRINTK((" init_graph %08x\n", rom->init_graph));
- DPRINTK((" bus support %02x\n", rom->bus_support));
- DPRINTK((" ext bus support %02x\n", rom->ext_bus_support));
- DPRINTK((" alternate code type %d\n", rom->alt_code_type));
+ DPRINTK((" supports %d monitors\n", rom->num_mons));
+ DPRINTK((" font start %08x\n", rom->font_start));
+ DPRINTK((" region list %08x\n", rom->region_list));
+ DPRINTK((" init_graph %08x\n", rom->init_graph));
+ DPRINTK((" bus support %02x\n", rom->bus_support));
+ DPRINTK((" ext bus support %02x\n", rom->ext_bus_support));
+ DPRINTK((" alternate code type %d\n", rom->alt_code_type));
}
ok = 0;
if ((sig & 0xff) == 0x01) {
- printk(KERN_INFO "STI byte mode ROM at %08lx, hpa at %08lx\n",
- address, hpa);
+ DPRINTK((" byte mode ROM at %08lx, hpa at %08lx\n",
+ address, hpa));
ok = sti_read_rom(0, sti, address);
}
if ((sig & 0xffff) == 0x0303) {
- printk(KERN_INFO "STI word mode ROM at %08lx, hpa at %08lx\n",
- address, hpa);
+ DPRINTK((" word mode ROM at %08lx, hpa at %08lx\n",
+ address, hpa));
ok = sti_read_rom(1, sti, address);
}
sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
sti_dump_outptr(sti);
- printk(KERN_INFO "STI device: %s\n", sti->outptr.dev_name );
+ printk(KERN_INFO " graphics card name: %s\n", sti->outptr.dev_name );
sti_roms[num_sti_roms] = sti;
num_sti_roms++;
* Low level Frame buffer driver for HP workstations with
* STI (standard text interface) video firmware.
*
- * Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2001-2004 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
*
* Based on:
*/
/* TODO:
- * - remove the static fb_info to support multiple cards
* - 1bpp mode is completely untested
* - add support for h/w acceleration
* - add hardware cursor
+ * - automatically disable double buffering (e.g. on RDI precisionbook laptop)
*/
* #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
#undef FALLBACK_TO_1BPP
+#undef DEBUG_STIFB_REGS /* debug sti register accesses */
+
#include <linux/config.h>
#include <linux/module.h>
#define READ_BYTE(fb,reg) __raw_readb((fb)->info.fix.mmio_start + (reg))
#define READ_WORD(fb,reg) __raw_readl((fb)->info.fix.mmio_start + (reg))
-#define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
-#define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->info.fix.mmio_start + (reg))
+
+
+#ifndef DEBUG_STIFB_REGS
+# define DEBUG_OFF()
+# define DEBUG_ON()
+# define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->info.fix.mmio_start + (reg))
+#else
+ static int debug_on = 1;
+# define DEBUG_OFF() debug_on=0
+# define DEBUG_ON() debug_on=1
+# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
+ printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
+ __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
+ __raw_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
+ printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
+ __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
+ __raw_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+#endif /* DEBUG_STIFB_REGS */
+
#define ENABLE 1 /* for enabling/disabling screen */
#define DISABLE 0
WRITE_WORD(val, fb, REG_6)
#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
- (u32) (fbaddrbase) + \
+ (u32) (fbaddrbase) + \
( (unsigned int) ( (y) << 13 ) | \
(unsigned int) ( (x) << 2 ) ) \
)
static void
SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
{
+ /* REG_6 seems to have special values when run on a
+ RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
+ INTERNAL_EG_X1024). The values are:
+ 0x2f0: internal (LCD) & external display enabled
+ 0x2a0: external display only
+ 0x000: zero on standard artist graphic cards
+ */
WRITE_WORD(0x00000000, fb, REG_6);
WRITE_WORD((width<<16) | height, fb, REG_9);
WRITE_WORD(0x05000000, fb, REG_6);
controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
switch (enable) {
- case 1: /* ENABLE */
+ case ENABLE:
/* clear screen */
if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb);
hyperUndoITE(fb);
break;
- case 0: /* DISABLE */
+ case DISABLE:
/* clear screen */
if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb);
green >>= 8;
blue >>= 8;
+ DEBUG_OFF();
+
START_IMAGE_COLORMAP_ACCESS(fb);
if (fb->info.var.grayscale) {
FINISH_IMAGE_COLORMAP_ACCESS(fb);
}
+ DEBUG_ON();
+
return 0;
}
/* only supported cards are allowed */
switch (fb->id) {
+ case CRT_ID_VISUALIZE_EG:
+ /* look for a double buffering device like e.g. the
+ "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
+ which won't work. The same device in non-double
+ buffering mode returns "INTERNAL_EG_X1024". */
+ if (strstr(sti->outptr.dev_name, "EG_DX")) {
+ printk(KERN_WARNING
+ "stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
+ sti->outptr.dev_name);
+ goto out_err0;
+ }
+ /* fall though */
case S9000_ID_ARTIST:
case S9000_ID_HCRX:
case S9000_ID_TIMBER:
case S9000_ID_A1659A:
case S9000_ID_A1439A:
- case CRT_ID_VISUALIZE_EG:
break;
default:
- printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
- fb->id);
- goto out_err1;
+ printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
+ sti->outptr.dev_name, fb->id);
+ goto out_err0;
}
/* default to 8 bpp on most graphic chips */
"stifb: Unsupported graphics card (id=0x%08x) "
"- skipping.\n",
fb->id);
- goto out_err1;
+ goto out_err0;
#endif
}
sti->info = info; /* save for unregister_framebuffer() */
printk(KERN_INFO
- "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
+ "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
fb->info.node,
fix->id,
var->xres,
var->yres,
var->bits_per_pixel,
+ sti->outptr.dev_name,
fb->id,
fix->mmio_start);
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
fb_dealloc_cmap(&info->cmap);
+out_err0:
kfree(fb);
return -ENXIO;
}
+static int stifb_disabled __initdata;
+
int __init
stifb_init(void)
{
struct sti_struct *sti;
int i;
+ if (stifb_disabled) {
+ printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
+ return -ENXIO;
+ }
+
for (i = 1; i < MAX_STI_ROMS; i++) {
sti = sti_get_rom(i);
if (!sti)
if (!options || !*options)
return 0;
+ if (strncmp(options, "off", 3) == 0) {
+ stifb_disabled = 1;
+ options += 3;
+ }
+
if (strncmp(options, "bpp", 3) == 0) {
options += 3;
for (i = 0; i < MAX_STI_ROMS; i++) {