aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Bondar <alexander.bondar@intel.com>2014-02-18 10:45:00 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-03-09 13:16:39 -0400
commita812cba9bb141225ce28a48b60038e115620bccd (patch)
tree6294679a060230f8dd66dae2fc190c2e4273f575
parent8ea0c68fe56983f40256d0407ecf19530fd31442 (diff)
iwlwifi: pcie: enable LP XTAL to reduce power consumption
1. Enable LP XTAL to avoid HW bug where device may consume much power if FW is not loaded after device reset. LP XTAL is disabled by default after device HW reset. Configure device's "persistence" mode to avoid resetting XTAL again when SHRD_HW_RST occurs in S3. 2. Add methods to access SHR (shared block memory space) directly from PCI bus w/o need to power up MAC HW. Shared internal registers (e.g. SHR_APMG_GP1, SHR_APMG_XTAL_CFG)can be accessed directly from PCI bus through SHR arbiter even when MAC HW is powered down. This is possible due to indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers. Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW need not be powered up so no "grab inc access" is required. For example, to read from SHR_APMG_GP1 register (0x1DC), first, write to the control register: HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 2 (read access) second, read from the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0]. To write the register, first, write to the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0] and then: HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 3 (write access) Signed-off-by: Alexander Bondar <alexander.bondar@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h38
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h23
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c131
7 files changed, 200 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index fbd262ffa497..003a546571d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -134,6 +134,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = {
134 .nvm_ver = IWL7260_NVM_VERSION, 134 .nvm_ver = IWL7260_NVM_VERSION,
135 .nvm_calib_ver = IWL7260_TX_POWER_VERSION, 135 .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
136 .host_interrupt_operation_mode = true, 136 .host_interrupt_operation_mode = true,
137 .lp_xtal_workaround = true,
137}; 138};
138 139
139const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { 140const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
@@ -145,6 +146,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
145 .nvm_calib_ver = IWL7260_TX_POWER_VERSION, 146 .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
146 .high_temp = true, 147 .high_temp = true,
147 .host_interrupt_operation_mode = true, 148 .host_interrupt_operation_mode = true,
149 .lp_xtal_workaround = true,
148}; 150};
149 151
150const struct iwl_cfg iwl7260_2n_cfg = { 152const struct iwl_cfg iwl7260_2n_cfg = {
@@ -155,6 +157,7 @@ const struct iwl_cfg iwl7260_2n_cfg = {
155 .nvm_ver = IWL7260_NVM_VERSION, 157 .nvm_ver = IWL7260_NVM_VERSION,
156 .nvm_calib_ver = IWL7260_TX_POWER_VERSION, 158 .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
157 .host_interrupt_operation_mode = true, 159 .host_interrupt_operation_mode = true,
160 .lp_xtal_workaround = true,
158}; 161};
159 162
160const struct iwl_cfg iwl7260_n_cfg = { 163const struct iwl_cfg iwl7260_n_cfg = {
@@ -165,6 +168,7 @@ const struct iwl_cfg iwl7260_n_cfg = {
165 .nvm_ver = IWL7260_NVM_VERSION, 168 .nvm_ver = IWL7260_NVM_VERSION,
166 .nvm_calib_ver = IWL7260_TX_POWER_VERSION, 169 .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
167 .host_interrupt_operation_mode = true, 170 .host_interrupt_operation_mode = true,
171 .lp_xtal_workaround = true,
168}; 172};
169 173
170const struct iwl_cfg iwl3160_2ac_cfg = { 174const struct iwl_cfg iwl3160_2ac_cfg = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 13ec56607d10..3f17dc3f2c8a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -262,6 +262,7 @@ struct iwl_cfg {
262 bool high_temp; 262 bool high_temp;
263 bool d0i3; 263 bool d0i3;
264 u8 nvm_hw_section_num; 264 u8 nvm_hw_section_num;
265 bool lp_xtal_workaround;
265 const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; 266 const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
266}; 267};
267 268
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index f13dec9ad9c9..fe129c94ae3e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -139,6 +139,13 @@
139#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) 139#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
140 140
141/* 141/*
142 * CSR HW resources monitor registers
143 */
144#define CSR_MONITOR_CFG_REG (CSR_BASE+0x214)
145#define CSR_MONITOR_STATUS_REG (CSR_BASE+0x228)
146#define CSR_MONITOR_XTAL_RESOURCES (0x00000010)
147
148/*
142 * CSR Hardware Revision Workaround Register. Indicates hardware rev; 149 * CSR Hardware Revision Workaround Register. Indicates hardware rev;
143 * "step" determines CCK backoff for txpower calculation. Used for 4965 only. 150 * "step" determines CCK backoff for txpower calculation. Used for 4965 only.
144 * See also CSR_HW_REV register. 151 * See also CSR_HW_REV register.
@@ -173,6 +180,7 @@
173#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ 180#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
174#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ 181#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
175#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ 182#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
183#define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */
176 184
177#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ 185#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/
178#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ 186#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/
@@ -240,6 +248,7 @@
240 * 001 -- MAC power-down 248 * 001 -- MAC power-down
241 * 010 -- PHY (radio) power-down 249 * 010 -- PHY (radio) power-down
242 * 011 -- Error 250 * 011 -- Error
251 * 10: XTAL ON request
243 * 9-6: SYS_CONFIG 252 * 9-6: SYS_CONFIG
244 * Indicates current system configuration, reflecting pins on chip 253 * Indicates current system configuration, reflecting pins on chip
245 * as forced high/low by device circuit board. 254 * as forced high/low by device circuit board.
@@ -271,6 +280,7 @@
271#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) 280#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
272#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) 281#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
273#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) 282#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
283#define CSR_GP_CNTRL_REG_FLAG_XTAL_ON (0x00000400)
274 284
275#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) 285#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
276 286
@@ -396,6 +406,34 @@
396#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) 406#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
397 407
398/* 408/*
409 * SHR target access (Shared block memory space)
410 *
411 * Shared internal registers can be accessed directly from PCI bus through SHR
412 * arbiter without need for the MAC HW to be powered up. This is possible due to
413 * indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and
414 * HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers.
415 *
416 * Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW
417 * need not be powered up so no "grab inc access" is required.
418 */
419
420/*
421 * Registers for accessing shared registers (e.g. SHR_APMG_GP1,
422 * SHR_APMG_XTAL_CFG). For example, to read from SHR_APMG_GP1 register (0x1DC),
423 * first, write to the control register:
424 * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register)
425 * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 2 (read access)
426 * second, read from the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0].
427 *
428 * To write the register, first, write to the data register
429 * HEEP_CTRL_WRD_PCIEX_DATA[31:0] and then:
430 * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register)
431 * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 3 (write access)
432 */
433#define HEEP_CTRL_WRD_PCIEX_CTRL_REG (CSR_BASE+0x0ec)
434#define HEEP_CTRL_WRD_PCIEX_DATA_REG (CSR_BASE+0x0f4)
435
436/*
399 * HBUS (Host-side Bus) 437 * HBUS (Host-side Bus)
400 * 438 *
401 * HBUS registers are mapped directly into PCI bus space, but are used 439 * HBUS registers are mapped directly into PCI bus space, but are used
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 07372f2b0250..44cc3cf45762 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -93,14 +93,14 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
93} 93}
94IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); 94IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
95 95
96static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs) 96u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs)
97{ 97{
98 u32 val = iwl_trans_read_prph(trans, ofs); 98 u32 val = iwl_trans_read_prph(trans, ofs);
99 trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); 99 trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val);
100 return val; 100 return val;
101} 101}
102 102
103static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) 103void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
104{ 104{
105 trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); 105 trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val);
106 iwl_trans_write_prph(trans, ofs, val); 106 iwl_trans_write_prph(trans, ofs, val);
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 9e81b23d738b..665ddd9dbbc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -70,7 +70,9 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
70void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); 70void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
71 71
72 72
73u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs);
73u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); 74u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs);
75void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
74void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); 76void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
75int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, 77int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
76 u32 bits, u32 mask, int timeout); 78 u32 bits, u32 mask, int timeout);
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 9c90186d1744..5f657c501406 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -95,7 +95,8 @@
95#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ 95#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
96#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) 96#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
97 97
98#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) 98#define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200)
99#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
99 100
100#define APMG_RTC_INT_STT_RFKILL (0x10000000) 101#define APMG_RTC_INT_STT_RFKILL (0x10000000)
101 102
@@ -105,6 +106,26 @@
105/* Device NMI register */ 106/* Device NMI register */
106#define DEVICE_SET_NMI_REG 0x00a01c30 107#define DEVICE_SET_NMI_REG 0x00a01c30
107 108
109/* Shared registers (0x0..0x3ff, via target indirect or periphery */
110#define SHR_BASE 0x00a10000
111
112/* Shared GP1 register */
113#define SHR_APMG_GP1_REG 0x01dc
114#define SHR_APMG_GP1_REG_PRPH (SHR_BASE + SHR_APMG_GP1_REG)
115#define SHR_APMG_GP1_WF_XTAL_LP_EN 0x00000004
116#define SHR_APMG_GP1_CHICKEN_BIT_SELECT 0x80000000
117
118/* Shared DL_CFG register */
119#define SHR_APMG_DL_CFG_REG 0x01c4
120#define SHR_APMG_DL_CFG_REG_PRPH (SHR_BASE + SHR_APMG_DL_CFG_REG)
121#define SHR_APMG_DL_CFG_RTCS_CLK_SELECTOR_MSK 0x000000c0
122#define SHR_APMG_DL_CFG_RTCS_CLK_INTERNAL_XTAL 0x00000080
123#define SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP 0x00000100
124
125/* Shared APMG_XTAL_CFG register */
126#define SHR_APMG_XTAL_CFG_REG 0x1c0
127#define SHR_APMG_XTAL_CFG_XTAL_ON_REQ 0x80000000
128
108/* 129/*
109 * Device reset for family 8000 130 * Device reset for family 8000
110 * write to bit 24 in order to reset the CPU 131 * write to bit 24 in order to reset the CPU
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 84d471299e5a..32a5a9a20811 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -75,6 +75,20 @@
75#include "iwl-agn-hw.h" 75#include "iwl-agn-hw.h"
76#include "internal.h" 76#include "internal.h"
77 77
78static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
79{
80 iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG,
81 ((reg & 0x0000ffff) | (2 << 28)));
82 return iwl_read32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG);
83}
84
85static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)
86{
87 iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG, val);
88 iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG,
89 ((reg & 0x0000ffff) | (3 << 28)));
90}
91
78static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) 92static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
79{ 93{
80 if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) 94 if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
@@ -229,6 +243,116 @@ out:
229 return ret; 243 return ret;
230} 244}
231 245
246/*
247 * Enable LP XTAL to avoid HW bug where device may consume much power if
248 * FW is not loaded after device reset. LP XTAL is disabled by default
249 * after device HW reset. Do it only if XTAL is fed by internal source.
250 * Configure device's "persistence" mode to avoid resetting XTAL again when
251 * SHRD_HW_RST occurs in S3.
252 */
253static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
254{
255 int ret;
256 u32 apmg_gp1_reg;
257 u32 apmg_xtal_cfg_reg;
258 u32 dl_cfg_reg;
259
260 /* Force XTAL ON */
261 __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
262 CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
263
264 /* Reset entire device - do controller reset (results in SHRD_HW_RST) */
265 iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
266
267 udelay(10);
268
269 /*
270 * Set "initialization complete" bit to move adapter from
271 * D0U* --> D0A* (powered-up active) state.
272 */
273 iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
274
275 /*
276 * Wait for clock stabilization; once stabilized, access to
277 * device-internal resources is possible.
278 */
279 ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
280 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
281 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
282 25000);
283 if (WARN_ON(ret < 0)) {
284 IWL_ERR(trans, "Access time out - failed to enable LP XTAL\n");
285 /* Release XTAL ON request */
286 __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
287 CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
288 return;
289 }
290
291 /*
292 * Clear "disable persistence" to avoid LP XTAL resetting when
293 * SHRD_HW_RST is applied in S3.
294 */
295 iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
296 APMG_PCIDEV_STT_VAL_PERSIST_DIS);
297
298 /*
299 * Force APMG XTAL to be active to prevent its disabling by HW
300 * caused by APMG idle state.
301 */
302 apmg_xtal_cfg_reg = iwl_trans_pcie_read_shr(trans,
303 SHR_APMG_XTAL_CFG_REG);
304 iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG,
305 apmg_xtal_cfg_reg |
306 SHR_APMG_XTAL_CFG_XTAL_ON_REQ);
307
308 /*
309 * Reset entire device again - do controller reset (results in
310 * SHRD_HW_RST). Turn MAC off before proceeding.
311 */
312 iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
313
314 udelay(10);
315
316 /* Enable LP XTAL by indirect access through CSR */
317 apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG);
318 iwl_trans_pcie_write_shr(trans, SHR_APMG_GP1_REG, apmg_gp1_reg |
319 SHR_APMG_GP1_WF_XTAL_LP_EN |
320 SHR_APMG_GP1_CHICKEN_BIT_SELECT);
321
322 /* Clear delay line clock power up */
323 dl_cfg_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_DL_CFG_REG);
324 iwl_trans_pcie_write_shr(trans, SHR_APMG_DL_CFG_REG, dl_cfg_reg &
325 ~SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP);
326
327 /*
328 * Enable persistence mode to avoid LP XTAL resetting when
329 * SHRD_HW_RST is applied in S3.
330 */
331 iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
332 CSR_HW_IF_CONFIG_REG_PERSIST_MODE);
333
334 /*
335 * Clear "initialization complete" bit to move adapter from
336 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
337 */
338 iwl_clear_bit(trans, CSR_GP_CNTRL,
339 CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
340
341 /* Activates XTAL resources monitor */
342 __iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG,
343 CSR_MONITOR_XTAL_RESOURCES);
344
345 /* Release XTAL ON request */
346 __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
347 CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
348 udelay(10);
349
350 /* Release APMG XTAL */
351 iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG,
352 apmg_xtal_cfg_reg &
353 ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ);
354}
355
232static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) 356static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
233{ 357{
234 int ret = 0; 358 int ret = 0;
@@ -256,6 +380,11 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans)
256 /* Stop device's DMA activity */ 380 /* Stop device's DMA activity */
257 iwl_pcie_apm_stop_master(trans); 381 iwl_pcie_apm_stop_master(trans);
258 382
383 if (trans->cfg->lp_xtal_workaround) {
384 iwl_pcie_apm_lp_xtal_enable(trans);
385 return;
386 }
387
259 /* Reset the entire device */ 388 /* Reset the entire device */
260 iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); 389 iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
261 390
@@ -1208,6 +1337,7 @@ static const char *get_csr_string(int cmd)
1208 IWL_CMD(CSR_GIO_CHICKEN_BITS); 1337 IWL_CMD(CSR_GIO_CHICKEN_BITS);
1209 IWL_CMD(CSR_ANA_PLL_CFG); 1338 IWL_CMD(CSR_ANA_PLL_CFG);
1210 IWL_CMD(CSR_HW_REV_WA_REG); 1339 IWL_CMD(CSR_HW_REV_WA_REG);
1340 IWL_CMD(CSR_MONITOR_STATUS_REG);
1211 IWL_CMD(CSR_DBG_HPET_MEM_REG); 1341 IWL_CMD(CSR_DBG_HPET_MEM_REG);
1212 default: 1342 default:
1213 return "UNKNOWN"; 1343 return "UNKNOWN";
@@ -1240,6 +1370,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans)
1240 CSR_DRAM_INT_TBL_REG, 1370 CSR_DRAM_INT_TBL_REG,
1241 CSR_GIO_CHICKEN_BITS, 1371 CSR_GIO_CHICKEN_BITS,
1242 CSR_ANA_PLL_CFG, 1372 CSR_ANA_PLL_CFG,
1373 CSR_MONITOR_STATUS_REG,
1243 CSR_HW_REV_WA_REG, 1374 CSR_HW_REV_WA_REG,
1244 CSR_DBG_HPET_MEM_REG 1375 CSR_DBG_HPET_MEM_REG
1245 }; 1376 };