linux/drivers/bcma/driver_pci.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * PCI Core
   4 *
   5 * Copyright 2005, Broadcom Corporation
   6 * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
   7 *
   8 * Licensed under the GNU/GPL. See COPYING for details.
   9 */
  10
  11#include "bcma_private.h"
  12#include <linux/export.h>
  13#include <linux/bcma/bcma.h>
  14
  15/**************************************************
  16 * R/W ops.
  17 **************************************************/
  18
  19static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
  20{
  21        pcicore_write32(pc, 0x130, address);
  22        pcicore_read32(pc, 0x130);
  23        return pcicore_read32(pc, 0x134);
  24}
  25
  26#if 0
  27static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
  28{
  29        pcicore_write32(pc, 0x130, address);
  30        pcicore_read32(pc, 0x130);
  31        pcicore_write32(pc, 0x134, data);
  32}
  33#endif
  34
  35static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
  36{
  37        const u16 mdio_control = 0x128;
  38        const u16 mdio_data = 0x12C;
  39        u32 v;
  40        int i;
  41
  42        v = (1 << 30); /* Start of Transaction */
  43        v |= (1 << 28); /* Write Transaction */
  44        v |= (1 << 17); /* Turnaround */
  45        v |= (0x1F << 18);
  46        v |= (phy << 4);
  47        pcicore_write32(pc, mdio_data, v);
  48
  49        udelay(10);
  50        for (i = 0; i < 200; i++) {
  51                v = pcicore_read32(pc, mdio_control);
  52                if (v & 0x100 /* Trans complete */)
  53                        break;
  54                msleep(1);
  55        }
  56}
  57
  58static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
  59{
  60        const u16 mdio_control = 0x128;
  61        const u16 mdio_data = 0x12C;
  62        int max_retries = 10;
  63        u16 ret = 0;
  64        u32 v;
  65        int i;
  66
  67        v = 0x80; /* Enable Preamble Sequence */
  68        v |= 0x2; /* MDIO Clock Divisor */
  69        pcicore_write32(pc, mdio_control, v);
  70
  71        if (pc->core->id.rev >= 10) {
  72                max_retries = 200;
  73                bcma_pcie_mdio_set_phy(pc, device);
  74        }
  75
  76        v = (1 << 30); /* Start of Transaction */
  77        v |= (1 << 29); /* Read Transaction */
  78        v |= (1 << 17); /* Turnaround */
  79        if (pc->core->id.rev < 10)
  80                v |= (u32)device << 22;
  81        v |= (u32)address << 18;
  82        pcicore_write32(pc, mdio_data, v);
  83        /* Wait for the device to complete the transaction */
  84        udelay(10);
  85        for (i = 0; i < max_retries; i++) {
  86                v = pcicore_read32(pc, mdio_control);
  87                if (v & 0x100 /* Trans complete */) {
  88                        udelay(10);
  89                        ret = pcicore_read32(pc, mdio_data);
  90                        break;
  91                }
  92                msleep(1);
  93        }
  94        pcicore_write32(pc, mdio_control, 0);
  95        return ret;
  96}
  97
  98static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
  99                                u8 address, u16 data)
 100{
 101        const u16 mdio_control = 0x128;
 102        const u16 mdio_data = 0x12C;
 103        int max_retries = 10;
 104        u32 v;
 105        int i;
 106
 107        v = 0x80; /* Enable Preamble Sequence */
 108        v |= 0x2; /* MDIO Clock Divisor */
 109        pcicore_write32(pc, mdio_control, v);
 110
 111        if (pc->core->id.rev >= 10) {
 112                max_retries = 200;
 113                bcma_pcie_mdio_set_phy(pc, device);
 114        }
 115
 116        v = (1 << 30); /* Start of Transaction */
 117        v |= (1 << 28); /* Write Transaction */
 118        v |= (1 << 17); /* Turnaround */
 119        if (pc->core->id.rev < 10)
 120                v |= (u32)device << 22;
 121        v |= (u32)address << 18;
 122        v |= data;
 123        pcicore_write32(pc, mdio_data, v);
 124        /* Wait for the device to complete the transaction */
 125        udelay(10);
 126        for (i = 0; i < max_retries; i++) {
 127                v = pcicore_read32(pc, mdio_control);
 128                if (v & 0x100 /* Trans complete */)
 129                        break;
 130                msleep(1);
 131        }
 132        pcicore_write32(pc, mdio_control, 0);
 133}
 134
 135/**************************************************
 136 * Workarounds.
 137 **************************************************/
 138
 139static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
 140{
 141        return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
 142}
 143
 144static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
 145{
 146        const u8 serdes_pll_device = 0x1D;
 147        const u8 serdes_rx_device = 0x1F;
 148        u16 tmp;
 149
 150        bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
 151                              bcma_pcicore_polarity_workaround(pc));
 152        tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
 153        if (tmp & 0x4000)
 154                bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
 155}
 156
 157/**************************************************
 158 * Init.
 159 **************************************************/
 160
 161static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
 162{
 163        bcma_pcicore_serdes_workaround(pc);
 164}
 165
 166static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
 167{
 168        struct bcma_bus *bus = pc->core->bus;
 169        u16 chipid_top;
 170
 171        chipid_top = (bus->chipinfo.id & 0xFF00);
 172        if (chipid_top != 0x4700 &&
 173            chipid_top != 0x5300)
 174                return false;
 175
 176#ifdef CONFIG_SSB_DRIVER_PCICORE
 177        if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 178                return false;
 179#endif /* CONFIG_SSB_DRIVER_PCICORE */
 180
 181#if 0
 182        /* TODO: on BCMA we use address from EROM instead of magic formula */
 183        u32 tmp;
 184        return !mips_busprobe32(tmp, (bus->mmio +
 185                (pc->core->core_index * BCMA_CORE_SIZE)));
 186#endif
 187
 188        return true;
 189}
 190
 191void bcma_core_pci_init(struct bcma_drv_pci *pc)
 192{
 193        if (pc->setup_done)
 194                return;
 195
 196        if (bcma_core_pci_is_in_hostmode(pc)) {
 197#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 198                bcma_core_pci_hostmode_init(pc);
 199#else
 200                pr_err("Driver compiled without support for hostmode PCI\n");
 201#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
 202        } else {
 203                bcma_core_pci_clientmode_init(pc);
 204        }
 205
 206        pc->setup_done = true;
 207}
 208
 209int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 210                          bool enable)
 211{
 212        struct pci_dev *pdev = pc->core->bus->host_pci;
 213        u32 coremask, tmp;
 214        int err = 0;
 215
 216        if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
 217                /* This bcma device is not on a PCI host-bus. So the IRQs are
 218                 * not routed through the PCI core.
 219                 * So we must not enable routing through the PCI core. */
 220                goto out;
 221        }
 222
 223        err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 224        if (err)
 225                goto out;
 226
 227        coremask = BIT(core->core_index) << 8;
 228        if (enable)
 229                tmp |= coremask;
 230        else
 231                tmp &= ~coremask;
 232
 233        err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
 234
 235out:
 236        return err;
 237}
 238EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 239