summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2012-05-25 17:53:57 +0000
committeradrian <adrian@FreeBSD.org>2012-05-25 17:53:57 +0000
commit0d2aec183a4ecc3d9de344ccac497f0b29ccf736 (patch)
tree3d9645fed3b3537c8179ce0b3a86f8d4893720d0
parent33d132b84d1242d16ea1a8c47ff86473f0f7c403 (diff)
downloadFreeBSD-src-0d2aec183a4ecc3d9de344ccac497f0b29ccf736.zip
FreeBSD-src-0d2aec183a4ecc3d9de344ccac497f0b29ccf736.tar.gz
Add some AR5416/AR5418 WAR's for power-on and suspend/resume:
* Now that ah_configPCIE is called for both power on and suspend/resume, make sure the right bit(s) are cleared and set when suspending and resuming. Specifically: + force disable/enable the PCIe PHY upon suspend/resume; + reprogram the PCIe WAR register when resuming and upon power-on. * Add a recipe which powers down any PCIe PHY hardware inside the AR5416 (which is the PCI variant) to save on power. I have (currently) no way to test exactly how much power is saved, if any. Tested on: * AR5416 cardbus - although unfortunately pccard/cbb/cardbus currently detaches the NIC upon suspend, I don't think it's a proper test case. * AR5418 PCIe attached to expresscard - since we're not doing PCIe APSM, it's also not likely a full/good test case. In both instances I went through a handful of suspend/resume cycles and ensured that the STA vap reassociated correctly. TODO: * Setup a laptop to simply sit in a suspend/resume loop, making sure that the NIC always correctly comes back; * Start doing suspend/resume tests with actual traffic going on in the background, as I bet this process is all quite racy at the present; * Test adhoc/hostap mode, just to be completely sure it's working correctly; * See if I can jury rig an external power source to an AR5416 to test out whether ah_disablePCIE() works. Obtained from: Qualcomm Atheros
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_attach.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
index ee92776..fc5eefb 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
@@ -468,18 +468,63 @@ ar5416AttachPCIE(struct ath_hal *ah)
static void
ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
- if (AH_PRIVATE(ah)->ah_ispcie && !restore) {
+
+ /* This is only applicable for AR5418 (AR5416 PCIe) */
+ if (! AH_PRIVATE(ah)->ah_ispcie)
+ return;
+
+ if (! restore) {
ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0);
OS_DELAY(1000);
- OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+ }
+
+ if (power_off) { /* Power-off */
+ /* clear bit 19 to disable L1 */
+ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+ } else { /* Power-on */
+ /* Set default WAR values for Owl */
OS_REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
+
+ /* set bit 19 to allow forcing of pcie core into L1 state */
+ OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
}
}
+/*
+ * Disable PCIe PHY if PCIe isn't used.
+ */
static void
ar5416DisablePCIE(struct ath_hal *ah)
{
- /* XXX TODO */
+
+ /* PCIe? Don't */
+ if (AH_PRIVATE(ah)->ah_ispcie)
+ return;
+
+ /* .. Only applicable for AR5416v2 or later */
+ if (! (AR_SREV_OWL(ah) && AR_SREV_OWL_20_OR_LATER(ah)))
+ return;
+
+ OS_REG_WRITE_BUFFER_ENABLE(ah);
+
+ /*
+ * Disable the PCIe PHY.
+ */
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
+
+ /* Load the new settings */
+ OS_REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+ OS_REG_WRITE_BUFFER_FLUSH(ah);
+ OS_REG_WRITE_BUFFER_DISABLE(ah);
}
static void
OpenPOWER on IntegriCloud