1e705c121SKalle Valo /******************************************************************************
2e705c121SKalle Valo  *
3e705c121SKalle Valo  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
414ef1b43SGolan Ben-Ami  * Copyright(c) 2015 Intel Deutschland GmbH
5e705c121SKalle Valo  *
6e705c121SKalle Valo  * Portions of this file are derived from the ipw3945 project.
7e705c121SKalle Valo  *
8e705c121SKalle Valo  * This program is free software; you can redistribute it and/or modify it
9e705c121SKalle Valo  * under the terms of version 2 of the GNU General Public License as
10e705c121SKalle Valo  * published by the Free Software Foundation.
11e705c121SKalle Valo  *
12e705c121SKalle Valo  * This program is distributed in the hope that it will be useful, but WITHOUT
13e705c121SKalle Valo  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14e705c121SKalle Valo  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15e705c121SKalle Valo  * more details.
16e705c121SKalle Valo  *
17e705c121SKalle Valo  * You should have received a copy of the GNU General Public License along with
18e705c121SKalle Valo  * this program; if not, write to the Free Software Foundation, Inc.,
19e705c121SKalle Valo  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
20e705c121SKalle Valo  *
21e705c121SKalle Valo  * The full GNU General Public License is included in this distribution in the
22e705c121SKalle Valo  * file called LICENSE.
23e705c121SKalle Valo  *
24e705c121SKalle Valo  * Contact Information:
25cb2f8277SEmmanuel Grumbach  *  Intel Linux Wireless <linuxwifi@intel.com>
26e705c121SKalle Valo  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27e705c121SKalle Valo  *
28e705c121SKalle Valo  *****************************************************************************/
29e705c121SKalle Valo #include <linux/delay.h>
30e705c121SKalle Valo #include <linux/device.h>
31e705c121SKalle Valo #include <linux/export.h>
32e705c121SKalle Valo 
33e705c121SKalle Valo #include "iwl-drv.h"
34e705c121SKalle Valo #include "iwl-io.h"
35e705c121SKalle Valo #include "iwl-csr.h"
36e705c121SKalle Valo #include "iwl-debug.h"
37e705c121SKalle Valo #include "iwl-prph.h"
38e705c121SKalle Valo #include "iwl-fh.h"
39e705c121SKalle Valo 
40e705c121SKalle Valo void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val)
41e705c121SKalle Valo {
42e705c121SKalle Valo 	trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val);
43e705c121SKalle Valo 	iwl_trans_write8(trans, ofs, val);
44e705c121SKalle Valo }
45e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write8);
46e705c121SKalle Valo 
47e705c121SKalle Valo void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val)
48e705c121SKalle Valo {
49e705c121SKalle Valo 	trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val);
50e705c121SKalle Valo 	iwl_trans_write32(trans, ofs, val);
51e705c121SKalle Valo }
52e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write32);
53e705c121SKalle Valo 
54e705c121SKalle Valo u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
55e705c121SKalle Valo {
56e705c121SKalle Valo 	u32 val = iwl_trans_read32(trans, ofs);
57e705c121SKalle Valo 
58e705c121SKalle Valo 	trace_iwlwifi_dev_ioread32(trans->dev, ofs, val);
59e705c121SKalle Valo 	return val;
60e705c121SKalle Valo }
61e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read32);
62e705c121SKalle Valo 
63e705c121SKalle Valo #define IWL_POLL_INTERVAL 10	/* microseconds */
64e705c121SKalle Valo 
65e705c121SKalle Valo int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
66e705c121SKalle Valo 		 u32 bits, u32 mask, int timeout)
67e705c121SKalle Valo {
68e705c121SKalle Valo 	int t = 0;
69e705c121SKalle Valo 
70e705c121SKalle Valo 	do {
71e705c121SKalle Valo 		if ((iwl_read32(trans, addr) & mask) == (bits & mask))
72e705c121SKalle Valo 			return t;
73e705c121SKalle Valo 		udelay(IWL_POLL_INTERVAL);
74e705c121SKalle Valo 		t += IWL_POLL_INTERVAL;
75e705c121SKalle Valo 	} while (t < timeout);
76e705c121SKalle Valo 
77e705c121SKalle Valo 	return -ETIMEDOUT;
78e705c121SKalle Valo }
79e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_poll_bit);
80e705c121SKalle Valo 
81e705c121SKalle Valo u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
82e705c121SKalle Valo {
83e705c121SKalle Valo 	u32 value = 0x5a5a5a5a;
84e705c121SKalle Valo 	unsigned long flags;
8523ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
86e705c121SKalle Valo 		value = iwl_read32(trans, reg);
87e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
88e705c121SKalle Valo 	}
89e705c121SKalle Valo 
90e705c121SKalle Valo 	return value;
91e705c121SKalle Valo }
92e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read_direct32);
93e705c121SKalle Valo 
94e705c121SKalle Valo void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
95e705c121SKalle Valo {
96e705c121SKalle Valo 	unsigned long flags;
97e705c121SKalle Valo 
9823ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
99e705c121SKalle Valo 		iwl_write32(trans, reg, value);
100e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
101e705c121SKalle Valo 	}
102e705c121SKalle Valo }
103e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write_direct32);
104e705c121SKalle Valo 
105e705c121SKalle Valo int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
106e705c121SKalle Valo 			int timeout)
107e705c121SKalle Valo {
108e705c121SKalle Valo 	int t = 0;
109e705c121SKalle Valo 
110e705c121SKalle Valo 	do {
111e705c121SKalle Valo 		if ((iwl_read_direct32(trans, addr) & mask) == mask)
112e705c121SKalle Valo 			return t;
113e705c121SKalle Valo 		udelay(IWL_POLL_INTERVAL);
114e705c121SKalle Valo 		t += IWL_POLL_INTERVAL;
115e705c121SKalle Valo 	} while (t < timeout);
116e705c121SKalle Valo 
117e705c121SKalle Valo 	return -ETIMEDOUT;
118e705c121SKalle Valo }
119e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
120e705c121SKalle Valo 
12114ef1b43SGolan Ben-Ami u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs)
122e705c121SKalle Valo {
123e705c121SKalle Valo 	u32 val = iwl_trans_read_prph(trans, ofs);
124e705c121SKalle Valo 	trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val);
125e705c121SKalle Valo 	return val;
126e705c121SKalle Valo }
12714ef1b43SGolan Ben-Ami IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab);
128e705c121SKalle Valo 
12914ef1b43SGolan Ben-Ami void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val)
130e705c121SKalle Valo {
131e705c121SKalle Valo 	trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val);
132e705c121SKalle Valo 	iwl_trans_write_prph(trans, ofs, val);
133e705c121SKalle Valo }
13414ef1b43SGolan Ben-Ami IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab);
135e705c121SKalle Valo 
136e705c121SKalle Valo u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
137e705c121SKalle Valo {
138e705c121SKalle Valo 	unsigned long flags;
139e705c121SKalle Valo 	u32 val = 0x5a5a5a5a;
140e705c121SKalle Valo 
14123ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
14214ef1b43SGolan Ben-Ami 		val = iwl_read_prph_no_grab(trans, ofs);
143e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
144e705c121SKalle Valo 	}
145e705c121SKalle Valo 	return val;
146e705c121SKalle Valo }
147e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read_prph);
148e705c121SKalle Valo 
149e705c121SKalle Valo void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
150e705c121SKalle Valo {
151e705c121SKalle Valo 	unsigned long flags;
152e705c121SKalle Valo 
15323ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
15414ef1b43SGolan Ben-Ami 		iwl_write_prph_no_grab(trans, ofs, val);
155e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
156e705c121SKalle Valo 	}
157e705c121SKalle Valo }
158e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write_prph);
159e705c121SKalle Valo 
160e705c121SKalle Valo int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
161e705c121SKalle Valo 		      u32 bits, u32 mask, int timeout)
162e705c121SKalle Valo {
163e705c121SKalle Valo 	int t = 0;
164e705c121SKalle Valo 
165e705c121SKalle Valo 	do {
166e705c121SKalle Valo 		if ((iwl_read_prph(trans, addr) & mask) == (bits & mask))
167e705c121SKalle Valo 			return t;
168e705c121SKalle Valo 		udelay(IWL_POLL_INTERVAL);
169e705c121SKalle Valo 		t += IWL_POLL_INTERVAL;
170e705c121SKalle Valo 	} while (t < timeout);
171e705c121SKalle Valo 
172e705c121SKalle Valo 	return -ETIMEDOUT;
173e705c121SKalle Valo }
174e705c121SKalle Valo 
175e705c121SKalle Valo void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
176e705c121SKalle Valo {
177e705c121SKalle Valo 	unsigned long flags;
178e705c121SKalle Valo 
17923ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
18014ef1b43SGolan Ben-Ami 		iwl_write_prph_no_grab(trans, ofs,
18114ef1b43SGolan Ben-Ami 				       iwl_read_prph_no_grab(trans, ofs) |
18214ef1b43SGolan Ben-Ami 				       mask);
183e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
184e705c121SKalle Valo 	}
185e705c121SKalle Valo }
186e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_set_bits_prph);
187e705c121SKalle Valo 
188e705c121SKalle Valo void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
189e705c121SKalle Valo 			    u32 bits, u32 mask)
190e705c121SKalle Valo {
191e705c121SKalle Valo 	unsigned long flags;
192e705c121SKalle Valo 
19323ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
19414ef1b43SGolan Ben-Ami 		iwl_write_prph_no_grab(trans, ofs,
19514ef1b43SGolan Ben-Ami 				       (iwl_read_prph_no_grab(trans, ofs) &
19614ef1b43SGolan Ben-Ami 					mask) | bits);
197e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
198e705c121SKalle Valo 	}
199e705c121SKalle Valo }
200e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph);
201e705c121SKalle Valo 
202e705c121SKalle Valo void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
203e705c121SKalle Valo {
204e705c121SKalle Valo 	unsigned long flags;
205e705c121SKalle Valo 	u32 val;
206e705c121SKalle Valo 
20723ba9340SEmmanuel Grumbach 	if (iwl_trans_grab_nic_access(trans, &flags)) {
20814ef1b43SGolan Ben-Ami 		val = iwl_read_prph_no_grab(trans, ofs);
20914ef1b43SGolan Ben-Ami 		iwl_write_prph_no_grab(trans, ofs, (val & ~mask));
210e705c121SKalle Valo 		iwl_trans_release_nic_access(trans, &flags);
211e705c121SKalle Valo 	}
212e705c121SKalle Valo }
213e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
214e705c121SKalle Valo 
215e705c121SKalle Valo void iwl_force_nmi(struct iwl_trans *trans)
216e705c121SKalle Valo {
217e705c121SKalle Valo 	if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
218e705c121SKalle Valo 		iwl_write_prph(trans, DEVICE_SET_NMI_REG,
219e705c121SKalle Valo 			       DEVICE_SET_NMI_VAL_DRV);
220e705c121SKalle Valo 		iwl_write_prph(trans, DEVICE_SET_NMI_REG,
221e705c121SKalle Valo 			       DEVICE_SET_NMI_VAL_HW);
222e705c121SKalle Valo 	} else {
223e705c121SKalle Valo 		iwl_write_prph(trans, DEVICE_SET_NMI_8000_REG,
224e705c121SKalle Valo 			       DEVICE_SET_NMI_8000_VAL);
225e705c121SKalle Valo 		iwl_write_prph(trans, DEVICE_SET_NMI_REG,
226e705c121SKalle Valo 			       DEVICE_SET_NMI_VAL_DRV);
227e705c121SKalle Valo 	}
228e705c121SKalle Valo }
229e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_force_nmi);
230e705c121SKalle Valo 
231e705c121SKalle Valo static const char *get_fh_string(int cmd)
232e705c121SKalle Valo {
233e705c121SKalle Valo #define IWL_CMD(x) case x: return #x
234e705c121SKalle Valo 	switch (cmd) {
235e705c121SKalle Valo 	IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
236e705c121SKalle Valo 	IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
237e705c121SKalle Valo 	IWL_CMD(FH_RSCSR_CHNL0_WPTR);
238e705c121SKalle Valo 	IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
239e705c121SKalle Valo 	IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
240e705c121SKalle Valo 	IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
241e705c121SKalle Valo 	IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
242e705c121SKalle Valo 	IWL_CMD(FH_TSSR_TX_STATUS_REG);
243e705c121SKalle Valo 	IWL_CMD(FH_TSSR_TX_ERROR_REG);
244e705c121SKalle Valo 	default:
245e705c121SKalle Valo 		return "UNKNOWN";
246e705c121SKalle Valo 	}
247e705c121SKalle Valo #undef IWL_CMD
248e705c121SKalle Valo }
249e705c121SKalle Valo 
250e705c121SKalle Valo int iwl_dump_fh(struct iwl_trans *trans, char **buf)
251e705c121SKalle Valo {
252e705c121SKalle Valo 	int i;
253e705c121SKalle Valo 	static const u32 fh_tbl[] = {
254e705c121SKalle Valo 		FH_RSCSR_CHNL0_STTS_WPTR_REG,
255e705c121SKalle Valo 		FH_RSCSR_CHNL0_RBDCB_BASE_REG,
256e705c121SKalle Valo 		FH_RSCSR_CHNL0_WPTR,
257e705c121SKalle Valo 		FH_MEM_RCSR_CHNL0_CONFIG_REG,
258e705c121SKalle Valo 		FH_MEM_RSSR_SHARED_CTRL_REG,
259e705c121SKalle Valo 		FH_MEM_RSSR_RX_STATUS_REG,
260e705c121SKalle Valo 		FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
261e705c121SKalle Valo 		FH_TSSR_TX_STATUS_REG,
262e705c121SKalle Valo 		FH_TSSR_TX_ERROR_REG
263e705c121SKalle Valo 	};
264e705c121SKalle Valo 
265e705c121SKalle Valo #ifdef CONFIG_IWLWIFI_DEBUGFS
266e705c121SKalle Valo 	if (buf) {
267e705c121SKalle Valo 		int pos = 0;
268e705c121SKalle Valo 		size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
269e705c121SKalle Valo 
270e705c121SKalle Valo 		*buf = kmalloc(bufsz, GFP_KERNEL);
271e705c121SKalle Valo 		if (!*buf)
272e705c121SKalle Valo 			return -ENOMEM;
273e705c121SKalle Valo 
274e705c121SKalle Valo 		pos += scnprintf(*buf + pos, bufsz - pos,
275e705c121SKalle Valo 				"FH register values:\n");
276e705c121SKalle Valo 
277e705c121SKalle Valo 		for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
278e705c121SKalle Valo 			pos += scnprintf(*buf + pos, bufsz - pos,
279e705c121SKalle Valo 				"  %34s: 0X%08x\n",
280e705c121SKalle Valo 				get_fh_string(fh_tbl[i]),
281e705c121SKalle Valo 				iwl_read_direct32(trans, fh_tbl[i]));
282e705c121SKalle Valo 
283e705c121SKalle Valo 		return pos;
284e705c121SKalle Valo 	}
285e705c121SKalle Valo #endif
286e705c121SKalle Valo 
287e705c121SKalle Valo 	IWL_ERR(trans, "FH register values:\n");
288e705c121SKalle Valo 	for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++)
289e705c121SKalle Valo 		IWL_ERR(trans, "  %34s: 0X%08x\n",
290e705c121SKalle Valo 			get_fh_string(fh_tbl[i]),
291e705c121SKalle Valo 			iwl_read_direct32(trans, fh_tbl[i]));
292e705c121SKalle Valo 
293e705c121SKalle Valo 	return 0;
294e705c121SKalle Valo }
295