0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "bcma_private.h"
0013 #include <linux/export.h>
0014 #include <linux/bcma/bcma.h>
0015
0016
0017
0018
0019
0020 u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
0021 {
0022 pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
0023 pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
0024 return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
0025 }
0026
0027 static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
0028 {
0029 pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
0030 pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
0031 pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
0032 }
0033
0034 static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u16 phy)
0035 {
0036 u32 v;
0037 int i;
0038
0039 v = BCMA_CORE_PCI_MDIODATA_START;
0040 v |= BCMA_CORE_PCI_MDIODATA_WRITE;
0041 v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
0042 BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
0043 v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR <<
0044 BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
0045 v |= BCMA_CORE_PCI_MDIODATA_TA;
0046 v |= (phy << 4);
0047 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
0048
0049 udelay(10);
0050 for (i = 0; i < 200; i++) {
0051 v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
0052 if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
0053 break;
0054 usleep_range(1000, 2000);
0055 }
0056 }
0057
0058 static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u16 device, u8 address)
0059 {
0060 int max_retries = 10;
0061 u16 ret = 0;
0062 u32 v;
0063 int i;
0064
0065
0066 v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
0067 v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
0068 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
0069
0070 if (pc->core->id.rev >= 10) {
0071 max_retries = 200;
0072 bcma_pcie_mdio_set_phy(pc, device);
0073 v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
0074 BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
0075 v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
0076 } else {
0077 v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
0078 v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
0079 }
0080
0081 v |= BCMA_CORE_PCI_MDIODATA_START;
0082 v |= BCMA_CORE_PCI_MDIODATA_READ;
0083 v |= BCMA_CORE_PCI_MDIODATA_TA;
0084
0085 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
0086
0087 udelay(10);
0088 for (i = 0; i < max_retries; i++) {
0089 v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
0090 if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) {
0091 udelay(10);
0092 ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
0093 break;
0094 }
0095 usleep_range(1000, 2000);
0096 }
0097 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
0098 return ret;
0099 }
0100
0101 static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u16 device,
0102 u8 address, u16 data)
0103 {
0104 int max_retries = 10;
0105 u32 v;
0106 int i;
0107
0108
0109 v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
0110 v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
0111 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
0112
0113 if (pc->core->id.rev >= 10) {
0114 max_retries = 200;
0115 bcma_pcie_mdio_set_phy(pc, device);
0116 v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
0117 BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
0118 v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
0119 } else {
0120 v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
0121 v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
0122 }
0123
0124 v |= BCMA_CORE_PCI_MDIODATA_START;
0125 v |= BCMA_CORE_PCI_MDIODATA_WRITE;
0126 v |= BCMA_CORE_PCI_MDIODATA_TA;
0127 v |= data;
0128 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
0129
0130 udelay(10);
0131 for (i = 0; i < max_retries; i++) {
0132 v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
0133 if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
0134 break;
0135 usleep_range(1000, 2000);
0136 }
0137 pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
0138 }
0139
0140 static u16 bcma_pcie_mdio_writeread(struct bcma_drv_pci *pc, u16 device,
0141 u8 address, u16 data)
0142 {
0143 bcma_pcie_mdio_write(pc, device, address, data);
0144 return bcma_pcie_mdio_read(pc, device, address);
0145 }
0146
0147
0148
0149
0150
0151 static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
0152 {
0153 struct bcma_device *core = pc->core;
0154 u16 val16, core_index;
0155 uint regoff;
0156
0157 regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
0158 core_index = (u16)core->core_index;
0159
0160 val16 = pcicore_read16(pc, regoff);
0161 if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
0162 != core_index) {
0163 val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
0164 (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
0165 pcicore_write16(pc, regoff, val16);
0166 }
0167 }
0168
0169
0170
0171
0172
0173 void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
0174 {
0175 if (pc->early_setup_done)
0176 return;
0177
0178 pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
0179 if (pc->hostmode)
0180 goto out;
0181
0182 bcma_core_pci_fixcfg(pc);
0183
0184 out:
0185 pc->early_setup_done = true;
0186 }
0187
0188
0189
0190
0191
0192 static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
0193 {
0194 u32 tmp;
0195
0196 tmp = bcma_pcie_read(pc, BCMA_CORE_PCI_PLP_STATUSREG);
0197 if (tmp & BCMA_CORE_PCI_PLP_POLARITYINV_STAT)
0198 return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE |
0199 BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY;
0200 else
0201 return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE;
0202 }
0203
0204 static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
0205 {
0206 u16 tmp;
0207
0208 bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_RX,
0209 BCMA_CORE_PCI_SERDES_RX_CTRL,
0210 bcma_pcicore_polarity_workaround(pc));
0211 tmp = bcma_pcie_mdio_read(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
0212 BCMA_CORE_PCI_SERDES_PLL_CTRL);
0213 if (tmp & BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN)
0214 bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
0215 BCMA_CORE_PCI_SERDES_PLL_CTRL,
0216 tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
0217 }
0218
0219
0220
0221 static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
0222 {
0223 u16 val16;
0224 uint regoff;
0225
0226 regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_MISC_CONFIG);
0227
0228 val16 = pcicore_read16(pc, regoff);
0229
0230 if (!(val16 & BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST)) {
0231 val16 |= BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST;
0232 pcicore_write16(pc, regoff, val16);
0233 }
0234 }
0235
0236
0237
0238
0239
0240 static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
0241 {
0242 bcma_pcicore_serdes_workaround(pc);
0243 bcma_core_pci_config_fixup(pc);
0244 }
0245
0246 void bcma_core_pci_init(struct bcma_drv_pci *pc)
0247 {
0248 if (pc->setup_done)
0249 return;
0250
0251 bcma_core_pci_early_init(pc);
0252
0253 if (pc->hostmode)
0254 bcma_core_pci_hostmode_init(pc);
0255 else
0256 bcma_core_pci_clientmode_init(pc);
0257 }
0258
0259 void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
0260 {
0261 struct bcma_drv_pci *pc;
0262 u16 data;
0263
0264 if (bus->hosttype != BCMA_HOSTTYPE_PCI)
0265 return;
0266
0267 pc = &bus->drv_pci[0];
0268
0269 if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
0270 data = up ? 0x74 : 0x7C;
0271 bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
0272 BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
0273 bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
0274 BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
0275 } else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
0276 data = up ? 0x75 : 0x7D;
0277 bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
0278 BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
0279 bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
0280 BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
0281 }
0282 }
0283 EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
0284
0285 static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
0286 {
0287 u32 w;
0288
0289 w = bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
0290 if (extend)
0291 w |= BCMA_CORE_PCI_ASPMTIMER_EXTEND;
0292 else
0293 w &= ~BCMA_CORE_PCI_ASPMTIMER_EXTEND;
0294 bcma_pcie_write(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG, w);
0295 bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
0296 }
0297
0298 void bcma_core_pci_up(struct bcma_drv_pci *pc)
0299 {
0300 bcma_core_pci_extend_L1timer(pc, true);
0301 }
0302
0303 void bcma_core_pci_down(struct bcma_drv_pci *pc)
0304 {
0305 bcma_core_pci_extend_L1timer(pc, false);
0306 }