1e7300d04SMaxime Bizon /* 2e7300d04SMaxime Bizon * This file is subject to the terms and conditions of the GNU General Public 3e7300d04SMaxime Bizon * License. See the file "COPYING" in the main directory of this archive 4e7300d04SMaxime Bizon * for more details. 5e7300d04SMaxime Bizon * 6e7300d04SMaxime Bizon * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7e7300d04SMaxime Bizon */ 8e7300d04SMaxime Bizon 9e7300d04SMaxime Bizon #include <linux/types.h> 10e7300d04SMaxime Bizon #include <linux/pci.h> 11e7300d04SMaxime Bizon #include <linux/kernel.h> 12e7300d04SMaxime Bizon #include <linux/delay.h> 13e7300d04SMaxime Bizon #include <linux/io.h> 14e7300d04SMaxime Bizon 15e7300d04SMaxime Bizon #include "pci-bcm63xx.h" 16e7300d04SMaxime Bizon 17e7300d04SMaxime Bizon /* 18e7300d04SMaxime Bizon * swizzle 32bits data to return only the needed part 19e7300d04SMaxime Bizon */ 20e7300d04SMaxime Bizon static int postprocess_read(u32 data, int where, unsigned int size) 21e7300d04SMaxime Bizon { 22e7300d04SMaxime Bizon u32 ret; 23e7300d04SMaxime Bizon 24e7300d04SMaxime Bizon ret = 0; 25e7300d04SMaxime Bizon switch (size) { 26e7300d04SMaxime Bizon case 1: 27e7300d04SMaxime Bizon ret = (data >> ((where & 3) << 3)) & 0xff; 28e7300d04SMaxime Bizon break; 29e7300d04SMaxime Bizon case 2: 30e7300d04SMaxime Bizon ret = (data >> ((where & 3) << 3)) & 0xffff; 31e7300d04SMaxime Bizon break; 32e7300d04SMaxime Bizon case 4: 33e7300d04SMaxime Bizon ret = data; 34e7300d04SMaxime Bizon break; 35e7300d04SMaxime Bizon } 36e7300d04SMaxime Bizon return ret; 37e7300d04SMaxime Bizon } 38e7300d04SMaxime Bizon 39e7300d04SMaxime Bizon static int preprocess_write(u32 orig_data, u32 val, int where, 40e7300d04SMaxime Bizon unsigned int size) 41e7300d04SMaxime Bizon { 42e7300d04SMaxime Bizon u32 ret; 43e7300d04SMaxime Bizon 44e7300d04SMaxime Bizon ret = 0; 45e7300d04SMaxime Bizon switch (size) { 46e7300d04SMaxime Bizon case 1: 47e7300d04SMaxime Bizon ret = (orig_data & ~(0xff << ((where & 3) << 3))) | 48e7300d04SMaxime Bizon (val << ((where & 3) << 3)); 49e7300d04SMaxime Bizon break; 50e7300d04SMaxime Bizon case 2: 51e7300d04SMaxime Bizon ret = (orig_data & ~(0xffff << ((where & 3) << 3))) | 52e7300d04SMaxime Bizon (val << ((where & 3) << 3)); 53e7300d04SMaxime Bizon break; 54e7300d04SMaxime Bizon case 4: 55e7300d04SMaxime Bizon ret = val; 56e7300d04SMaxime Bizon break; 57e7300d04SMaxime Bizon } 58e7300d04SMaxime Bizon return ret; 59e7300d04SMaxime Bizon } 60e7300d04SMaxime Bizon 61e7300d04SMaxime Bizon /* 62e7300d04SMaxime Bizon * setup hardware for a configuration cycle with given parameters 63e7300d04SMaxime Bizon */ 64e7300d04SMaxime Bizon static int bcm63xx_setup_cfg_access(int type, unsigned int busn, 65e7300d04SMaxime Bizon unsigned int devfn, int where) 66e7300d04SMaxime Bizon { 67e7300d04SMaxime Bizon unsigned int slot, func, reg; 68e7300d04SMaxime Bizon u32 val; 69e7300d04SMaxime Bizon 70e7300d04SMaxime Bizon slot = PCI_SLOT(devfn); 71e7300d04SMaxime Bizon func = PCI_FUNC(devfn); 72e7300d04SMaxime Bizon reg = where >> 2; 73e7300d04SMaxime Bizon 74e7300d04SMaxime Bizon /* sanity check */ 75e7300d04SMaxime Bizon if (slot > (MPI_L2PCFG_DEVNUM_MASK >> MPI_L2PCFG_DEVNUM_SHIFT)) 76e7300d04SMaxime Bizon return 1; 77e7300d04SMaxime Bizon 78e7300d04SMaxime Bizon if (func > (MPI_L2PCFG_FUNC_MASK >> MPI_L2PCFG_FUNC_SHIFT)) 79e7300d04SMaxime Bizon return 1; 80e7300d04SMaxime Bizon 81e7300d04SMaxime Bizon if (reg > (MPI_L2PCFG_REG_MASK >> MPI_L2PCFG_REG_SHIFT)) 82e7300d04SMaxime Bizon return 1; 83e7300d04SMaxime Bizon 84e7300d04SMaxime Bizon /* ok, setup config access */ 85e7300d04SMaxime Bizon val = (reg << MPI_L2PCFG_REG_SHIFT); 86e7300d04SMaxime Bizon val |= (func << MPI_L2PCFG_FUNC_SHIFT); 87e7300d04SMaxime Bizon val |= (slot << MPI_L2PCFG_DEVNUM_SHIFT); 88e7300d04SMaxime Bizon val |= MPI_L2PCFG_CFG_USEREG_MASK; 89e7300d04SMaxime Bizon val |= MPI_L2PCFG_CFG_SEL_MASK; 90e7300d04SMaxime Bizon /* type 0 cycle for local bus, type 1 cycle for anything else */ 91e7300d04SMaxime Bizon if (type != 0) { 92e7300d04SMaxime Bizon /* FIXME: how to specify bus ??? */ 93e7300d04SMaxime Bizon val |= (1 << MPI_L2PCFG_CFG_TYPE_SHIFT); 94e7300d04SMaxime Bizon } 95e7300d04SMaxime Bizon bcm_mpi_writel(val, MPI_L2PCFG_REG); 96e7300d04SMaxime Bizon 97e7300d04SMaxime Bizon return 0; 98e7300d04SMaxime Bizon } 99e7300d04SMaxime Bizon 100e7300d04SMaxime Bizon static int bcm63xx_do_cfg_read(int type, unsigned int busn, 101e7300d04SMaxime Bizon unsigned int devfn, int where, int size, 102e7300d04SMaxime Bizon u32 *val) 103e7300d04SMaxime Bizon { 104e7300d04SMaxime Bizon u32 data; 105e7300d04SMaxime Bizon 106e7300d04SMaxime Bizon /* two phase cycle, first we write address, then read data at 107e7300d04SMaxime Bizon * another location, caller already has a spinlock so no need 108e7300d04SMaxime Bizon * to add one here */ 109e7300d04SMaxime Bizon if (bcm63xx_setup_cfg_access(type, busn, devfn, where)) 110e7300d04SMaxime Bizon return PCIBIOS_DEVICE_NOT_FOUND; 111e7300d04SMaxime Bizon iob(); 112e7300d04SMaxime Bizon data = le32_to_cpu(__raw_readl(pci_iospace_start)); 113e7300d04SMaxime Bizon /* restore IO space normal behaviour */ 114e7300d04SMaxime Bizon bcm_mpi_writel(0, MPI_L2PCFG_REG); 115e7300d04SMaxime Bizon 116e7300d04SMaxime Bizon *val = postprocess_read(data, where, size); 117e7300d04SMaxime Bizon 118e7300d04SMaxime Bizon return PCIBIOS_SUCCESSFUL; 119e7300d04SMaxime Bizon } 120e7300d04SMaxime Bizon 121e7300d04SMaxime Bizon static int bcm63xx_do_cfg_write(int type, unsigned int busn, 122e7300d04SMaxime Bizon unsigned int devfn, int where, int size, 123e7300d04SMaxime Bizon u32 val) 124e7300d04SMaxime Bizon { 125e7300d04SMaxime Bizon u32 data; 126e7300d04SMaxime Bizon 127e7300d04SMaxime Bizon /* two phase cycle, first we write address, then write data to 128e7300d04SMaxime Bizon * another location, caller already has a spinlock so no need 129e7300d04SMaxime Bizon * to add one here */ 130e7300d04SMaxime Bizon if (bcm63xx_setup_cfg_access(type, busn, devfn, where)) 131e7300d04SMaxime Bizon return PCIBIOS_DEVICE_NOT_FOUND; 132e7300d04SMaxime Bizon iob(); 133e7300d04SMaxime Bizon 134e7300d04SMaxime Bizon data = le32_to_cpu(__raw_readl(pci_iospace_start)); 135e7300d04SMaxime Bizon data = preprocess_write(data, val, where, size); 136e7300d04SMaxime Bizon 137e7300d04SMaxime Bizon __raw_writel(cpu_to_le32(data), pci_iospace_start); 138e7300d04SMaxime Bizon wmb(); 139e7300d04SMaxime Bizon /* no way to know the access is done, we have to wait */ 140e7300d04SMaxime Bizon udelay(500); 141e7300d04SMaxime Bizon /* restore IO space normal behaviour */ 142e7300d04SMaxime Bizon bcm_mpi_writel(0, MPI_L2PCFG_REG); 143e7300d04SMaxime Bizon 144e7300d04SMaxime Bizon return PCIBIOS_SUCCESSFUL; 145e7300d04SMaxime Bizon } 146e7300d04SMaxime Bizon 147e7300d04SMaxime Bizon static int bcm63xx_pci_read(struct pci_bus *bus, unsigned int devfn, 148e7300d04SMaxime Bizon int where, int size, u32 *val) 149e7300d04SMaxime Bizon { 150e7300d04SMaxime Bizon int type; 151e7300d04SMaxime Bizon 152e7300d04SMaxime Bizon type = bus->parent ? 1 : 0; 153e7300d04SMaxime Bizon 154e7300d04SMaxime Bizon if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL) 155e7300d04SMaxime Bizon return PCIBIOS_DEVICE_NOT_FOUND; 156e7300d04SMaxime Bizon 157e7300d04SMaxime Bizon return bcm63xx_do_cfg_read(type, bus->number, devfn, 158e7300d04SMaxime Bizon where, size, val); 159e7300d04SMaxime Bizon } 160e7300d04SMaxime Bizon 161e7300d04SMaxime Bizon static int bcm63xx_pci_write(struct pci_bus *bus, unsigned int devfn, 162e7300d04SMaxime Bizon int where, int size, u32 val) 163e7300d04SMaxime Bizon { 164e7300d04SMaxime Bizon int type; 165e7300d04SMaxime Bizon 166e7300d04SMaxime Bizon type = bus->parent ? 1 : 0; 167e7300d04SMaxime Bizon 168e7300d04SMaxime Bizon if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL) 169e7300d04SMaxime Bizon return PCIBIOS_DEVICE_NOT_FOUND; 170e7300d04SMaxime Bizon 171e7300d04SMaxime Bizon return bcm63xx_do_cfg_write(type, bus->number, devfn, 172e7300d04SMaxime Bizon where, size, val); 173e7300d04SMaxime Bizon } 174e7300d04SMaxime Bizon 175e7300d04SMaxime Bizon struct pci_ops bcm63xx_pci_ops = { 176e7300d04SMaxime Bizon .read = bcm63xx_pci_read, 177e7300d04SMaxime Bizon .write = bcm63xx_pci_write 178e7300d04SMaxime Bizon }; 179e7300d04SMaxime Bizon 180e7300d04SMaxime Bizon #ifdef CONFIG_CARDBUS 181e7300d04SMaxime Bizon /* 182e7300d04SMaxime Bizon * emulate configuration read access on a cardbus bridge 183e7300d04SMaxime Bizon */ 184e7300d04SMaxime Bizon #define FAKE_CB_BRIDGE_SLOT 0x1e 185e7300d04SMaxime Bizon 186e7300d04SMaxime Bizon static int fake_cb_bridge_bus_number = -1; 187e7300d04SMaxime Bizon 188e7300d04SMaxime Bizon static struct { 189e7300d04SMaxime Bizon u16 pci_command; 190e7300d04SMaxime Bizon u8 cb_latency; 191e7300d04SMaxime Bizon u8 subordinate_busn; 192e7300d04SMaxime Bizon u8 cardbus_busn; 193e7300d04SMaxime Bizon u8 pci_busn; 194e7300d04SMaxime Bizon int bus_assigned; 195e7300d04SMaxime Bizon u16 bridge_control; 196e7300d04SMaxime Bizon 197e7300d04SMaxime Bizon u32 mem_base0; 198e7300d04SMaxime Bizon u32 mem_limit0; 199e7300d04SMaxime Bizon u32 mem_base1; 200e7300d04SMaxime Bizon u32 mem_limit1; 201e7300d04SMaxime Bizon 202e7300d04SMaxime Bizon u32 io_base0; 203e7300d04SMaxime Bizon u32 io_limit0; 204e7300d04SMaxime Bizon u32 io_base1; 205e7300d04SMaxime Bizon u32 io_limit1; 206e7300d04SMaxime Bizon } fake_cb_bridge_regs; 207e7300d04SMaxime Bizon 208e7300d04SMaxime Bizon static int fake_cb_bridge_read(int where, int size, u32 *val) 209e7300d04SMaxime Bizon { 210e7300d04SMaxime Bizon unsigned int reg; 211e7300d04SMaxime Bizon u32 data; 212e7300d04SMaxime Bizon 213e7300d04SMaxime Bizon data = 0; 214e7300d04SMaxime Bizon reg = where >> 2; 215e7300d04SMaxime Bizon switch (reg) { 216e7300d04SMaxime Bizon case (PCI_VENDOR_ID >> 2): 217e7300d04SMaxime Bizon case (PCI_CB_SUBSYSTEM_VENDOR_ID >> 2): 218e7300d04SMaxime Bizon /* create dummy vendor/device id from our cpu id */ 219e7300d04SMaxime Bizon data = (bcm63xx_get_cpu_id() << 16) | PCI_VENDOR_ID_BROADCOM; 220e7300d04SMaxime Bizon break; 221e7300d04SMaxime Bizon 222e7300d04SMaxime Bizon case (PCI_COMMAND >> 2): 223e7300d04SMaxime Bizon data = (PCI_STATUS_DEVSEL_SLOW << 16); 224e7300d04SMaxime Bizon data |= fake_cb_bridge_regs.pci_command; 225e7300d04SMaxime Bizon break; 226e7300d04SMaxime Bizon 227e7300d04SMaxime Bizon case (PCI_CLASS_REVISION >> 2): 228e7300d04SMaxime Bizon data = (PCI_CLASS_BRIDGE_CARDBUS << 16); 229e7300d04SMaxime Bizon break; 230e7300d04SMaxime Bizon 231e7300d04SMaxime Bizon case (PCI_CACHE_LINE_SIZE >> 2): 232e7300d04SMaxime Bizon data = (PCI_HEADER_TYPE_CARDBUS << 16); 233e7300d04SMaxime Bizon break; 234e7300d04SMaxime Bizon 235e7300d04SMaxime Bizon case (PCI_INTERRUPT_LINE >> 2): 236e7300d04SMaxime Bizon /* bridge control */ 237e7300d04SMaxime Bizon data = (fake_cb_bridge_regs.bridge_control << 16); 238e7300d04SMaxime Bizon /* pin:intA line:0xff */ 239e7300d04SMaxime Bizon data |= (0x1 << 8) | 0xff; 240e7300d04SMaxime Bizon break; 241e7300d04SMaxime Bizon 242e7300d04SMaxime Bizon case (PCI_CB_PRIMARY_BUS >> 2): 243e7300d04SMaxime Bizon data = (fake_cb_bridge_regs.cb_latency << 24); 244e7300d04SMaxime Bizon data |= (fake_cb_bridge_regs.subordinate_busn << 16); 245e7300d04SMaxime Bizon data |= (fake_cb_bridge_regs.cardbus_busn << 8); 246e7300d04SMaxime Bizon data |= fake_cb_bridge_regs.pci_busn; 247e7300d04SMaxime Bizon break; 248e7300d04SMaxime Bizon 249e7300d04SMaxime Bizon case (PCI_CB_MEMORY_BASE_0 >> 2): 250e7300d04SMaxime Bizon data = fake_cb_bridge_regs.mem_base0; 251e7300d04SMaxime Bizon break; 252e7300d04SMaxime Bizon 253e7300d04SMaxime Bizon case (PCI_CB_MEMORY_LIMIT_0 >> 2): 254e7300d04SMaxime Bizon data = fake_cb_bridge_regs.mem_limit0; 255e7300d04SMaxime Bizon break; 256e7300d04SMaxime Bizon 257e7300d04SMaxime Bizon case (PCI_CB_MEMORY_BASE_1 >> 2): 258e7300d04SMaxime Bizon data = fake_cb_bridge_regs.mem_base1; 259e7300d04SMaxime Bizon break; 260e7300d04SMaxime Bizon 261e7300d04SMaxime Bizon case (PCI_CB_MEMORY_LIMIT_1 >> 2): 262e7300d04SMaxime Bizon data = fake_cb_bridge_regs.mem_limit1; 263e7300d04SMaxime Bizon break; 264e7300d04SMaxime Bizon 265e7300d04SMaxime Bizon case (PCI_CB_IO_BASE_0 >> 2): 266e7300d04SMaxime Bizon /* | 1 for 32bits io support */ 267e7300d04SMaxime Bizon data = fake_cb_bridge_regs.io_base0 | 0x1; 268e7300d04SMaxime Bizon break; 269e7300d04SMaxime Bizon 270e7300d04SMaxime Bizon case (PCI_CB_IO_LIMIT_0 >> 2): 271e7300d04SMaxime Bizon data = fake_cb_bridge_regs.io_limit0; 272e7300d04SMaxime Bizon break; 273e7300d04SMaxime Bizon 274e7300d04SMaxime Bizon case (PCI_CB_IO_BASE_1 >> 2): 275e7300d04SMaxime Bizon /* | 1 for 32bits io support */ 276e7300d04SMaxime Bizon data = fake_cb_bridge_regs.io_base1 | 0x1; 277e7300d04SMaxime Bizon break; 278e7300d04SMaxime Bizon 279e7300d04SMaxime Bizon case (PCI_CB_IO_LIMIT_1 >> 2): 280e7300d04SMaxime Bizon data = fake_cb_bridge_regs.io_limit1; 281e7300d04SMaxime Bizon break; 282e7300d04SMaxime Bizon } 283e7300d04SMaxime Bizon 284e7300d04SMaxime Bizon *val = postprocess_read(data, where, size); 285e7300d04SMaxime Bizon return PCIBIOS_SUCCESSFUL; 286e7300d04SMaxime Bizon } 287e7300d04SMaxime Bizon 288e7300d04SMaxime Bizon /* 289e7300d04SMaxime Bizon * emulate configuration write access on a cardbus bridge 290e7300d04SMaxime Bizon */ 291e7300d04SMaxime Bizon static int fake_cb_bridge_write(int where, int size, u32 val) 292e7300d04SMaxime Bizon { 293e7300d04SMaxime Bizon unsigned int reg; 294e7300d04SMaxime Bizon u32 data, tmp; 295e7300d04SMaxime Bizon int ret; 296e7300d04SMaxime Bizon 297e7300d04SMaxime Bizon ret = fake_cb_bridge_read((where & ~0x3), 4, &data); 298e7300d04SMaxime Bizon if (ret != PCIBIOS_SUCCESSFUL) 299e7300d04SMaxime Bizon return ret; 300e7300d04SMaxime Bizon 301e7300d04SMaxime Bizon data = preprocess_write(data, val, where, size); 302e7300d04SMaxime Bizon 303e7300d04SMaxime Bizon reg = where >> 2; 304e7300d04SMaxime Bizon switch (reg) { 305e7300d04SMaxime Bizon case (PCI_COMMAND >> 2): 306e7300d04SMaxime Bizon fake_cb_bridge_regs.pci_command = (data & 0xffff); 307e7300d04SMaxime Bizon break; 308e7300d04SMaxime Bizon 309e7300d04SMaxime Bizon case (PCI_CB_PRIMARY_BUS >> 2): 310e7300d04SMaxime Bizon fake_cb_bridge_regs.cb_latency = (data >> 24) & 0xff; 311e7300d04SMaxime Bizon fake_cb_bridge_regs.subordinate_busn = (data >> 16) & 0xff; 312e7300d04SMaxime Bizon fake_cb_bridge_regs.cardbus_busn = (data >> 8) & 0xff; 313e7300d04SMaxime Bizon fake_cb_bridge_regs.pci_busn = data & 0xff; 314e7300d04SMaxime Bizon if (fake_cb_bridge_regs.cardbus_busn) 315e7300d04SMaxime Bizon fake_cb_bridge_regs.bus_assigned = 1; 316e7300d04SMaxime Bizon break; 317e7300d04SMaxime Bizon 318e7300d04SMaxime Bizon case (PCI_INTERRUPT_LINE >> 2): 319e7300d04SMaxime Bizon tmp = (data >> 16) & 0xffff; 320e7300d04SMaxime Bizon /* disable memory prefetch support */ 321e7300d04SMaxime Bizon tmp &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; 322e7300d04SMaxime Bizon tmp &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; 323e7300d04SMaxime Bizon fake_cb_bridge_regs.bridge_control = tmp; 324e7300d04SMaxime Bizon break; 325e7300d04SMaxime Bizon 326e7300d04SMaxime Bizon case (PCI_CB_MEMORY_BASE_0 >> 2): 327e7300d04SMaxime Bizon fake_cb_bridge_regs.mem_base0 = data; 328e7300d04SMaxime Bizon break; 329e7300d04SMaxime Bizon 330e7300d04SMaxime Bizon case (PCI_CB_MEMORY_LIMIT_0 >> 2): 331e7300d04SMaxime Bizon fake_cb_bridge_regs.mem_limit0 = data; 332e7300d04SMaxime Bizon break; 333e7300d04SMaxime Bizon 334e7300d04SMaxime Bizon case (PCI_CB_MEMORY_BASE_1 >> 2): 335e7300d04SMaxime Bizon fake_cb_bridge_regs.mem_base1 = data; 336e7300d04SMaxime Bizon break; 337e7300d04SMaxime Bizon 338e7300d04SMaxime Bizon case (PCI_CB_MEMORY_LIMIT_1 >> 2): 339e7300d04SMaxime Bizon fake_cb_bridge_regs.mem_limit1 = data; 340e7300d04SMaxime Bizon break; 341e7300d04SMaxime Bizon 342e7300d04SMaxime Bizon case (PCI_CB_IO_BASE_0 >> 2): 343e7300d04SMaxime Bizon fake_cb_bridge_regs.io_base0 = data; 344e7300d04SMaxime Bizon break; 345e7300d04SMaxime Bizon 346e7300d04SMaxime Bizon case (PCI_CB_IO_LIMIT_0 >> 2): 347e7300d04SMaxime Bizon fake_cb_bridge_regs.io_limit0 = data; 348e7300d04SMaxime Bizon break; 349e7300d04SMaxime Bizon 350e7300d04SMaxime Bizon case (PCI_CB_IO_BASE_1 >> 2): 351e7300d04SMaxime Bizon fake_cb_bridge_regs.io_base1 = data; 352e7300d04SMaxime Bizon break; 353e7300d04SMaxime Bizon 354e7300d04SMaxime Bizon case (PCI_CB_IO_LIMIT_1 >> 2): 355e7300d04SMaxime Bizon fake_cb_bridge_regs.io_limit1 = data; 356e7300d04SMaxime Bizon break; 357e7300d04SMaxime Bizon } 358e7300d04SMaxime Bizon 359e7300d04SMaxime Bizon return PCIBIOS_SUCCESSFUL; 360e7300d04SMaxime Bizon } 361e7300d04SMaxime Bizon 362e7300d04SMaxime Bizon static int bcm63xx_cb_read(struct pci_bus *bus, unsigned int devfn, 363e7300d04SMaxime Bizon int where, int size, u32 *val) 364e7300d04SMaxime Bizon { 365e7300d04SMaxime Bizon /* snoop access to slot 0x1e on root bus, we fake a cardbus 366e7300d04SMaxime Bizon * bridge at this location */ 367e7300d04SMaxime Bizon if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) { 368e7300d04SMaxime Bizon fake_cb_bridge_bus_number = bus->number; 369e7300d04SMaxime Bizon return fake_cb_bridge_read(where, size, val); 370e7300d04SMaxime Bizon } 371e7300d04SMaxime Bizon 372e7300d04SMaxime Bizon /* a configuration cycle for the device behind the cardbus 373e7300d04SMaxime Bizon * bridge is actually done as a type 0 cycle on the primary 374e7300d04SMaxime Bizon * bus. This means that only one device can be on the cardbus 375e7300d04SMaxime Bizon * bus */ 376e7300d04SMaxime Bizon if (fake_cb_bridge_regs.bus_assigned && 377e7300d04SMaxime Bizon bus->number == fake_cb_bridge_regs.cardbus_busn && 378e7300d04SMaxime Bizon PCI_SLOT(devfn) == 0) 379e7300d04SMaxime Bizon return bcm63xx_do_cfg_read(0, 0, 380e7300d04SMaxime Bizon PCI_DEVFN(CARDBUS_PCI_IDSEL, 0), 381e7300d04SMaxime Bizon where, size, val); 382e7300d04SMaxime Bizon 383e7300d04SMaxime Bizon return PCIBIOS_DEVICE_NOT_FOUND; 384e7300d04SMaxime Bizon } 385e7300d04SMaxime Bizon 386e7300d04SMaxime Bizon static int bcm63xx_cb_write(struct pci_bus *bus, unsigned int devfn, 387e7300d04SMaxime Bizon int where, int size, u32 val) 388e7300d04SMaxime Bizon { 389e7300d04SMaxime Bizon if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) { 390e7300d04SMaxime Bizon fake_cb_bridge_bus_number = bus->number; 391e7300d04SMaxime Bizon return fake_cb_bridge_write(where, size, val); 392e7300d04SMaxime Bizon } 393e7300d04SMaxime Bizon 394e7300d04SMaxime Bizon if (fake_cb_bridge_regs.bus_assigned && 395e7300d04SMaxime Bizon bus->number == fake_cb_bridge_regs.cardbus_busn && 396e7300d04SMaxime Bizon PCI_SLOT(devfn) == 0) 397e7300d04SMaxime Bizon return bcm63xx_do_cfg_write(0, 0, 398e7300d04SMaxime Bizon PCI_DEVFN(CARDBUS_PCI_IDSEL, 0), 399e7300d04SMaxime Bizon where, size, val); 400e7300d04SMaxime Bizon 401e7300d04SMaxime Bizon return PCIBIOS_DEVICE_NOT_FOUND; 402e7300d04SMaxime Bizon } 403e7300d04SMaxime Bizon 404e7300d04SMaxime Bizon struct pci_ops bcm63xx_cb_ops = { 405e7300d04SMaxime Bizon .read = bcm63xx_cb_read, 406e7300d04SMaxime Bizon .write = bcm63xx_cb_write, 407e7300d04SMaxime Bizon }; 408e7300d04SMaxime Bizon 409e7300d04SMaxime Bizon /* 410e7300d04SMaxime Bizon * only one IO window, so it cannot be shared by PCI and cardbus, use 411e7300d04SMaxime Bizon * fixup to choose and detect unhandled configuration 412e7300d04SMaxime Bizon */ 41328eb0e46SGreg Kroah-Hartman static void bcm63xx_fixup(struct pci_dev *dev) 414e7300d04SMaxime Bizon { 415e7300d04SMaxime Bizon static int io_window = -1; 416*09cc9006SMika Westerberg int found, new_io_window; 417*09cc9006SMika Westerberg struct resource *r; 418e7300d04SMaxime Bizon u32 val; 419e7300d04SMaxime Bizon 420e7300d04SMaxime Bizon /* look for any io resource */ 421e7300d04SMaxime Bizon found = 0; 422*09cc9006SMika Westerberg pci_dev_for_each_resource(dev, r) { 423*09cc9006SMika Westerberg if (resource_type(r) == IORESOURCE_IO) { 424e7300d04SMaxime Bizon found = 1; 425e7300d04SMaxime Bizon break; 426e7300d04SMaxime Bizon } 427e7300d04SMaxime Bizon } 428e7300d04SMaxime Bizon if (!found) 429e7300d04SMaxime Bizon return; 430e7300d04SMaxime Bizon 431e7300d04SMaxime Bizon /* skip our fake bus with only cardbus bridge on it */ 432e7300d04SMaxime Bizon if (dev->bus->number == fake_cb_bridge_bus_number) 433e7300d04SMaxime Bizon return; 434e7300d04SMaxime Bizon 435e7300d04SMaxime Bizon /* find on which bus the device is */ 436e7300d04SMaxime Bizon if (fake_cb_bridge_regs.bus_assigned && 437e7300d04SMaxime Bizon dev->bus->number == fake_cb_bridge_regs.cardbus_busn && 438e7300d04SMaxime Bizon PCI_SLOT(dev->devfn) == 0) 439e7300d04SMaxime Bizon new_io_window = 1; 440e7300d04SMaxime Bizon else 441e7300d04SMaxime Bizon new_io_window = 0; 442e7300d04SMaxime Bizon 443e7300d04SMaxime Bizon if (new_io_window == io_window) 444e7300d04SMaxime Bizon return; 445e7300d04SMaxime Bizon 446e7300d04SMaxime Bizon if (io_window != -1) { 447e7300d04SMaxime Bizon printk(KERN_ERR "bcm63xx: both PCI and cardbus devices " 448e7300d04SMaxime Bizon "need IO, which hardware cannot do\n"); 449e7300d04SMaxime Bizon return; 450e7300d04SMaxime Bizon } 451e7300d04SMaxime Bizon 452e7300d04SMaxime Bizon printk(KERN_INFO "bcm63xx: PCI IO window assigned to %s\n", 453e7300d04SMaxime Bizon (new_io_window == 0) ? "PCI" : "cardbus"); 454e7300d04SMaxime Bizon 455e7300d04SMaxime Bizon val = bcm_mpi_readl(MPI_L2PIOREMAP_REG); 456e7300d04SMaxime Bizon if (io_window) 457e7300d04SMaxime Bizon val |= MPI_L2PREMAP_IS_CARDBUS_MASK; 458e7300d04SMaxime Bizon else 459e7300d04SMaxime Bizon val &= ~MPI_L2PREMAP_IS_CARDBUS_MASK; 460e7300d04SMaxime Bizon bcm_mpi_writel(val, MPI_L2PIOREMAP_REG); 461e7300d04SMaxime Bizon 462e7300d04SMaxime Bizon io_window = new_io_window; 463e7300d04SMaxime Bizon } 464e7300d04SMaxime Bizon 465e7300d04SMaxime Bizon DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup); 466e7300d04SMaxime Bizon #endif 46719c860d9SJonas Gorski 46819c860d9SJonas Gorski static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn) 46919c860d9SJonas Gorski { 47019c860d9SJonas Gorski switch (bus->number) { 47119c860d9SJonas Gorski case PCIE_BUS_BRIDGE: 472635c9907SRalf Baechle return PCI_SLOT(devfn) == 0; 47319c860d9SJonas Gorski case PCIE_BUS_DEVICE: 47419c860d9SJonas Gorski if (PCI_SLOT(devfn) == 0) 47519c860d9SJonas Gorski return bcm_pcie_readl(PCIE_DLSTATUS_REG) 47619c860d9SJonas Gorski & DLSTATUS_PHYLINKUP; 477c9b02990SLiangliang Huang fallthrough; 47819c860d9SJonas Gorski default: 47919c860d9SJonas Gorski return false; 48019c860d9SJonas Gorski } 48119c860d9SJonas Gorski } 48219c860d9SJonas Gorski 48319c860d9SJonas Gorski static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn, 48419c860d9SJonas Gorski int where, int size, u32 *val) 48519c860d9SJonas Gorski { 48619c860d9SJonas Gorski u32 data; 48719c860d9SJonas Gorski u32 reg = where & ~3; 48819c860d9SJonas Gorski 48919c860d9SJonas Gorski if (!bcm63xx_pcie_can_access(bus, devfn)) 49019c860d9SJonas Gorski return PCIBIOS_DEVICE_NOT_FOUND; 49119c860d9SJonas Gorski 49219c860d9SJonas Gorski if (bus->number == PCIE_BUS_DEVICE) 49319c860d9SJonas Gorski reg += PCIE_DEVICE_OFFSET; 49419c860d9SJonas Gorski 49519c860d9SJonas Gorski data = bcm_pcie_readl(reg); 49619c860d9SJonas Gorski 49719c860d9SJonas Gorski *val = postprocess_read(data, where, size); 49819c860d9SJonas Gorski 49919c860d9SJonas Gorski return PCIBIOS_SUCCESSFUL; 50019c860d9SJonas Gorski 50119c860d9SJonas Gorski } 50219c860d9SJonas Gorski 50319c860d9SJonas Gorski static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn, 50419c860d9SJonas Gorski int where, int size, u32 val) 50519c860d9SJonas Gorski { 50619c860d9SJonas Gorski u32 data; 50719c860d9SJonas Gorski u32 reg = where & ~3; 50819c860d9SJonas Gorski 50919c860d9SJonas Gorski if (!bcm63xx_pcie_can_access(bus, devfn)) 51019c860d9SJonas Gorski return PCIBIOS_DEVICE_NOT_FOUND; 51119c860d9SJonas Gorski 51219c860d9SJonas Gorski if (bus->number == PCIE_BUS_DEVICE) 51319c860d9SJonas Gorski reg += PCIE_DEVICE_OFFSET; 51419c860d9SJonas Gorski 51519c860d9SJonas Gorski 51619c860d9SJonas Gorski data = bcm_pcie_readl(reg); 51719c860d9SJonas Gorski 51819c860d9SJonas Gorski data = preprocess_write(data, val, where, size); 51919c860d9SJonas Gorski bcm_pcie_writel(data, reg); 52019c860d9SJonas Gorski 52119c860d9SJonas Gorski return PCIBIOS_SUCCESSFUL; 52219c860d9SJonas Gorski } 52319c860d9SJonas Gorski 52419c860d9SJonas Gorski 52519c860d9SJonas Gorski struct pci_ops bcm63xx_pcie_ops = { 52619c860d9SJonas Gorski .read = bcm63xx_pcie_read, 52719c860d9SJonas Gorski .write = bcm63xx_pcie_write 52819c860d9SJonas Gorski }; 529