162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci** 462306a36Sopenharmony_ci** PCI Lower Bus Adapter (LBA) manager 562306a36Sopenharmony_ci** 662306a36Sopenharmony_ci** (c) Copyright 1999,2000 Grant Grundler 762306a36Sopenharmony_ci** (c) Copyright 1999,2000 Hewlett-Packard Company 862306a36Sopenharmony_ci** 962306a36Sopenharmony_ci** 1062306a36Sopenharmony_ci** 1162306a36Sopenharmony_ci** This module primarily provides access to PCI bus (config/IOport 1262306a36Sopenharmony_ci** spaces) on platforms with an SBA/LBA chipset. A/B/C/J/L/N-class 1362306a36Sopenharmony_ci** with 4 digit model numbers - eg C3000 (and A400...sigh). 1462306a36Sopenharmony_ci** 1562306a36Sopenharmony_ci** LBA driver isn't as simple as the Dino driver because: 1662306a36Sopenharmony_ci** (a) this chip has substantial bug fixes between revisions 1762306a36Sopenharmony_ci** (Only one Dino bug has a software workaround :^( ) 1862306a36Sopenharmony_ci** (b) has more options which we don't (yet) support (DMA hints, OLARD) 1962306a36Sopenharmony_ci** (c) IRQ support lives in the I/O SAPIC driver (not with PCI driver) 2062306a36Sopenharmony_ci** (d) play nicely with both PAT and "Legacy" PA-RISC firmware (PDC). 2162306a36Sopenharmony_ci** (dino only deals with "Legacy" PDC) 2262306a36Sopenharmony_ci** 2362306a36Sopenharmony_ci** LBA driver passes the I/O SAPIC HPA to the I/O SAPIC driver. 2462306a36Sopenharmony_ci** (I/O SAPIC is integratd in the LBA chip). 2562306a36Sopenharmony_ci** 2662306a36Sopenharmony_ci** FIXME: Add support to SBA and LBA drivers for DMA hint sets 2762306a36Sopenharmony_ci** FIXME: Add support for PCI card hot-plug (OLARD). 2862306a36Sopenharmony_ci*/ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/delay.h> 3162306a36Sopenharmony_ci#include <linux/types.h> 3262306a36Sopenharmony_ci#include <linux/kernel.h> 3362306a36Sopenharmony_ci#include <linux/spinlock.h> 3462306a36Sopenharmony_ci#include <linux/init.h> /* for __init */ 3562306a36Sopenharmony_ci#include <linux/pci.h> 3662306a36Sopenharmony_ci#include <linux/ioport.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <asm/byteorder.h> 4062306a36Sopenharmony_ci#include <asm/pdc.h> 4162306a36Sopenharmony_ci#include <asm/pdcpat.h> 4262306a36Sopenharmony_ci#include <asm/page.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include <asm/ropes.h> 4562306a36Sopenharmony_ci#include <asm/hardware.h> /* for register_parisc_driver() stuff */ 4662306a36Sopenharmony_ci#include <asm/parisc-device.h> 4762306a36Sopenharmony_ci#include <asm/io.h> /* read/write stuff */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include "iommu.h" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#undef DEBUG_LBA /* general stuff */ 5262306a36Sopenharmony_ci#undef DEBUG_LBA_PORT /* debug I/O Port access */ 5362306a36Sopenharmony_ci#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */ 5462306a36Sopenharmony_ci#undef DEBUG_LBA_PAT /* debug PCI Resource Mgt code - PDC PAT only */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#undef FBB_SUPPORT /* Fast Back-Back xfers - NOT READY YET */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#ifdef DEBUG_LBA 6062306a36Sopenharmony_ci#define DBG(x...) printk(x) 6162306a36Sopenharmony_ci#else 6262306a36Sopenharmony_ci#define DBG(x...) 6362306a36Sopenharmony_ci#endif 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#ifdef DEBUG_LBA_PORT 6662306a36Sopenharmony_ci#define DBG_PORT(x...) printk(x) 6762306a36Sopenharmony_ci#else 6862306a36Sopenharmony_ci#define DBG_PORT(x...) 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef DEBUG_LBA_CFG 7262306a36Sopenharmony_ci#define DBG_CFG(x...) printk(x) 7362306a36Sopenharmony_ci#else 7462306a36Sopenharmony_ci#define DBG_CFG(x...) 7562306a36Sopenharmony_ci#endif 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#ifdef DEBUG_LBA_PAT 7862306a36Sopenharmony_ci#define DBG_PAT(x...) printk(x) 7962306a36Sopenharmony_ci#else 8062306a36Sopenharmony_ci#define DBG_PAT(x...) 8162306a36Sopenharmony_ci#endif 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci** Config accessor functions only pass in the 8-bit bus number and not 8662306a36Sopenharmony_ci** the 8-bit "PCI Segment" number. Each LBA will be assigned a PCI bus 8762306a36Sopenharmony_ci** number based on what firmware wrote into the scratch register. 8862306a36Sopenharmony_ci** 8962306a36Sopenharmony_ci** The "secondary" bus number is set to this before calling 9062306a36Sopenharmony_ci** pci_register_ops(). If any PPB's are present, the scan will 9162306a36Sopenharmony_ci** discover them and update the "secondary" and "subordinate" 9262306a36Sopenharmony_ci** fields in the pci_bus structure. 9362306a36Sopenharmony_ci** 9462306a36Sopenharmony_ci** Changes in the configuration *may* result in a different 9562306a36Sopenharmony_ci** bus number for each LBA depending on what firmware does. 9662306a36Sopenharmony_ci*/ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define MODULE_NAME "LBA" 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* non-postable I/O port space, densely packed */ 10162306a36Sopenharmony_ci#define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL) 10262306a36Sopenharmony_cistatic void __iomem *astro_iop_base __read_mostly; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic u32 lba_t32; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* lba flags */ 10762306a36Sopenharmony_ci#define LBA_FLAG_SKIP_PROBE 0x10 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic inline struct lba_device *LBA_DEV(struct pci_hba_data *hba) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci return container_of(hba, struct lba_device, hba); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* 11762306a36Sopenharmony_ci** Only allow 8 subsidiary busses per LBA 11862306a36Sopenharmony_ci** Problem is the PCI bus numbering is globally shared. 11962306a36Sopenharmony_ci*/ 12062306a36Sopenharmony_ci#define LBA_MAX_NUM_BUSES 8 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/************************************ 12362306a36Sopenharmony_ci * LBA register read and write support 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * BE WARNED: register writes are posted. 12662306a36Sopenharmony_ci * (ie follow writes which must reach HW with a read) 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci#define READ_U8(addr) __raw_readb(addr) 12962306a36Sopenharmony_ci#define READ_U16(addr) __raw_readw(addr) 13062306a36Sopenharmony_ci#define READ_U32(addr) __raw_readl(addr) 13162306a36Sopenharmony_ci#define WRITE_U8(value, addr) __raw_writeb(value, addr) 13262306a36Sopenharmony_ci#define WRITE_U16(value, addr) __raw_writew(value, addr) 13362306a36Sopenharmony_ci#define WRITE_U32(value, addr) __raw_writel(value, addr) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define READ_REG8(addr) readb(addr) 13662306a36Sopenharmony_ci#define READ_REG16(addr) readw(addr) 13762306a36Sopenharmony_ci#define READ_REG32(addr) readl(addr) 13862306a36Sopenharmony_ci#define READ_REG64(addr) readq(addr) 13962306a36Sopenharmony_ci#define WRITE_REG8(value, addr) writeb(value, addr) 14062306a36Sopenharmony_ci#define WRITE_REG16(value, addr) writew(value, addr) 14162306a36Sopenharmony_ci#define WRITE_REG32(value, addr) writel(value, addr) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8)) 14562306a36Sopenharmony_ci#define LBA_CFG_BUS(tok) ((u8) ((tok)>>16)) 14662306a36Sopenharmony_ci#define LBA_CFG_DEV(tok) ((u8) ((tok)>>11) & 0x1f) 14762306a36Sopenharmony_ci#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* 15162306a36Sopenharmony_ci** Extract LBA (Rope) number from HPA 15262306a36Sopenharmony_ci** REVISIT: 16 ropes for Stretch/Ike? 15362306a36Sopenharmony_ci*/ 15462306a36Sopenharmony_ci#define ROPES_PER_IOC 8 15562306a36Sopenharmony_ci#define LBA_NUM(x) ((((unsigned long) x) >> 13) & (ROPES_PER_IOC-1)) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void 15962306a36Sopenharmony_cilba_dump_res(struct resource *r, int d) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci int i; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (NULL == r) 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci printk(KERN_DEBUG "(%p)", r->parent); 16762306a36Sopenharmony_ci for (i = d; i ; --i) printk(" "); 16862306a36Sopenharmony_ci printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, 16962306a36Sopenharmony_ci (long)r->start, (long)r->end, r->flags); 17062306a36Sopenharmony_ci lba_dump_res(r->child, d+2); 17162306a36Sopenharmony_ci lba_dump_res(r->sibling, d); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex 17762306a36Sopenharmony_ci** workaround for cfg cycles: 17862306a36Sopenharmony_ci** -- preserve LBA state 17962306a36Sopenharmony_ci** -- prevent any DMA from occurring 18062306a36Sopenharmony_ci** -- turn on smart mode 18162306a36Sopenharmony_ci** -- probe with config writes before doing config reads 18262306a36Sopenharmony_ci** -- check ERROR_STATUS 18362306a36Sopenharmony_ci** -- clear ERROR_STATUS 18462306a36Sopenharmony_ci** -- restore LBA state 18562306a36Sopenharmony_ci** 18662306a36Sopenharmony_ci** The workaround is only used for device discovery. 18762306a36Sopenharmony_ci*/ 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int lba_device_present(u8 bus, u8 dfn, struct lba_device *d) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci u8 first_bus = d->hba.hba_bus->busn_res.start; 19262306a36Sopenharmony_ci u8 last_sub_bus = d->hba.hba_bus->busn_res.end; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if ((bus < first_bus) || 19562306a36Sopenharmony_ci (bus > last_sub_bus) || 19662306a36Sopenharmony_ci ((bus - first_bus) >= LBA_MAX_NUM_BUSES)) { 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return 1; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#define LBA_CFG_SETUP(d, tok) { \ 20662306a36Sopenharmony_ci /* Save contents of error config register. */ \ 20762306a36Sopenharmony_ci error_config = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); \ 20862306a36Sopenharmony_ci\ 20962306a36Sopenharmony_ci /* Save contents of status control register. */ \ 21062306a36Sopenharmony_ci status_control = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); \ 21162306a36Sopenharmony_ci\ 21262306a36Sopenharmony_ci /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA \ 21362306a36Sopenharmony_ci ** arbitration for full bus walks. \ 21462306a36Sopenharmony_ci */ \ 21562306a36Sopenharmony_ci /* Save contents of arb mask register. */ \ 21662306a36Sopenharmony_ci arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK); \ 21762306a36Sopenharmony_ci\ 21862306a36Sopenharmony_ci /* \ 21962306a36Sopenharmony_ci * Turn off all device arbitration bits (i.e. everything \ 22062306a36Sopenharmony_ci * except arbitration enable bit). \ 22162306a36Sopenharmony_ci */ \ 22262306a36Sopenharmony_ci WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK); \ 22362306a36Sopenharmony_ci\ 22462306a36Sopenharmony_ci /* \ 22562306a36Sopenharmony_ci * Set the smart mode bit so that master aborts don't cause \ 22662306a36Sopenharmony_ci * LBA to go into PCI fatal mode (required). \ 22762306a36Sopenharmony_ci */ \ 22862306a36Sopenharmony_ci WRITE_REG32(error_config | LBA_SMART_MODE, d->hba.base_addr + LBA_ERROR_CONFIG); \ 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#define LBA_CFG_PROBE(d, tok) { \ 23362306a36Sopenharmony_ci /* \ 23462306a36Sopenharmony_ci * Setup Vendor ID write and read back the address register \ 23562306a36Sopenharmony_ci * to make sure that LBA is the bus master. \ 23662306a36Sopenharmony_ci */ \ 23762306a36Sopenharmony_ci WRITE_REG32(tok | PCI_VENDOR_ID, (d)->hba.base_addr + LBA_PCI_CFG_ADDR);\ 23862306a36Sopenharmony_ci /* \ 23962306a36Sopenharmony_ci * Read address register to ensure that LBA is the bus master, \ 24062306a36Sopenharmony_ci * which implies that DMA traffic has stopped when DMA arb is off. \ 24162306a36Sopenharmony_ci */ \ 24262306a36Sopenharmony_ci lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ 24362306a36Sopenharmony_ci /* \ 24462306a36Sopenharmony_ci * Generate a cfg write cycle (will have no affect on \ 24562306a36Sopenharmony_ci * Vendor ID register since read-only). \ 24662306a36Sopenharmony_ci */ \ 24762306a36Sopenharmony_ci WRITE_REG32(~0, (d)->hba.base_addr + LBA_PCI_CFG_DATA); \ 24862306a36Sopenharmony_ci /* \ 24962306a36Sopenharmony_ci * Make sure write has completed before proceeding further, \ 25062306a36Sopenharmony_ci * i.e. before setting clear enable. \ 25162306a36Sopenharmony_ci */ \ 25262306a36Sopenharmony_ci lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * HPREVISIT: 25862306a36Sopenharmony_ci * -- Can't tell if config cycle got the error. 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * OV bit is broken until rev 4.0, so can't use OV bit and 26162306a36Sopenharmony_ci * LBA_ERROR_LOG_ADDR to tell if error belongs to config cycle. 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * As of rev 4.0, no longer need the error check. 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * -- Even if we could tell, we still want to return -1 26662306a36Sopenharmony_ci * for **ANY** error (not just master abort). 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * -- Only clear non-fatal errors (we don't want to bring 26962306a36Sopenharmony_ci * LBA out of pci-fatal mode). 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * Actually, there is still a race in which 27262306a36Sopenharmony_ci * we could be clearing a fatal error. We will 27362306a36Sopenharmony_ci * live with this during our initial bus walk 27462306a36Sopenharmony_ci * until rev 4.0 (no driver activity during 27562306a36Sopenharmony_ci * initial bus walk). The initial bus walk 27662306a36Sopenharmony_ci * has race conditions concerning the use of 27762306a36Sopenharmony_ci * smart mode as well. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci#define LBA_MASTER_ABORT_ERROR 0xc 28162306a36Sopenharmony_ci#define LBA_FATAL_ERROR 0x10 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci#define LBA_CFG_MASTER_ABORT_CHECK(d, base, tok, error) { \ 28462306a36Sopenharmony_ci u32 error_status = 0; \ 28562306a36Sopenharmony_ci /* \ 28662306a36Sopenharmony_ci * Set clear enable (CE) bit. Unset by HW when new \ 28762306a36Sopenharmony_ci * errors are logged -- LBA HW ERS section 14.3.3). \ 28862306a36Sopenharmony_ci */ \ 28962306a36Sopenharmony_ci WRITE_REG32(status_control | CLEAR_ERRLOG_ENABLE, base + LBA_STAT_CTL); \ 29062306a36Sopenharmony_ci error_status = READ_REG32(base + LBA_ERROR_STATUS); \ 29162306a36Sopenharmony_ci if ((error_status & 0x1f) != 0) { \ 29262306a36Sopenharmony_ci /* \ 29362306a36Sopenharmony_ci * Fail the config read request. \ 29462306a36Sopenharmony_ci */ \ 29562306a36Sopenharmony_ci error = 1; \ 29662306a36Sopenharmony_ci if ((error_status & LBA_FATAL_ERROR) == 0) { \ 29762306a36Sopenharmony_ci /* \ 29862306a36Sopenharmony_ci * Clear error status (if fatal bit not set) by setting \ 29962306a36Sopenharmony_ci * clear error log bit (CL). \ 30062306a36Sopenharmony_ci */ \ 30162306a36Sopenharmony_ci WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \ 30262306a36Sopenharmony_ci } \ 30362306a36Sopenharmony_ci } \ 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \ 30762306a36Sopenharmony_ci WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#define LBA_CFG_ADDR_SETUP(d, addr) { \ 31062306a36Sopenharmony_ci WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ 31162306a36Sopenharmony_ci /* \ 31262306a36Sopenharmony_ci * Read address register to ensure that LBA is the bus master, \ 31362306a36Sopenharmony_ci * which implies that DMA traffic has stopped when DMA arb is off. \ 31462306a36Sopenharmony_ci */ \ 31562306a36Sopenharmony_ci lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci#define LBA_CFG_RESTORE(d, base) { \ 32062306a36Sopenharmony_ci /* \ 32162306a36Sopenharmony_ci * Restore status control register (turn off clear enable). \ 32262306a36Sopenharmony_ci */ \ 32362306a36Sopenharmony_ci WRITE_REG32(status_control, base + LBA_STAT_CTL); \ 32462306a36Sopenharmony_ci /* \ 32562306a36Sopenharmony_ci * Restore error config register (turn off smart mode). \ 32662306a36Sopenharmony_ci */ \ 32762306a36Sopenharmony_ci WRITE_REG32(error_config, base + LBA_ERROR_CONFIG); \ 32862306a36Sopenharmony_ci /* \ 32962306a36Sopenharmony_ci * Restore arb mask register (reenables DMA arbitration). \ 33062306a36Sopenharmony_ci */ \ 33162306a36Sopenharmony_ci WRITE_REG32(arb_mask, base + LBA_ARB_MASK); \ 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic unsigned int 33762306a36Sopenharmony_cilba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci u32 data = ~0U; 34062306a36Sopenharmony_ci int error = 0; 34162306a36Sopenharmony_ci u32 arb_mask = 0; /* used by LBA_CFG_SETUP/RESTORE */ 34262306a36Sopenharmony_ci u32 error_config = 0; /* used by LBA_CFG_SETUP/RESTORE */ 34362306a36Sopenharmony_ci u32 status_control = 0; /* used by LBA_CFG_SETUP/RESTORE */ 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci LBA_CFG_SETUP(d, tok); 34662306a36Sopenharmony_ci LBA_CFG_PROBE(d, tok); 34762306a36Sopenharmony_ci LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); 34862306a36Sopenharmony_ci if (!error) { 34962306a36Sopenharmony_ci void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci LBA_CFG_ADDR_SETUP(d, tok | reg); 35262306a36Sopenharmony_ci switch (size) { 35362306a36Sopenharmony_ci case 1: data = (u32) READ_REG8(data_reg + (reg & 3)); break; 35462306a36Sopenharmony_ci case 2: data = (u32) READ_REG16(data_reg+ (reg & 2)); break; 35562306a36Sopenharmony_ci case 4: data = READ_REG32(data_reg); break; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci LBA_CFG_RESTORE(d, d->hba.base_addr); 35962306a36Sopenharmony_ci return(data); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge)); 36662306a36Sopenharmony_ci u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; 36762306a36Sopenharmony_ci u32 tok = LBA_CFG_TOK(local_bus, devfn); 36862306a36Sopenharmony_ci void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if ((pos > 255) || (devfn > 255)) 37162306a36Sopenharmony_ci return -EINVAL; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* FIXME: B2K/C3600 workaround is always use old method... */ 37462306a36Sopenharmony_ci /* if (!LBA_SKIP_PROBE(d)) */ { 37562306a36Sopenharmony_ci /* original - Generate config cycle on broken elroy 37662306a36Sopenharmony_ci with risk we will miss PCI bus errors. */ 37762306a36Sopenharmony_ci *data = lba_rd_cfg(d, tok, pos, size); 37862306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __func__, tok, pos, *data); 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->busn_res.start, devfn, d)) { 38362306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __func__, tok, pos); 38462306a36Sopenharmony_ci /* either don't want to look or know device isn't present. */ 38562306a36Sopenharmony_ci *data = ~0U; 38662306a36Sopenharmony_ci return(0); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Basic Algorithm 39062306a36Sopenharmony_ci ** Should only get here on fully working LBA rev. 39162306a36Sopenharmony_ci ** This is how simple the code should have been. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci LBA_CFG_ADDR_SETUP(d, tok | pos); 39462306a36Sopenharmony_ci switch(size) { 39562306a36Sopenharmony_ci case 1: *data = READ_REG8 (data_reg + (pos & 3)); break; 39662306a36Sopenharmony_ci case 2: *data = READ_REG16(data_reg + (pos & 2)); break; 39762306a36Sopenharmony_ci case 4: *data = READ_REG32(data_reg); break; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __func__, tok, pos, *data); 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic void 40562306a36Sopenharmony_cilba_wr_cfg(struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci int error __maybe_unused = 0; 40862306a36Sopenharmony_ci u32 arb_mask = 0; 40962306a36Sopenharmony_ci u32 error_config = 0; 41062306a36Sopenharmony_ci u32 status_control = 0; 41162306a36Sopenharmony_ci void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci LBA_CFG_SETUP(d, tok); 41462306a36Sopenharmony_ci LBA_CFG_ADDR_SETUP(d, tok | reg); 41562306a36Sopenharmony_ci switch (size) { 41662306a36Sopenharmony_ci case 1: WRITE_REG8 (data, data_reg + (reg & 3)); break; 41762306a36Sopenharmony_ci case 2: WRITE_REG16(data, data_reg + (reg & 2)); break; 41862306a36Sopenharmony_ci case 4: WRITE_REG32(data, data_reg); break; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); 42162306a36Sopenharmony_ci LBA_CFG_RESTORE(d, d->hba.base_addr); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* 42662306a36Sopenharmony_ci * LBA 4.0 config write code implements non-postable semantics 42762306a36Sopenharmony_ci * by doing a read of CONFIG ADDR after the write. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int elroy_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge)); 43362306a36Sopenharmony_ci u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; 43462306a36Sopenharmony_ci u32 tok = LBA_CFG_TOK(local_bus,devfn); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if ((pos > 255) || (devfn > 255)) 43762306a36Sopenharmony_ci return -EINVAL; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (!LBA_SKIP_PROBE(d)) { 44062306a36Sopenharmony_ci /* Original Workaround */ 44162306a36Sopenharmony_ci lba_wr_cfg(d, tok, pos, (u32) data, size); 44262306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __func__, tok, pos,data); 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->busn_res.start, devfn, d))) { 44762306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __func__, tok, pos,data); 44862306a36Sopenharmony_ci return 1; /* New Workaround */ 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __func__, tok, pos, data); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Basic Algorithm */ 45462306a36Sopenharmony_ci LBA_CFG_ADDR_SETUP(d, tok | pos); 45562306a36Sopenharmony_ci switch(size) { 45662306a36Sopenharmony_ci case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3)); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2)); 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci case 4: WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci /* flush posted write */ 46462306a36Sopenharmony_ci lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); 46562306a36Sopenharmony_ci return 0; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic struct pci_ops elroy_cfg_ops = { 47062306a36Sopenharmony_ci .read = elroy_cfg_read, 47162306a36Sopenharmony_ci .write = elroy_cfg_write, 47262306a36Sopenharmony_ci}; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * The mercury_cfg_ops are slightly misnamed; they're also used for Elroy 47662306a36Sopenharmony_ci * TR4.0 as no additional bugs were found in this areea between Elroy and 47762306a36Sopenharmony_ci * Mercury 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int mercury_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge)); 48362306a36Sopenharmony_ci u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; 48462306a36Sopenharmony_ci u32 tok = LBA_CFG_TOK(local_bus, devfn); 48562306a36Sopenharmony_ci void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if ((pos > 255) || (devfn > 255)) 48862306a36Sopenharmony_ci return -EINVAL; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); 49162306a36Sopenharmony_ci switch(size) { 49262306a36Sopenharmony_ci case 1: 49362306a36Sopenharmony_ci *data = READ_REG8(data_reg + (pos & 3)); 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case 2: 49662306a36Sopenharmony_ci *data = READ_REG16(data_reg + (pos & 2)); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci case 4: 49962306a36Sopenharmony_ci *data = READ_REG32(data_reg); break; 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci DBG_CFG("mercury_cfg_read(%x+%2x) -> 0x%x\n", tok, pos, *data); 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci/* 50862306a36Sopenharmony_ci * LBA 4.0 config write code implements non-postable semantics 50962306a36Sopenharmony_ci * by doing a read of CONFIG ADDR after the write. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge)); 51562306a36Sopenharmony_ci void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; 51662306a36Sopenharmony_ci u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; 51762306a36Sopenharmony_ci u32 tok = LBA_CFG_TOK(local_bus,devfn); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if ((pos > 255) || (devfn > 255)) 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __func__, tok, pos, data); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); 52562306a36Sopenharmony_ci switch(size) { 52662306a36Sopenharmony_ci case 1: 52762306a36Sopenharmony_ci WRITE_REG8 (data, data_reg + (pos & 3)); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci case 2: 53062306a36Sopenharmony_ci WRITE_REG16(data, data_reg + (pos & 2)); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case 4: 53362306a36Sopenharmony_ci WRITE_REG32(data, data_reg); 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* flush posted write */ 53862306a36Sopenharmony_ci lba_t32 = READ_U32(d->hba.base_addr + LBA_PCI_CFG_ADDR); 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic struct pci_ops mercury_cfg_ops = { 54362306a36Sopenharmony_ci .read = mercury_cfg_read, 54462306a36Sopenharmony_ci .write = mercury_cfg_write, 54562306a36Sopenharmony_ci}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic void 54962306a36Sopenharmony_cilba_bios_init(void) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci DBG(MODULE_NAME ": lba_bios_init\n"); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci#ifdef CONFIG_64BIT 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/* 55862306a36Sopenharmony_ci * truncate_pat_collision: Deal with overlaps or outright collisions 55962306a36Sopenharmony_ci * between PAT PDC reported ranges. 56062306a36Sopenharmony_ci * 56162306a36Sopenharmony_ci * Broken PA8800 firmware will report lmmio range that 56262306a36Sopenharmony_ci * overlaps with CPU HPA. Just truncate the lmmio range. 56362306a36Sopenharmony_ci * 56462306a36Sopenharmony_ci * BEWARE: conflicts with this lmmio range may be an 56562306a36Sopenharmony_ci * elmmio range which is pointing down another rope. 56662306a36Sopenharmony_ci * 56762306a36Sopenharmony_ci * FIXME: only deals with one collision per range...theoretically we 56862306a36Sopenharmony_ci * could have several. Supporting more than one collision will get messy. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_cistatic unsigned long 57162306a36Sopenharmony_citruncate_pat_collision(struct resource *root, struct resource *new) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci unsigned long start = new->start; 57462306a36Sopenharmony_ci unsigned long end = new->end; 57562306a36Sopenharmony_ci struct resource *tmp = root->child; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (end <= start || start < root->start || !tmp) 57862306a36Sopenharmony_ci return 0; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* find first overlap */ 58162306a36Sopenharmony_ci while (tmp && tmp->end < start) 58262306a36Sopenharmony_ci tmp = tmp->sibling; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* no entries overlap */ 58562306a36Sopenharmony_ci if (!tmp) return 0; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* found one that starts behind the new one 58862306a36Sopenharmony_ci ** Don't need to do anything. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci if (tmp->start >= end) return 0; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (tmp->start <= start) { 59362306a36Sopenharmony_ci /* "front" of new one overlaps */ 59462306a36Sopenharmony_ci new->start = tmp->end + 1; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (tmp->end >= end) { 59762306a36Sopenharmony_ci /* AACCKK! totally overlaps! drop this range. */ 59862306a36Sopenharmony_ci return 1; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (tmp->end < end ) { 60362306a36Sopenharmony_ci /* "end" of new one overlaps */ 60462306a36Sopenharmony_ci new->end = tmp->start - 1; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci printk(KERN_WARNING "LBA: Truncating lmmio_space [%lx/%lx] " 60862306a36Sopenharmony_ci "to [%lx,%lx]\n", 60962306a36Sopenharmony_ci start, end, 61062306a36Sopenharmony_ci (long)new->start, (long)new->end ); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return 0; /* truncation successful */ 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * extend_lmmio_len: extend lmmio range to maximum length 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * This is needed at least on C8000 systems to get the ATI FireGL card 61962306a36Sopenharmony_ci * working. On other systems we will currently not extend the lmmio space. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_cistatic unsigned long 62262306a36Sopenharmony_ciextend_lmmio_len(unsigned long start, unsigned long end, unsigned long lba_len) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct resource *tmp; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* exit if not a C8000 */ 62762306a36Sopenharmony_ci if (boot_cpu_data.cpu_type < mako) 62862306a36Sopenharmony_ci return end; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci pr_debug("LMMIO mismatch: PAT length = 0x%lx, MASK register = 0x%lx\n", 63162306a36Sopenharmony_ci end - start, lba_len); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci lba_len = min(lba_len+1, 256UL*1024*1024); /* limit to 256 MB */ 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - original\n", start, end); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci end += lba_len; 63962306a36Sopenharmony_ci if (end < start) /* fix overflow */ 64062306a36Sopenharmony_ci end = -1ULL; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - current\n", start, end); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* first overlap */ 64562306a36Sopenharmony_ci for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) { 64662306a36Sopenharmony_ci pr_debug("LBA: testing %pR\n", tmp); 64762306a36Sopenharmony_ci if (tmp->start == start) 64862306a36Sopenharmony_ci continue; /* ignore ourself */ 64962306a36Sopenharmony_ci if (tmp->end < start) 65062306a36Sopenharmony_ci continue; 65162306a36Sopenharmony_ci if (tmp->start > end) 65262306a36Sopenharmony_ci continue; 65362306a36Sopenharmony_ci if (end >= tmp->start) 65462306a36Sopenharmony_ci end = tmp->start - 1; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci pr_info("LBA: lmmio_space [0x%lx-0x%lx] - new\n", start, end); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* return new end */ 66062306a36Sopenharmony_ci return end; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci#else 66462306a36Sopenharmony_ci#define truncate_pat_collision(r,n) (0) 66562306a36Sopenharmony_ci#endif 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic void pcibios_allocate_bridge_resources(struct pci_dev *dev) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci int idx; 67062306a36Sopenharmony_ci struct resource *r; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { 67362306a36Sopenharmony_ci r = &dev->resource[idx]; 67462306a36Sopenharmony_ci if (!r->flags) 67562306a36Sopenharmony_ci continue; 67662306a36Sopenharmony_ci if (r->parent) /* Already allocated */ 67762306a36Sopenharmony_ci continue; 67862306a36Sopenharmony_ci if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) { 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * Something is wrong with the region. 68162306a36Sopenharmony_ci * Invalidate the resource to prevent 68262306a36Sopenharmony_ci * child resource allocations in this 68362306a36Sopenharmony_ci * range. 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci r->start = r->end = 0; 68662306a36Sopenharmony_ci r->flags = 0; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic void pcibios_allocate_bus_resources(struct pci_bus *bus) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct pci_bus *child; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Depth-First Search on bus tree */ 69662306a36Sopenharmony_ci if (bus->self) 69762306a36Sopenharmony_ci pcibios_allocate_bridge_resources(bus->self); 69862306a36Sopenharmony_ci list_for_each_entry(child, &bus->children, node) 69962306a36Sopenharmony_ci pcibios_allocate_bus_resources(child); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci/* 70462306a36Sopenharmony_ci** The algorithm is generic code. 70562306a36Sopenharmony_ci** But it needs to access local data structures to get the IRQ base. 70662306a36Sopenharmony_ci** Could make this a "pci_fixup_irq(bus, region)" but not sure 70762306a36Sopenharmony_ci** it's worth it. 70862306a36Sopenharmony_ci** 70962306a36Sopenharmony_ci** Called by do_pci_scan_bus() immediately after each PCI bus is walked. 71062306a36Sopenharmony_ci** Resources aren't allocated until recursive buswalk below HBA is completed. 71162306a36Sopenharmony_ci*/ 71262306a36Sopenharmony_cistatic void 71362306a36Sopenharmony_cilba_fixup_bus(struct pci_bus *bus) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct pci_dev *dev; 71662306a36Sopenharmony_ci#ifdef FBB_SUPPORT 71762306a36Sopenharmony_ci u16 status; 71862306a36Sopenharmony_ci#endif 71962306a36Sopenharmony_ci struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge)); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci DBG("lba_fixup_bus(0x%p) bus %d platform_data 0x%p\n", 72262306a36Sopenharmony_ci bus, (int)bus->busn_res.start, bus->bridge->platform_data); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* 72562306a36Sopenharmony_ci ** Properly Setup MMIO resources for this bus. 72662306a36Sopenharmony_ci ** pci_alloc_primary_bus() mangles this. 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ci if (bus->parent) { 72962306a36Sopenharmony_ci /* PCI-PCI Bridge */ 73062306a36Sopenharmony_ci pci_read_bridge_bases(bus); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* check and allocate bridge resources */ 73362306a36Sopenharmony_ci pcibios_allocate_bus_resources(bus); 73462306a36Sopenharmony_ci } else { 73562306a36Sopenharmony_ci /* Host-PCI Bridge */ 73662306a36Sopenharmony_ci int err; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n", 73962306a36Sopenharmony_ci ldev->hba.io_space.name, 74062306a36Sopenharmony_ci ldev->hba.io_space.start, ldev->hba.io_space.end, 74162306a36Sopenharmony_ci ldev->hba.io_space.flags); 74262306a36Sopenharmony_ci DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n", 74362306a36Sopenharmony_ci ldev->hba.lmmio_space.name, 74462306a36Sopenharmony_ci ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.end, 74562306a36Sopenharmony_ci ldev->hba.lmmio_space.flags); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci err = request_resource(&ioport_resource, &(ldev->hba.io_space)); 74862306a36Sopenharmony_ci if (err < 0) { 74962306a36Sopenharmony_ci lba_dump_res(&ioport_resource, 2); 75062306a36Sopenharmony_ci BUG(); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (ldev->hba.elmmio_space.flags) { 75462306a36Sopenharmony_ci err = request_resource(&iomem_resource, 75562306a36Sopenharmony_ci &(ldev->hba.elmmio_space)); 75662306a36Sopenharmony_ci if (err < 0) { 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci printk("FAILED: lba_fixup_bus() request for " 75962306a36Sopenharmony_ci "elmmio_space [%lx/%lx]\n", 76062306a36Sopenharmony_ci (long)ldev->hba.elmmio_space.start, 76162306a36Sopenharmony_ci (long)ldev->hba.elmmio_space.end); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* lba_dump_res(&iomem_resource, 2); */ 76462306a36Sopenharmony_ci /* BUG(); */ 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (ldev->hba.lmmio_space.flags) { 76962306a36Sopenharmony_ci err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); 77062306a36Sopenharmony_ci if (err < 0) { 77162306a36Sopenharmony_ci printk(KERN_ERR "FAILED: lba_fixup_bus() request for " 77262306a36Sopenharmony_ci "lmmio_space [%lx/%lx]\n", 77362306a36Sopenharmony_ci (long)ldev->hba.lmmio_space.start, 77462306a36Sopenharmony_ci (long)ldev->hba.lmmio_space.end); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci#ifdef CONFIG_64BIT 77962306a36Sopenharmony_ci /* GMMIO is distributed range. Every LBA/Rope gets part it. */ 78062306a36Sopenharmony_ci if (ldev->hba.gmmio_space.flags) { 78162306a36Sopenharmony_ci err = request_resource(&iomem_resource, &(ldev->hba.gmmio_space)); 78262306a36Sopenharmony_ci if (err < 0) { 78362306a36Sopenharmony_ci printk("FAILED: lba_fixup_bus() request for " 78462306a36Sopenharmony_ci "gmmio_space [%lx/%lx]\n", 78562306a36Sopenharmony_ci (long)ldev->hba.gmmio_space.start, 78662306a36Sopenharmony_ci (long)ldev->hba.gmmio_space.end); 78762306a36Sopenharmony_ci lba_dump_res(&iomem_resource, 2); 78862306a36Sopenharmony_ci BUG(); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci#endif 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci list_for_each_entry(dev, &bus->devices, bus_list) { 79662306a36Sopenharmony_ci int i; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci DBG("lba_fixup_bus() %s\n", pci_name(dev)); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Virtualize Device/Bridge Resources. */ 80162306a36Sopenharmony_ci for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { 80262306a36Sopenharmony_ci struct resource *res = &dev->resource[i]; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* If resource not allocated - skip it */ 80562306a36Sopenharmony_ci if (!res->start) 80662306a36Sopenharmony_ci continue; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci ** FIXME: this will result in whinging for devices 81062306a36Sopenharmony_ci ** that share expansion ROMs (think quad tulip), but 81162306a36Sopenharmony_ci ** isn't harmful. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci pci_claim_resource(dev, i); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci#ifdef FBB_SUPPORT 81762306a36Sopenharmony_ci /* 81862306a36Sopenharmony_ci ** If one device does not support FBB transfers, 81962306a36Sopenharmony_ci ** No one on the bus can be allowed to use them. 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ci (void) pci_read_config_word(dev, PCI_STATUS, &status); 82262306a36Sopenharmony_ci bus->bridge_ctl &= ~(status & PCI_STATUS_FAST_BACK); 82362306a36Sopenharmony_ci#endif 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* 82662306a36Sopenharmony_ci ** P2PB's have no IRQs. ignore them. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ci if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 82962306a36Sopenharmony_ci pcibios_init_bridge(dev); 83062306a36Sopenharmony_ci continue; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Adjust INTERRUPT_LINE for this dev */ 83462306a36Sopenharmony_ci iosapic_fixup_irq(ldev->iosapic_obj, dev); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci#ifdef FBB_SUPPORT 83862306a36Sopenharmony_ci/* FIXME/REVISIT - finish figuring out to set FBB on both 83962306a36Sopenharmony_ci** pci_setup_bridge() clobbers PCI_BRIDGE_CONTROL. 84062306a36Sopenharmony_ci** Can't fixup here anyway....garr... 84162306a36Sopenharmony_ci*/ 84262306a36Sopenharmony_ci if (fbb_enable) { 84362306a36Sopenharmony_ci if (bus->parent) { 84462306a36Sopenharmony_ci u8 control; 84562306a36Sopenharmony_ci /* enable on PPB */ 84662306a36Sopenharmony_ci (void) pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &control); 84762306a36Sopenharmony_ci (void) pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, control | PCI_STATUS_FAST_BACK); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci } else { 85062306a36Sopenharmony_ci /* enable on LBA */ 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci fbb_enable = PCI_COMMAND_FAST_BACK; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* Lastly enable FBB/PERR/SERR on all devices too */ 85662306a36Sopenharmony_ci list_for_each_entry(dev, &bus->devices, bus_list) { 85762306a36Sopenharmony_ci (void) pci_read_config_word(dev, PCI_COMMAND, &status); 85862306a36Sopenharmony_ci status |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | fbb_enable; 85962306a36Sopenharmony_ci (void) pci_write_config_word(dev, PCI_COMMAND, status); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci#endif 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic struct pci_bios_ops lba_bios_ops = { 86662306a36Sopenharmony_ci .init = lba_bios_init, 86762306a36Sopenharmony_ci .fixup_bus = lba_fixup_bus, 86862306a36Sopenharmony_ci}; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci/******************************************************* 87462306a36Sopenharmony_ci** 87562306a36Sopenharmony_ci** LBA Sprockets "I/O Port" Space Accessor Functions 87662306a36Sopenharmony_ci** 87762306a36Sopenharmony_ci** This set of accessor functions is intended for use with 87862306a36Sopenharmony_ci** "legacy firmware" (ie Sprockets on Allegro/Forte boxes). 87962306a36Sopenharmony_ci** 88062306a36Sopenharmony_ci** Many PCI devices don't require use of I/O port space (eg Tulip, 88162306a36Sopenharmony_ci** NCR720) since they export the same registers to both MMIO and 88262306a36Sopenharmony_ci** I/O port space. In general I/O port space is slower than 88362306a36Sopenharmony_ci** MMIO since drivers are designed so PIO writes can be posted. 88462306a36Sopenharmony_ci** 88562306a36Sopenharmony_ci********************************************************/ 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci#define LBA_PORT_IN(size, mask) \ 88862306a36Sopenharmony_cistatic u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \ 88962306a36Sopenharmony_ci{ \ 89062306a36Sopenharmony_ci u##size t; \ 89162306a36Sopenharmony_ci t = READ_REG##size(astro_iop_base + addr); \ 89262306a36Sopenharmony_ci DBG_PORT(" 0x%x\n", t); \ 89362306a36Sopenharmony_ci return (t); \ 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ciLBA_PORT_IN( 8, 3) 89762306a36Sopenharmony_ciLBA_PORT_IN(16, 2) 89862306a36Sopenharmony_ciLBA_PORT_IN(32, 0) 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci/* 90362306a36Sopenharmony_ci** BUG X4107: Ordering broken - DMA RD return can bypass PIO WR 90462306a36Sopenharmony_ci** 90562306a36Sopenharmony_ci** Fixed in Elroy 2.2. The READ_U32(..., LBA_FUNC_ID) below is 90662306a36Sopenharmony_ci** guarantee non-postable completion semantics - not avoid X4107. 90762306a36Sopenharmony_ci** The READ_U32 only guarantees the write data gets to elroy but 90862306a36Sopenharmony_ci** out to the PCI bus. We can't read stuff from I/O port space 90962306a36Sopenharmony_ci** since we don't know what has side-effects. Attempting to read 91062306a36Sopenharmony_ci** from configuration space would be suicidal given the number of 91162306a36Sopenharmony_ci** bugs in that elroy functionality. 91262306a36Sopenharmony_ci** 91362306a36Sopenharmony_ci** Description: 91462306a36Sopenharmony_ci** DMA read results can improperly pass PIO writes (X4107). The 91562306a36Sopenharmony_ci** result of this bug is that if a processor modifies a location in 91662306a36Sopenharmony_ci** memory after having issued PIO writes, the PIO writes are not 91762306a36Sopenharmony_ci** guaranteed to be completed before a PCI device is allowed to see 91862306a36Sopenharmony_ci** the modified data in a DMA read. 91962306a36Sopenharmony_ci** 92062306a36Sopenharmony_ci** Note that IKE bug X3719 in TR1 IKEs will result in the same 92162306a36Sopenharmony_ci** symptom. 92262306a36Sopenharmony_ci** 92362306a36Sopenharmony_ci** Workaround: 92462306a36Sopenharmony_ci** The workaround for this bug is to always follow a PIO write with 92562306a36Sopenharmony_ci** a PIO read to the same bus before starting DMA on that PCI bus. 92662306a36Sopenharmony_ci** 92762306a36Sopenharmony_ci*/ 92862306a36Sopenharmony_ci#define LBA_PORT_OUT(size, mask) \ 92962306a36Sopenharmony_cistatic void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ 93062306a36Sopenharmony_ci{ \ 93162306a36Sopenharmony_ci DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __func__, d, addr, val); \ 93262306a36Sopenharmony_ci WRITE_REG##size(val, astro_iop_base + addr); \ 93362306a36Sopenharmony_ci if (LBA_DEV(d)->hw_rev < 3) \ 93462306a36Sopenharmony_ci lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \ 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ciLBA_PORT_OUT( 8, 3) 93862306a36Sopenharmony_ciLBA_PORT_OUT(16, 2) 93962306a36Sopenharmony_ciLBA_PORT_OUT(32, 0) 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic struct pci_port_ops lba_astro_port_ops = { 94362306a36Sopenharmony_ci .inb = lba_astro_in8, 94462306a36Sopenharmony_ci .inw = lba_astro_in16, 94562306a36Sopenharmony_ci .inl = lba_astro_in32, 94662306a36Sopenharmony_ci .outb = lba_astro_out8, 94762306a36Sopenharmony_ci .outw = lba_astro_out16, 94862306a36Sopenharmony_ci .outl = lba_astro_out32 94962306a36Sopenharmony_ci}; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci#ifdef CONFIG_64BIT 95362306a36Sopenharmony_ci#define PIOP_TO_GMMIO(lba, addr) \ 95462306a36Sopenharmony_ci ((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3)) 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci/******************************************************* 95762306a36Sopenharmony_ci** 95862306a36Sopenharmony_ci** LBA PAT "I/O Port" Space Accessor Functions 95962306a36Sopenharmony_ci** 96062306a36Sopenharmony_ci** This set of accessor functions is intended for use with 96162306a36Sopenharmony_ci** "PAT PDC" firmware (ie Prelude/Rhapsody/Piranha boxes). 96262306a36Sopenharmony_ci** 96362306a36Sopenharmony_ci** This uses the PIOP space located in the first 64MB of GMMIO. 96462306a36Sopenharmony_ci** Each rope gets a full 64*KB* (ie 4 bytes per page) this way. 96562306a36Sopenharmony_ci** bits 1:0 stay the same. bits 15:2 become 25:12. 96662306a36Sopenharmony_ci** Then add the base and we can generate an I/O Port cycle. 96762306a36Sopenharmony_ci********************************************************/ 96862306a36Sopenharmony_ci#undef LBA_PORT_IN 96962306a36Sopenharmony_ci#define LBA_PORT_IN(size, mask) \ 97062306a36Sopenharmony_cistatic u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \ 97162306a36Sopenharmony_ci{ \ 97262306a36Sopenharmony_ci u##size t; \ 97362306a36Sopenharmony_ci DBG_PORT("%s(0x%p, 0x%x) ->", __func__, l, addr); \ 97462306a36Sopenharmony_ci t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \ 97562306a36Sopenharmony_ci DBG_PORT(" 0x%x\n", t); \ 97662306a36Sopenharmony_ci return (t); \ 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ciLBA_PORT_IN( 8, 3) 98062306a36Sopenharmony_ciLBA_PORT_IN(16, 2) 98162306a36Sopenharmony_ciLBA_PORT_IN(32, 0) 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci#undef LBA_PORT_OUT 98562306a36Sopenharmony_ci#define LBA_PORT_OUT(size, mask) \ 98662306a36Sopenharmony_cistatic void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \ 98762306a36Sopenharmony_ci{ \ 98862306a36Sopenharmony_ci void __iomem *where = PIOP_TO_GMMIO(LBA_DEV(l), addr); \ 98962306a36Sopenharmony_ci DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __func__, l, addr, val); \ 99062306a36Sopenharmony_ci WRITE_REG##size(val, where); \ 99162306a36Sopenharmony_ci /* flush the I/O down to the elroy at least */ \ 99262306a36Sopenharmony_ci lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \ 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ciLBA_PORT_OUT( 8, 3) 99662306a36Sopenharmony_ciLBA_PORT_OUT(16, 2) 99762306a36Sopenharmony_ciLBA_PORT_OUT(32, 0) 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistatic struct pci_port_ops lba_pat_port_ops = { 100162306a36Sopenharmony_ci .inb = lba_pat_in8, 100262306a36Sopenharmony_ci .inw = lba_pat_in16, 100362306a36Sopenharmony_ci .inl = lba_pat_in32, 100462306a36Sopenharmony_ci .outb = lba_pat_out8, 100562306a36Sopenharmony_ci .outw = lba_pat_out16, 100662306a36Sopenharmony_ci .outl = lba_pat_out32 100762306a36Sopenharmony_ci}; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci/* 101262306a36Sopenharmony_ci** make range information from PDC available to PCI subsystem. 101362306a36Sopenharmony_ci** We make the PDC call here in order to get the PCI bus range 101462306a36Sopenharmony_ci** numbers. The rest will get forwarded in pcibios_fixup_bus(). 101562306a36Sopenharmony_ci** We don't have a struct pci_bus assigned to us yet. 101662306a36Sopenharmony_ci*/ 101762306a36Sopenharmony_cistatic void 101862306a36Sopenharmony_cilba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci unsigned long bytecnt; 102162306a36Sopenharmony_ci long io_count __maybe_unused; 102262306a36Sopenharmony_ci long status; /* PDC return status */ 102362306a36Sopenharmony_ci long pa_count; 102462306a36Sopenharmony_ci pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell; /* PA_VIEW */ 102562306a36Sopenharmony_ci pdc_pat_cell_mod_maddr_block_t *io_pdc_cell; /* IO_VIEW */ 102662306a36Sopenharmony_ci int i; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci pa_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL); 102962306a36Sopenharmony_ci if (!pa_pdc_cell) 103062306a36Sopenharmony_ci return; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci io_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL); 103362306a36Sopenharmony_ci if (!io_pdc_cell) { 103462306a36Sopenharmony_ci kfree(pa_pdc_cell); 103562306a36Sopenharmony_ci return; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci /* return cell module (IO view) */ 103962306a36Sopenharmony_ci status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index, 104062306a36Sopenharmony_ci PA_VIEW, pa_pdc_cell); 104162306a36Sopenharmony_ci pa_count = pa_pdc_cell->mod[1]; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index, 104462306a36Sopenharmony_ci IO_VIEW, io_pdc_cell); 104562306a36Sopenharmony_ci io_count = io_pdc_cell->mod[1]; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* We've already done this once for device discovery...*/ 104862306a36Sopenharmony_ci if (status != PDC_OK) { 104962306a36Sopenharmony_ci panic("pdc_pat_cell_module() call failed for LBA!\n"); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (PAT_GET_ENTITY(pa_pdc_cell->mod_info) != PAT_ENTITY_LBA) { 105362306a36Sopenharmony_ci panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n"); 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* 105762306a36Sopenharmony_ci ** Inspect the resources PAT tells us about 105862306a36Sopenharmony_ci */ 105962306a36Sopenharmony_ci for (i = 0; i < pa_count; i++) { 106062306a36Sopenharmony_ci struct { 106162306a36Sopenharmony_ci unsigned long type; 106262306a36Sopenharmony_ci unsigned long start; 106362306a36Sopenharmony_ci unsigned long end; /* aka finish */ 106462306a36Sopenharmony_ci } *p, *io; 106562306a36Sopenharmony_ci struct resource *r; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci p = (void *) &(pa_pdc_cell->mod[2+i*3]); 106862306a36Sopenharmony_ci io = (void *) &(io_pdc_cell->mod[2+i*3]); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Convert the PAT range data to PCI "struct resource" */ 107162306a36Sopenharmony_ci switch(p->type & 0xff) { 107262306a36Sopenharmony_ci case PAT_PBNUM: 107362306a36Sopenharmony_ci lba_dev->hba.bus_num.start = p->start; 107462306a36Sopenharmony_ci lba_dev->hba.bus_num.end = p->end; 107562306a36Sopenharmony_ci lba_dev->hba.bus_num.flags = IORESOURCE_BUS; 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci case PAT_LMMIO: 107962306a36Sopenharmony_ci /* used to fix up pre-initialized MEM BARs */ 108062306a36Sopenharmony_ci if (!lba_dev->hba.lmmio_space.flags) { 108162306a36Sopenharmony_ci unsigned long lba_len; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci lba_len = ~READ_REG32(lba_dev->hba.base_addr 108462306a36Sopenharmony_ci + LBA_LMMIO_MASK); 108562306a36Sopenharmony_ci if ((p->end - p->start) != lba_len) 108662306a36Sopenharmony_ci p->end = extend_lmmio_len(p->start, 108762306a36Sopenharmony_ci p->end, lba_len); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci sprintf(lba_dev->hba.lmmio_name, 109062306a36Sopenharmony_ci "PCI%02x LMMIO", 109162306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 109262306a36Sopenharmony_ci lba_dev->hba.lmmio_space_offset = p->start - 109362306a36Sopenharmony_ci io->start; 109462306a36Sopenharmony_ci r = &lba_dev->hba.lmmio_space; 109562306a36Sopenharmony_ci r->name = lba_dev->hba.lmmio_name; 109662306a36Sopenharmony_ci } else if (!lba_dev->hba.elmmio_space.flags) { 109762306a36Sopenharmony_ci sprintf(lba_dev->hba.elmmio_name, 109862306a36Sopenharmony_ci "PCI%02x ELMMIO", 109962306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 110062306a36Sopenharmony_ci r = &lba_dev->hba.elmmio_space; 110162306a36Sopenharmony_ci r->name = lba_dev->hba.elmmio_name; 110262306a36Sopenharmony_ci } else { 110362306a36Sopenharmony_ci printk(KERN_WARNING MODULE_NAME 110462306a36Sopenharmony_ci " only supports 2 LMMIO resources!\n"); 110562306a36Sopenharmony_ci break; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci r->start = p->start; 110962306a36Sopenharmony_ci r->end = p->end; 111062306a36Sopenharmony_ci r->flags = IORESOURCE_MEM; 111162306a36Sopenharmony_ci r->parent = r->sibling = r->child = NULL; 111262306a36Sopenharmony_ci break; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci case PAT_GMMIO: 111562306a36Sopenharmony_ci /* MMIO space > 4GB phys addr; for 64-bit BAR */ 111662306a36Sopenharmony_ci sprintf(lba_dev->hba.gmmio_name, "PCI%02x GMMIO", 111762306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 111862306a36Sopenharmony_ci r = &lba_dev->hba.gmmio_space; 111962306a36Sopenharmony_ci r->name = lba_dev->hba.gmmio_name; 112062306a36Sopenharmony_ci r->start = p->start; 112162306a36Sopenharmony_ci r->end = p->end; 112262306a36Sopenharmony_ci r->flags = IORESOURCE_MEM; 112362306a36Sopenharmony_ci r->parent = r->sibling = r->child = NULL; 112462306a36Sopenharmony_ci break; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci case PAT_NPIOP: 112762306a36Sopenharmony_ci printk(KERN_WARNING MODULE_NAME 112862306a36Sopenharmony_ci " range[%d] : ignoring NPIOP (0x%lx)\n", 112962306a36Sopenharmony_ci i, p->start); 113062306a36Sopenharmony_ci break; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci case PAT_PIOP: 113362306a36Sopenharmony_ci /* 113462306a36Sopenharmony_ci ** Postable I/O port space is per PCI host adapter. 113562306a36Sopenharmony_ci ** base of 64MB PIOP region 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_ci lba_dev->iop_base = ioremap(p->start, 64 * 1024 * 1024); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci sprintf(lba_dev->hba.io_name, "PCI%02x Ports", 114062306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 114162306a36Sopenharmony_ci r = &lba_dev->hba.io_space; 114262306a36Sopenharmony_ci r->name = lba_dev->hba.io_name; 114362306a36Sopenharmony_ci r->start = HBA_PORT_BASE(lba_dev->hba.hba_num); 114462306a36Sopenharmony_ci r->end = r->start + HBA_PORT_SPACE_SIZE - 1; 114562306a36Sopenharmony_ci r->flags = IORESOURCE_IO; 114662306a36Sopenharmony_ci r->parent = r->sibling = r->child = NULL; 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci default: 115062306a36Sopenharmony_ci printk(KERN_WARNING MODULE_NAME 115162306a36Sopenharmony_ci " range[%d] : unknown pat range type (0x%lx)\n", 115262306a36Sopenharmony_ci i, p->type & 0xff); 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci kfree(pa_pdc_cell); 115862306a36Sopenharmony_ci kfree(io_pdc_cell); 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci#else 116162306a36Sopenharmony_ci/* keep compiler from complaining about missing declarations */ 116262306a36Sopenharmony_ci#define lba_pat_port_ops lba_astro_port_ops 116362306a36Sopenharmony_ci#define lba_pat_resources(pa_dev, lba_dev) 116462306a36Sopenharmony_ci#endif /* CONFIG_64BIT */ 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_cistatic void 116862306a36Sopenharmony_cilba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci struct resource *r; 117162306a36Sopenharmony_ci int lba_num; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci lba_dev->hba.lmmio_space_offset = PCI_F_EXTEND; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* 117662306a36Sopenharmony_ci ** With "legacy" firmware, the lowest byte of FW_SCRATCH 117762306a36Sopenharmony_ci ** represents bus->secondary and the second byte represents 117862306a36Sopenharmony_ci ** bus->subsidiary (i.e. highest PPB programmed by firmware). 117962306a36Sopenharmony_ci ** PCI bus walk *should* end up with the same result. 118062306a36Sopenharmony_ci ** FIXME: But we don't have sanity checks in PCI or LBA. 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci lba_num = READ_REG32(lba_dev->hba.base_addr + LBA_FW_SCRATCH); 118362306a36Sopenharmony_ci r = &(lba_dev->hba.bus_num); 118462306a36Sopenharmony_ci r->name = "LBA PCI Busses"; 118562306a36Sopenharmony_ci r->start = lba_num & 0xff; 118662306a36Sopenharmony_ci r->end = (lba_num>>8) & 0xff; 118762306a36Sopenharmony_ci r->flags = IORESOURCE_BUS; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* Set up local PCI Bus resources - we don't need them for 119062306a36Sopenharmony_ci ** Legacy boxes but it's nice to see in /proc/iomem. 119162306a36Sopenharmony_ci */ 119262306a36Sopenharmony_ci r = &(lba_dev->hba.lmmio_space); 119362306a36Sopenharmony_ci sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO", 119462306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 119562306a36Sopenharmony_ci r->name = lba_dev->hba.lmmio_name; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci#if 1 119862306a36Sopenharmony_ci /* We want the CPU -> IO routing of addresses. 119962306a36Sopenharmony_ci * The SBA BASE/MASK registers control CPU -> IO routing. 120062306a36Sopenharmony_ci * Ask SBA what is routed to this rope/LBA. 120162306a36Sopenharmony_ci */ 120262306a36Sopenharmony_ci sba_distributed_lmmio(pa_dev, r); 120362306a36Sopenharmony_ci#else 120462306a36Sopenharmony_ci /* 120562306a36Sopenharmony_ci * The LBA BASE/MASK registers control IO -> System routing. 120662306a36Sopenharmony_ci * 120762306a36Sopenharmony_ci * The following code works but doesn't get us what we want. 120862306a36Sopenharmony_ci * Well, only because firmware (v5.0) on C3000 doesn't program 120962306a36Sopenharmony_ci * the LBA BASE/MASE registers to be the exact inverse of 121062306a36Sopenharmony_ci * the corresponding SBA registers. Other Astro/Pluto 121162306a36Sopenharmony_ci * based platform firmware may do it right. 121262306a36Sopenharmony_ci * 121362306a36Sopenharmony_ci * Should someone want to mess with MSI, they may need to 121462306a36Sopenharmony_ci * reprogram LBA BASE/MASK registers. Thus preserve the code 121562306a36Sopenharmony_ci * below until MSI is known to work on C3000/A500/N4000/RP3440. 121662306a36Sopenharmony_ci * 121762306a36Sopenharmony_ci * Using the code below, /proc/iomem shows: 121862306a36Sopenharmony_ci * ... 121962306a36Sopenharmony_ci * f0000000-f0ffffff : PCI00 LMMIO 122062306a36Sopenharmony_ci * f05d0000-f05d0000 : lcd_data 122162306a36Sopenharmony_ci * f05d0008-f05d0008 : lcd_cmd 122262306a36Sopenharmony_ci * f1000000-f1ffffff : PCI01 LMMIO 122362306a36Sopenharmony_ci * f4000000-f4ffffff : PCI02 LMMIO 122462306a36Sopenharmony_ci * f4000000-f4001fff : sym53c8xx 122562306a36Sopenharmony_ci * f4002000-f4003fff : sym53c8xx 122662306a36Sopenharmony_ci * f4004000-f40043ff : sym53c8xx 122762306a36Sopenharmony_ci * f4005000-f40053ff : sym53c8xx 122862306a36Sopenharmony_ci * f4007000-f4007fff : ohci_hcd 122962306a36Sopenharmony_ci * f4008000-f40083ff : tulip 123062306a36Sopenharmony_ci * f6000000-f6ffffff : PCI03 LMMIO 123162306a36Sopenharmony_ci * f8000000-fbffffff : PCI00 ELMMIO 123262306a36Sopenharmony_ci * fa100000-fa4fffff : stifb mmio 123362306a36Sopenharmony_ci * fb000000-fb1fffff : stifb fb 123462306a36Sopenharmony_ci * 123562306a36Sopenharmony_ci * But everything listed under PCI02 actually lives under PCI00. 123662306a36Sopenharmony_ci * This is clearly wrong. 123762306a36Sopenharmony_ci * 123862306a36Sopenharmony_ci * Asking SBA how things are routed tells the correct story: 123962306a36Sopenharmony_ci * LMMIO_BASE/MASK/ROUTE f4000001 fc000000 00000000 124062306a36Sopenharmony_ci * DIR0_BASE/MASK/ROUTE fa000001 fe000000 00000006 124162306a36Sopenharmony_ci * DIR1_BASE/MASK/ROUTE f9000001 ff000000 00000004 124262306a36Sopenharmony_ci * DIR2_BASE/MASK/ROUTE f0000000 fc000000 00000000 124362306a36Sopenharmony_ci * DIR3_BASE/MASK/ROUTE f0000000 fc000000 00000000 124462306a36Sopenharmony_ci * 124562306a36Sopenharmony_ci * Which looks like this in /proc/iomem: 124662306a36Sopenharmony_ci * f4000000-f47fffff : PCI00 LMMIO 124762306a36Sopenharmony_ci * f4000000-f4001fff : sym53c8xx 124862306a36Sopenharmony_ci * ...[deteled core devices - same as above]... 124962306a36Sopenharmony_ci * f4008000-f40083ff : tulip 125062306a36Sopenharmony_ci * f4800000-f4ffffff : PCI01 LMMIO 125162306a36Sopenharmony_ci * f6000000-f67fffff : PCI02 LMMIO 125262306a36Sopenharmony_ci * f7000000-f77fffff : PCI03 LMMIO 125362306a36Sopenharmony_ci * f9000000-f9ffffff : PCI02 ELMMIO 125462306a36Sopenharmony_ci * fa000000-fbffffff : PCI03 ELMMIO 125562306a36Sopenharmony_ci * fa100000-fa4fffff : stifb mmio 125662306a36Sopenharmony_ci * fb000000-fb1fffff : stifb fb 125762306a36Sopenharmony_ci * 125862306a36Sopenharmony_ci * ie all Built-in core are under now correctly under PCI00. 125962306a36Sopenharmony_ci * The "PCI02 ELMMIO" directed range is for: 126062306a36Sopenharmony_ci * +-[02]---03.0 3Dfx Interactive, Inc. Voodoo 2 126162306a36Sopenharmony_ci * 126262306a36Sopenharmony_ci * All is well now. 126362306a36Sopenharmony_ci */ 126462306a36Sopenharmony_ci r->start = READ_REG32(lba_dev->hba.base_addr + LBA_LMMIO_BASE); 126562306a36Sopenharmony_ci if (r->start & 1) { 126662306a36Sopenharmony_ci unsigned long rsize; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci r->flags = IORESOURCE_MEM; 126962306a36Sopenharmony_ci /* mmio_mask also clears Enable bit */ 127062306a36Sopenharmony_ci r->start &= mmio_mask; 127162306a36Sopenharmony_ci r->start = PCI_HOST_ADDR(&lba_dev->hba, r->start); 127262306a36Sopenharmony_ci rsize = ~ READ_REG32(lba_dev->hba.base_addr + LBA_LMMIO_MASK); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* 127562306a36Sopenharmony_ci ** Each rope only gets part of the distributed range. 127662306a36Sopenharmony_ci ** Adjust "window" for this rope. 127762306a36Sopenharmony_ci */ 127862306a36Sopenharmony_ci rsize /= ROPES_PER_IOC; 127962306a36Sopenharmony_ci r->start += (rsize + 1) * LBA_NUM(pa_dev->hpa.start); 128062306a36Sopenharmony_ci r->end = r->start + rsize; 128162306a36Sopenharmony_ci } else { 128262306a36Sopenharmony_ci r->end = r->start = 0; /* Not enabled. */ 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci#endif 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* 128762306a36Sopenharmony_ci ** "Directed" ranges are used when the "distributed range" isn't 128862306a36Sopenharmony_ci ** sufficient for all devices below a given LBA. Typically devices 128962306a36Sopenharmony_ci ** like graphics cards or X25 may need a directed range when the 129062306a36Sopenharmony_ci ** bus has multiple slots (ie multiple devices) or the device 129162306a36Sopenharmony_ci ** needs more than the typical 4 or 8MB a distributed range offers. 129262306a36Sopenharmony_ci ** 129362306a36Sopenharmony_ci ** The main reason for ignoring it now frigging complications. 129462306a36Sopenharmony_ci ** Directed ranges may overlap (and have precedence) over 129562306a36Sopenharmony_ci ** distributed ranges. Or a distributed range assigned to a unused 129662306a36Sopenharmony_ci ** rope may be used by a directed range on a different rope. 129762306a36Sopenharmony_ci ** Support for graphics devices may require fixing this 129862306a36Sopenharmony_ci ** since they may be assigned a directed range which overlaps 129962306a36Sopenharmony_ci ** an existing (but unused portion of) distributed range. 130062306a36Sopenharmony_ci */ 130162306a36Sopenharmony_ci r = &(lba_dev->hba.elmmio_space); 130262306a36Sopenharmony_ci sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO", 130362306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 130462306a36Sopenharmony_ci r->name = lba_dev->hba.elmmio_name; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci#if 1 130762306a36Sopenharmony_ci /* See comment which precedes call to sba_directed_lmmio() */ 130862306a36Sopenharmony_ci sba_directed_lmmio(pa_dev, r); 130962306a36Sopenharmony_ci#else 131062306a36Sopenharmony_ci r->start = READ_REG32(lba_dev->hba.base_addr + LBA_ELMMIO_BASE); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if (r->start & 1) { 131362306a36Sopenharmony_ci unsigned long rsize; 131462306a36Sopenharmony_ci r->flags = IORESOURCE_MEM; 131562306a36Sopenharmony_ci /* mmio_mask also clears Enable bit */ 131662306a36Sopenharmony_ci r->start &= mmio_mask; 131762306a36Sopenharmony_ci r->start = PCI_HOST_ADDR(&lba_dev->hba, r->start); 131862306a36Sopenharmony_ci rsize = READ_REG32(lba_dev->hba.base_addr + LBA_ELMMIO_MASK); 131962306a36Sopenharmony_ci r->end = r->start + ~rsize; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci#endif 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci r = &(lba_dev->hba.io_space); 132462306a36Sopenharmony_ci sprintf(lba_dev->hba.io_name, "PCI%02x Ports", 132562306a36Sopenharmony_ci (int)lba_dev->hba.bus_num.start); 132662306a36Sopenharmony_ci r->name = lba_dev->hba.io_name; 132762306a36Sopenharmony_ci r->flags = IORESOURCE_IO; 132862306a36Sopenharmony_ci r->start = READ_REG32(lba_dev->hba.base_addr + LBA_IOS_BASE) & ~1L; 132962306a36Sopenharmony_ci r->end = r->start + (READ_REG32(lba_dev->hba.base_addr + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1)); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* Virtualize the I/O Port space ranges */ 133262306a36Sopenharmony_ci lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num); 133362306a36Sopenharmony_ci r->start |= lba_num; 133462306a36Sopenharmony_ci r->end |= lba_num; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci/************************************************************************** 133962306a36Sopenharmony_ci** 134062306a36Sopenharmony_ci** LBA initialization code (HW and SW) 134162306a36Sopenharmony_ci** 134262306a36Sopenharmony_ci** o identify LBA chip itself 134362306a36Sopenharmony_ci** o initialize LBA chip modes (HardFail) 134462306a36Sopenharmony_ci** o FIXME: initialize DMA hints for reasonable defaults 134562306a36Sopenharmony_ci** o enable configuration functions 134662306a36Sopenharmony_ci** o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked) 134762306a36Sopenharmony_ci** 134862306a36Sopenharmony_ci**************************************************************************/ 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int __init 135162306a36Sopenharmony_cilba_hw_init(struct lba_device *d) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci u32 stat; 135462306a36Sopenharmony_ci u32 bus_reset; /* PDC_PAT_BUG */ 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci#if 0 135762306a36Sopenharmony_ci printk(KERN_DEBUG "LBA %lx STAT_CTL %Lx ERROR_CFG %Lx STATUS %Lx DMA_CTL %Lx\n", 135862306a36Sopenharmony_ci d->hba.base_addr, 135962306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_STAT_CTL), 136062306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_ERROR_CONFIG), 136162306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_ERROR_STATUS), 136262306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_DMA_CTL) ); 136362306a36Sopenharmony_ci printk(KERN_DEBUG " ARB mask %Lx pri %Lx mode %Lx mtlt %Lx\n", 136462306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_ARB_MASK), 136562306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_ARB_PRI), 136662306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_ARB_MODE), 136762306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) ); 136862306a36Sopenharmony_ci printk(KERN_DEBUG " HINT cfg 0x%Lx\n", 136962306a36Sopenharmony_ci READ_REG64(d->hba.base_addr + LBA_HINT_CFG)); 137062306a36Sopenharmony_ci printk(KERN_DEBUG " HINT reg "); 137162306a36Sopenharmony_ci { int i; 137262306a36Sopenharmony_ci for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8) 137362306a36Sopenharmony_ci printk(" %Lx", READ_REG64(d->hba.base_addr + i)); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci printk("\n"); 137662306a36Sopenharmony_ci#endif /* DEBUG_LBA_PAT */ 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci#ifdef CONFIG_64BIT 137962306a36Sopenharmony_ci/* 138062306a36Sopenharmony_ci * FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support 138162306a36Sopenharmony_ci * Only N-Class and up can really make use of Get slot status. 138262306a36Sopenharmony_ci * maybe L-class too but I've never played with it there. 138362306a36Sopenharmony_ci */ 138462306a36Sopenharmony_ci#endif 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */ 138762306a36Sopenharmony_ci bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1; 138862306a36Sopenharmony_ci if (bus_reset) { 138962306a36Sopenharmony_ci printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n"); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); 139362306a36Sopenharmony_ci if (stat & LBA_SMART_MODE) { 139462306a36Sopenharmony_ci printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n"); 139562306a36Sopenharmony_ci stat &= ~LBA_SMART_MODE; 139662306a36Sopenharmony_ci WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG); 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* 140162306a36Sopenharmony_ci * Hard Fail vs. Soft Fail on PCI "Master Abort". 140262306a36Sopenharmony_ci * 140362306a36Sopenharmony_ci * "Master Abort" means the MMIO transaction timed out - usually due to 140462306a36Sopenharmony_ci * the device not responding to an MMIO read. We would like HF to be 140562306a36Sopenharmony_ci * enabled to find driver problems, though it means the system will 140662306a36Sopenharmony_ci * crash with a HPMC. 140762306a36Sopenharmony_ci * 140862306a36Sopenharmony_ci * In SoftFail mode "~0L" is returned as a result of a timeout on the 140962306a36Sopenharmony_ci * pci bus. This is like how PCI busses on x86 and most other 141062306a36Sopenharmony_ci * architectures behave. In order to increase compatibility with 141162306a36Sopenharmony_ci * existing (x86) PCI hardware and existing Linux drivers we enable 141262306a36Sopenharmony_ci * Soft Faul mode on PA-RISC now too. 141362306a36Sopenharmony_ci */ 141462306a36Sopenharmony_ci stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); 141562306a36Sopenharmony_ci#if defined(ENABLE_HARDFAIL) 141662306a36Sopenharmony_ci WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); 141762306a36Sopenharmony_ci#else 141862306a36Sopenharmony_ci WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); 141962306a36Sopenharmony_ci#endif 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* 142262306a36Sopenharmony_ci ** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal 142362306a36Sopenharmony_ci ** if it's not already set. If we just cleared the PCI Bus Reset 142462306a36Sopenharmony_ci ** signal, wait a bit for the PCI devices to recover and setup. 142562306a36Sopenharmony_ci */ 142662306a36Sopenharmony_ci if (bus_reset) 142762306a36Sopenharmony_ci mdelay(pci_post_reset_delay); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) { 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci ** PDC_PAT_BUG: PDC rev 40.48 on L2000. 143262306a36Sopenharmony_ci ** B2000/C3600/J6000 also have this problem? 143362306a36Sopenharmony_ci ** 143462306a36Sopenharmony_ci ** Elroys with hot pluggable slots don't get configured 143562306a36Sopenharmony_ci ** correctly if the slot is empty. ARB_MASK is set to 0 143662306a36Sopenharmony_ci ** and we can't master transactions on the bus if it's 143762306a36Sopenharmony_ci ** not at least one. 0x3 enables elroy and first slot. 143862306a36Sopenharmony_ci */ 143962306a36Sopenharmony_ci printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n"); 144062306a36Sopenharmony_ci WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK); 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci /* 144462306a36Sopenharmony_ci ** FIXME: Hint registers are programmed with default hint 144562306a36Sopenharmony_ci ** values by firmware. Hints should be sane even if we 144662306a36Sopenharmony_ci ** can't reprogram them the way drivers want. 144762306a36Sopenharmony_ci */ 144862306a36Sopenharmony_ci return 0; 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci/* 145262306a36Sopenharmony_ci * Unfortunately, when firmware numbers busses, it doesn't take into account 145362306a36Sopenharmony_ci * Cardbus bridges. So we have to renumber the busses to suit ourselves. 145462306a36Sopenharmony_ci * Elroy/Mercury don't actually know what bus number they're attached to; 145562306a36Sopenharmony_ci * we use bus 0 to indicate the directly attached bus and any other bus 145662306a36Sopenharmony_ci * number will be taken care of by the PCI-PCI bridge. 145762306a36Sopenharmony_ci */ 145862306a36Sopenharmony_cistatic unsigned int lba_next_bus = 0; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci/* 146162306a36Sopenharmony_ci * Determine if lba should claim this chip (return 0) or not (return 1). 146262306a36Sopenharmony_ci * If so, initialize the chip and tell other partners in crime they 146362306a36Sopenharmony_ci * have work to do. 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_cistatic int __init 146662306a36Sopenharmony_cilba_driver_probe(struct parisc_device *dev) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct lba_device *lba_dev; 146962306a36Sopenharmony_ci LIST_HEAD(resources); 147062306a36Sopenharmony_ci struct pci_bus *lba_bus; 147162306a36Sopenharmony_ci struct pci_ops *cfg_ops; 147262306a36Sopenharmony_ci u32 func_class; 147362306a36Sopenharmony_ci void *tmp_obj; 147462306a36Sopenharmony_ci char *version; 147562306a36Sopenharmony_ci void __iomem *addr; 147662306a36Sopenharmony_ci int max; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci addr = ioremap(dev->hpa.start, 4096); 147962306a36Sopenharmony_ci if (addr == NULL) 148062306a36Sopenharmony_ci return -ENOMEM; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* Read HW Rev First */ 148362306a36Sopenharmony_ci func_class = READ_REG32(addr + LBA_FCLASS); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci if (IS_ELROY(dev)) { 148662306a36Sopenharmony_ci func_class &= 0xf; 148762306a36Sopenharmony_ci switch (func_class) { 148862306a36Sopenharmony_ci case 0: version = "TR1.0"; break; 148962306a36Sopenharmony_ci case 1: version = "TR2.0"; break; 149062306a36Sopenharmony_ci case 2: version = "TR2.1"; break; 149162306a36Sopenharmony_ci case 3: version = "TR2.2"; break; 149262306a36Sopenharmony_ci case 4: version = "TR3.0"; break; 149362306a36Sopenharmony_ci case 5: version = "TR4.0"; break; 149462306a36Sopenharmony_ci default: version = "TR4+"; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n", 149862306a36Sopenharmony_ci version, func_class & 0xf, (long)dev->hpa.start); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (func_class < 2) { 150162306a36Sopenharmony_ci printk(KERN_WARNING "Can't support LBA older than " 150262306a36Sopenharmony_ci "TR2.1 - continuing under adversity.\n"); 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci#if 0 150662306a36Sopenharmony_ci/* Elroy TR4.0 should work with simple algorithm. 150762306a36Sopenharmony_ci But it doesn't. Still missing something. *sigh* 150862306a36Sopenharmony_ci*/ 150962306a36Sopenharmony_ci if (func_class > 4) { 151062306a36Sopenharmony_ci cfg_ops = &mercury_cfg_ops; 151162306a36Sopenharmony_ci } else 151262306a36Sopenharmony_ci#endif 151362306a36Sopenharmony_ci { 151462306a36Sopenharmony_ci cfg_ops = &elroy_cfg_ops; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci } else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) { 151862306a36Sopenharmony_ci int major, minor; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci func_class &= 0xff; 152162306a36Sopenharmony_ci major = func_class >> 4, minor = func_class & 0xf; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* We could use one printk for both Elroy and Mercury, 152462306a36Sopenharmony_ci * but for the mask for func_class. 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_ci printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n", 152762306a36Sopenharmony_ci IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major, 152862306a36Sopenharmony_ci minor, func_class, (long)dev->hpa.start); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci cfg_ops = &mercury_cfg_ops; 153162306a36Sopenharmony_ci } else { 153262306a36Sopenharmony_ci printk(KERN_ERR "Unknown LBA found at 0x%lx\n", 153362306a36Sopenharmony_ci (long)dev->hpa.start); 153462306a36Sopenharmony_ci return -ENODEV; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* Tell I/O SAPIC driver we have a IRQ handler/region. */ 153862306a36Sopenharmony_ci tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE, 153962306a36Sopenharmony_ci addr + LBA_IOSAPIC_BASE); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't 154262306a36Sopenharmony_ci ** have an IRT entry will get NULL back from iosapic code. 154362306a36Sopenharmony_ci */ 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci lba_dev = kzalloc(sizeof(struct lba_device), GFP_KERNEL); 154662306a36Sopenharmony_ci if (!lba_dev) { 154762306a36Sopenharmony_ci printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n"); 154862306a36Sopenharmony_ci return(1); 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci /* ---------- First : initialize data we already have --------- */ 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci lba_dev->hw_rev = func_class; 155562306a36Sopenharmony_ci lba_dev->hba.base_addr = addr; 155662306a36Sopenharmony_ci lba_dev->hba.dev = dev; 155762306a36Sopenharmony_ci lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ 155862306a36Sopenharmony_ci lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */ 155962306a36Sopenharmony_ci parisc_set_drvdata(dev, lba_dev); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci /* ------------ Second : initialize common stuff ---------- */ 156262306a36Sopenharmony_ci pci_bios = &lba_bios_ops; 156362306a36Sopenharmony_ci pcibios_register_hba(&lba_dev->hba); 156462306a36Sopenharmony_ci spin_lock_init(&lba_dev->lba_lock); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (lba_hw_init(lba_dev)) 156762306a36Sopenharmony_ci return(1); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* ---------- Third : setup I/O Port and MMIO resources --------- */ 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (is_pdc_pat()) { 157262306a36Sopenharmony_ci /* PDC PAT firmware uses PIOP region of GMMIO space. */ 157362306a36Sopenharmony_ci pci_port = &lba_pat_port_ops; 157462306a36Sopenharmony_ci /* Go ask PDC PAT what resources this LBA has */ 157562306a36Sopenharmony_ci lba_pat_resources(dev, lba_dev); 157662306a36Sopenharmony_ci } else { 157762306a36Sopenharmony_ci if (!astro_iop_base) { 157862306a36Sopenharmony_ci /* Sprockets PDC uses NPIOP region */ 157962306a36Sopenharmony_ci astro_iop_base = ioremap(LBA_PORT_BASE, 64 * 1024); 158062306a36Sopenharmony_ci pci_port = &lba_astro_port_ops; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci /* Poke the chip a bit for /proc output */ 158462306a36Sopenharmony_ci lba_legacy_resources(dev, lba_dev); 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci if (lba_dev->hba.bus_num.start < lba_next_bus) 158862306a36Sopenharmony_ci lba_dev->hba.bus_num.start = lba_next_bus; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci /* Overlaps with elmmio can (and should) fail here. 159162306a36Sopenharmony_ci * We will prune (or ignore) the distributed range. 159262306a36Sopenharmony_ci * 159362306a36Sopenharmony_ci * FIXME: SBA code should register all elmmio ranges first. 159462306a36Sopenharmony_ci * that would take care of elmmio ranges routed 159562306a36Sopenharmony_ci * to a different rope (already discovered) from 159662306a36Sopenharmony_ci * getting registered *after* LBA code has already 159762306a36Sopenharmony_ci * registered it's distributed lmmio range. 159862306a36Sopenharmony_ci */ 159962306a36Sopenharmony_ci if (truncate_pat_collision(&iomem_resource, 160062306a36Sopenharmony_ci &(lba_dev->hba.lmmio_space))) { 160162306a36Sopenharmony_ci printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n", 160262306a36Sopenharmony_ci (long)lba_dev->hba.lmmio_space.start, 160362306a36Sopenharmony_ci (long)lba_dev->hba.lmmio_space.end); 160462306a36Sopenharmony_ci lba_dev->hba.lmmio_space.flags = 0; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci pci_add_resource_offset(&resources, &lba_dev->hba.io_space, 160862306a36Sopenharmony_ci HBA_PORT_BASE(lba_dev->hba.hba_num)); 160962306a36Sopenharmony_ci if (lba_dev->hba.elmmio_space.flags) 161062306a36Sopenharmony_ci pci_add_resource_offset(&resources, &lba_dev->hba.elmmio_space, 161162306a36Sopenharmony_ci lba_dev->hba.lmmio_space_offset); 161262306a36Sopenharmony_ci if (lba_dev->hba.lmmio_space.flags) 161362306a36Sopenharmony_ci pci_add_resource_offset(&resources, &lba_dev->hba.lmmio_space, 161462306a36Sopenharmony_ci lba_dev->hba.lmmio_space_offset); 161562306a36Sopenharmony_ci if (lba_dev->hba.gmmio_space.flags) { 161662306a36Sopenharmony_ci /* Not registering GMMIO space - according to docs it's not 161762306a36Sopenharmony_ci * even used on HP-UX. */ 161862306a36Sopenharmony_ci /* pci_add_resource(&resources, &lba_dev->hba.gmmio_space); */ 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci pci_add_resource(&resources, &lba_dev->hba.bus_num); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci dev->dev.platform_data = lba_dev; 162462306a36Sopenharmony_ci lba_bus = lba_dev->hba.hba_bus = 162562306a36Sopenharmony_ci pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start, 162662306a36Sopenharmony_ci cfg_ops, NULL, &resources); 162762306a36Sopenharmony_ci if (!lba_bus) { 162862306a36Sopenharmony_ci pci_free_resource_list(&resources); 162962306a36Sopenharmony_ci return 0; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci max = pci_scan_child_bus(lba_bus); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci /* This is in lieu of calling pci_assign_unassigned_resources() */ 163562306a36Sopenharmony_ci if (is_pdc_pat()) { 163662306a36Sopenharmony_ci /* assign resources to un-initialized devices */ 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci DBG_PAT("LBA pci_bus_size_bridges()\n"); 163962306a36Sopenharmony_ci pci_bus_size_bridges(lba_bus); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci DBG_PAT("LBA pci_bus_assign_resources()\n"); 164262306a36Sopenharmony_ci pci_bus_assign_resources(lba_bus); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci#ifdef DEBUG_LBA_PAT 164562306a36Sopenharmony_ci DBG_PAT("\nLBA PIOP resource tree\n"); 164662306a36Sopenharmony_ci lba_dump_res(&lba_dev->hba.io_space, 2); 164762306a36Sopenharmony_ci DBG_PAT("\nLBA LMMIO resource tree\n"); 164862306a36Sopenharmony_ci lba_dump_res(&lba_dev->hba.lmmio_space, 2); 164962306a36Sopenharmony_ci#endif 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* 165362306a36Sopenharmony_ci ** Once PCI register ops has walked the bus, access to config 165462306a36Sopenharmony_ci ** space is restricted. Avoids master aborts on config cycles. 165562306a36Sopenharmony_ci ** Early LBA revs go fatal on *any* master abort. 165662306a36Sopenharmony_ci */ 165762306a36Sopenharmony_ci if (cfg_ops == &elroy_cfg_ops) { 165862306a36Sopenharmony_ci lba_dev->flags |= LBA_FLAG_SKIP_PROBE; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci lba_next_bus = max + 1; 166262306a36Sopenharmony_ci pci_bus_add_devices(lba_bus); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* Whew! Finally done! Tell services we got this one covered. */ 166562306a36Sopenharmony_ci return 0; 166662306a36Sopenharmony_ci} 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_cistatic const struct parisc_device_id lba_tbl[] __initconst = { 166962306a36Sopenharmony_ci { HPHW_BRIDGE, HVERSION_REV_ANY_ID, ELROY_HVERS, 0xa }, 167062306a36Sopenharmony_ci { HPHW_BRIDGE, HVERSION_REV_ANY_ID, MERCURY_HVERS, 0xa }, 167162306a36Sopenharmony_ci { HPHW_BRIDGE, HVERSION_REV_ANY_ID, QUICKSILVER_HVERS, 0xa }, 167262306a36Sopenharmony_ci { 0, } 167362306a36Sopenharmony_ci}; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic struct parisc_driver lba_driver __refdata = { 167662306a36Sopenharmony_ci .name = MODULE_NAME, 167762306a36Sopenharmony_ci .id_table = lba_tbl, 167862306a36Sopenharmony_ci .probe = lba_driver_probe, 167962306a36Sopenharmony_ci}; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci/* 168262306a36Sopenharmony_ci** One time initialization to let the world know the LBA was found. 168362306a36Sopenharmony_ci** Must be called exactly once before pci_init(). 168462306a36Sopenharmony_ci*/ 168562306a36Sopenharmony_cistatic int __init lba_init(void) 168662306a36Sopenharmony_ci{ 168762306a36Sopenharmony_ci return register_parisc_driver(&lba_driver); 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ciarch_initcall(lba_init); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci/* 169262306a36Sopenharmony_ci** Initialize the IBASE/IMASK registers for LBA (Elroy). 169362306a36Sopenharmony_ci** Only called from sba_iommu.c in order to route ranges (MMIO vs DMA). 169462306a36Sopenharmony_ci** sba_iommu is responsible for locking (none needed at init time). 169562306a36Sopenharmony_ci*/ 169662306a36Sopenharmony_civoid lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci void __iomem * base_addr = ioremap(lba->hpa.start, 4096); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci imask <<= 2; /* adjust for hints - 2 more bits */ 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* Make sure we aren't trying to set bits that aren't writeable. */ 170362306a36Sopenharmony_ci WARN_ON((ibase & 0x001fffff) != 0); 170462306a36Sopenharmony_ci WARN_ON((imask & 0x001fffff) != 0); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci DBG("%s() ibase 0x%x imask 0x%x\n", __func__, ibase, imask); 170762306a36Sopenharmony_ci WRITE_REG32( imask, base_addr + LBA_IMASK); 170862306a36Sopenharmony_ci WRITE_REG32( ibase, base_addr + LBA_IBASE); 170962306a36Sopenharmony_ci iounmap(base_addr); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci/* 171462306a36Sopenharmony_ci * The design of the Diva management card in rp34x0 machines (rp3410, rp3440) 171562306a36Sopenharmony_ci * seems rushed, so that many built-in components simply don't work. 171662306a36Sopenharmony_ci * The following quirks disable the serial AUX port and the built-in ATI RV100 171762306a36Sopenharmony_ci * Radeon 7000 graphics card which both don't have any external connectors and 171862306a36Sopenharmony_ci * thus are useless, and even worse, e.g. the AUX port occupies ttyS0 and as 171962306a36Sopenharmony_ci * such makes those machines the only PARISC machines on which we can't use 172062306a36Sopenharmony_ci * ttyS0 as boot console. 172162306a36Sopenharmony_ci */ 172262306a36Sopenharmony_cistatic void quirk_diva_ati_card(struct pci_dev *dev) 172362306a36Sopenharmony_ci{ 172462306a36Sopenharmony_ci if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || 172562306a36Sopenharmony_ci dev->subsystem_device != 0x1292) 172662306a36Sopenharmony_ci return; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci dev_info(&dev->dev, "Hiding Diva built-in ATI card"); 172962306a36Sopenharmony_ci dev->device = 0; 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, 173262306a36Sopenharmony_ci quirk_diva_ati_card); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_cistatic void quirk_diva_aux_disable(struct pci_dev *dev) 173562306a36Sopenharmony_ci{ 173662306a36Sopenharmony_ci if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || 173762306a36Sopenharmony_ci dev->subsystem_device != 0x1291) 173862306a36Sopenharmony_ci return; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci dev_info(&dev->dev, "Hiding Diva built-in AUX serial device"); 174162306a36Sopenharmony_ci dev->device = 0; 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX, 174462306a36Sopenharmony_ci quirk_diva_aux_disable); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic void quirk_tosca_aux_disable(struct pci_dev *dev) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || 174962306a36Sopenharmony_ci dev->subsystem_device != 0x104a) 175062306a36Sopenharmony_ci return; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci dev_info(&dev->dev, "Hiding Tosca secondary built-in AUX serial device"); 175362306a36Sopenharmony_ci dev->device = 0; 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA, 175662306a36Sopenharmony_ci quirk_tosca_aux_disable); 1757