xref: /wlan-dirver/qca-wifi-host-cmn/hal/wifi3.0/hal_generic_api.h (revision 00bcc8cbd3251495b2372fa547568b4656558e1c)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 #ifndef _HAL_GENERIC_API_H_
19 #define _HAL_GENERIC_API_H_
20 
21 #include <hal_rx.h>
22 
23 /**
24  * hal_get_radiotap_he_gi_ltf() - Convert HE ltf and GI value
25  * from stats enum to radiotap enum
26  * @he_gi: HE GI value used in stats
27  * @he_ltf: HE LTF value used in stats
28  *
29  * Return: void
30  */
31 static inline void hal_get_radiotap_he_gi_ltf(uint16_t *he_gi, uint16_t *he_ltf)
32 {
33 	switch (*he_gi) {
34 	case HE_GI_0_8:
35 		*he_gi = HE_GI_RADIOTAP_0_8;
36 		break;
37 	case HE_GI_1_6:
38 		*he_gi = HE_GI_RADIOTAP_1_6;
39 		break;
40 	case HE_GI_3_2:
41 		*he_gi = HE_GI_RADIOTAP_3_2;
42 		break;
43 	default:
44 		*he_gi = HE_GI_RADIOTAP_RESERVED;
45 	}
46 
47 	switch (*he_ltf) {
48 	case HE_LTF_1_X:
49 		*he_ltf = HE_LTF_RADIOTAP_1_X;
50 		break;
51 	case HE_LTF_2_X:
52 		*he_ltf = HE_LTF_RADIOTAP_2_X;
53 		break;
54 	case HE_LTF_4_X:
55 		*he_ltf = HE_LTF_RADIOTAP_4_X;
56 		break;
57 	default:
58 		*he_ltf = HE_LTF_RADIOTAP_UNKNOWN;
59 	}
60 }
61 
62 /* channel number to freq conversion */
63 #define CHANNEL_NUM_14 14
64 #define CHANNEL_NUM_15 15
65 #define CHANNEL_NUM_27 27
66 #define CHANNEL_NUM_35 35
67 #define CHANNEL_NUM_182 182
68 #define CHANNEL_NUM_197 197
69 #define CHANNEL_FREQ_2484 2484
70 #define CHANNEL_FREQ_2407 2407
71 #define CHANNEL_FREQ_2512 2512
72 #define CHANNEL_FREQ_5000 5000
73 #define CHANNEL_FREQ_5950 5950
74 #define CHANNEL_FREQ_4000 4000
75 #define CHANNEL_FREQ_5150 5150
76 #define CHANNEL_FREQ_5920 5920
77 #define CHANNEL_FREQ_5935 5935
78 #define FREQ_MULTIPLIER_CONST_5MHZ 5
79 #define FREQ_MULTIPLIER_CONST_20MHZ 20
80 /**
81  * hal_rx_radiotap_num_to_freq() - Get frequency from chan number
82  * @chan_num - Input channel number
83  * @center_freq - Input Channel Center frequency
84  *
85  * Return - Channel frequency in Mhz
86  */
87 static uint16_t
88 hal_rx_radiotap_num_to_freq(uint16_t chan_num, qdf_freq_t center_freq)
89 {
90 	if (center_freq > CHANNEL_FREQ_5920 && center_freq < CHANNEL_FREQ_5950)
91 		return CHANNEL_FREQ_5935;
92 
93 	if (center_freq < CHANNEL_FREQ_5950) {
94 		if (chan_num == CHANNEL_NUM_14)
95 			return CHANNEL_FREQ_2484;
96 		if (chan_num < CHANNEL_NUM_14)
97 			return CHANNEL_FREQ_2407 +
98 				(chan_num * FREQ_MULTIPLIER_CONST_5MHZ);
99 
100 		if (chan_num < CHANNEL_NUM_27)
101 			return CHANNEL_FREQ_2512 +
102 				((chan_num - CHANNEL_NUM_15) *
103 					FREQ_MULTIPLIER_CONST_20MHZ);
104 
105 		if (chan_num > CHANNEL_NUM_182 &&
106 		    chan_num < CHANNEL_NUM_197)
107 			return ((chan_num * FREQ_MULTIPLIER_CONST_5MHZ) +
108 				CHANNEL_FREQ_4000);
109 
110 		return CHANNEL_FREQ_5000 +
111 			(chan_num * FREQ_MULTIPLIER_CONST_5MHZ);
112 	} else {
113 		return CHANNEL_FREQ_5950 +
114 			(chan_num * FREQ_MULTIPLIER_CONST_5MHZ);
115 	}
116 }
117 
118 /**
119  * hal_get_hw_hptp_generic()  - Get HW head and tail pointer value for any ring
120  * @hal_soc: Opaque HAL SOC handle
121  * @hal_ring: Source ring pointer
122  * @headp: Head Pointer
123  * @tailp: Tail Pointer
124  * @ring: Ring type
125  *
126  * Return: Update tail pointer and head pointer in arguments.
127  */
128 static inline
129 void hal_get_hw_hptp_generic(struct hal_soc *hal_soc,
130 			     hal_ring_handle_t hal_ring_hdl,
131 			     uint32_t *headp, uint32_t *tailp,
132 			     uint8_t ring)
133 {
134 	struct hal_srng *srng = (struct hal_srng *)hal_ring_hdl;
135 	struct hal_hw_srng_config *ring_config;
136 	enum hal_ring_type ring_type = (enum hal_ring_type)ring;
137 
138 	if (!hal_soc  || !srng) {
139 		QDF_TRACE(QDF_MODULE_ID_HAL, QDF_TRACE_LEVEL_ERROR,
140 			  "%s: Context is Null", __func__);
141 		return;
142 	}
143 
144 	ring_config = HAL_SRNG_CONFIG(hal_soc, ring_type);
145 	if (!ring_config->lmac_ring) {
146 		if (srng->ring_dir == HAL_SRNG_SRC_RING) {
147 			*headp = SRNG_SRC_REG_READ(srng, HP);
148 			*tailp = SRNG_SRC_REG_READ(srng, TP);
149 		} else {
150 			*headp = SRNG_DST_REG_READ(srng, HP);
151 			*tailp = SRNG_DST_REG_READ(srng, TP);
152 		}
153 	}
154 }
155 
156 #if defined(WBM_IDLE_LSB_WRITE_CONFIRM_WAR)
157 /**
158  * hal_wbm_idle_lsb_write_confirm() - Check and update WBM_IDLE_LINK ring LSB
159  * @srng: srng handle
160  *
161  * Return: None
162  */
163 static void hal_wbm_idle_lsb_write_confirm(struct hal_srng *srng)
164 {
165 	if (srng->ring_id == HAL_SRNG_WBM_IDLE_LINK) {
166 		while (SRNG_SRC_REG_READ(srng, BASE_LSB) !=
167 		       ((unsigned int)srng->ring_base_paddr & 0xffffffff))
168 				SRNG_SRC_REG_WRITE(srng, BASE_LSB,
169 						   srng->ring_base_paddr &
170 						   0xffffffff);
171 	}
172 }
173 #else
174 static void hal_wbm_idle_lsb_write_confirm(struct hal_srng *srng)
175 {
176 }
177 #endif
178 
179 /**
180  * hal_srng_src_hw_init - Private function to initialize SRNG
181  * source ring HW
182  * @hal_soc: HAL SOC handle
183  * @srng: SRNG ring pointer
184  */
185 static inline
186 void hal_srng_src_hw_init_generic(struct hal_soc *hal,
187 				  struct hal_srng *srng)
188 {
189 	uint32_t reg_val = 0;
190 	uint64_t tp_addr = 0;
191 
192 	hal_debug("hw_init srng %d", srng->ring_id);
193 
194 	if (srng->flags & HAL_SRNG_MSI_INTR) {
195 		SRNG_SRC_REG_WRITE(srng, MSI1_BASE_LSB,
196 			srng->msi_addr & 0xffffffff);
197 		reg_val = SRNG_SM(SRNG_SRC_FLD(MSI1_BASE_MSB, ADDR),
198 			(uint64_t)(srng->msi_addr) >> 32) |
199 			SRNG_SM(SRNG_SRC_FLD(MSI1_BASE_MSB,
200 			MSI1_ENABLE), 1);
201 		SRNG_SRC_REG_WRITE(srng, MSI1_BASE_MSB, reg_val);
202 		SRNG_SRC_REG_WRITE(srng, MSI1_DATA,
203 				   qdf_cpu_to_le32(srng->msi_data));
204 	}
205 
206 	SRNG_SRC_REG_WRITE(srng, BASE_LSB, srng->ring_base_paddr & 0xffffffff);
207 	hal_wbm_idle_lsb_write_confirm(srng);
208 
209 	reg_val = SRNG_SM(SRNG_SRC_FLD(BASE_MSB, RING_BASE_ADDR_MSB),
210 		((uint64_t)(srng->ring_base_paddr) >> 32)) |
211 		SRNG_SM(SRNG_SRC_FLD(BASE_MSB, RING_SIZE),
212 		srng->entry_size * srng->num_entries);
213 	SRNG_SRC_REG_WRITE(srng, BASE_MSB, reg_val);
214 
215 	reg_val = SRNG_SM(SRNG_SRC_FLD(ID, ENTRY_SIZE), srng->entry_size);
216 	SRNG_SRC_REG_WRITE(srng, ID, reg_val);
217 
218 	/**
219 	 * Interrupt setup:
220 	 * Default interrupt mode is 'pulse'. Need to setup SW_INTERRUPT_MODE
221 	 * if level mode is required
222 	 */
223 	reg_val = 0;
224 
225 	/*
226 	 * WAR - Hawkeye v1 has a hardware bug which requires timer value to be
227 	 * programmed in terms of 1us resolution instead of 8us resolution as
228 	 * given in MLD.
229 	 */
230 	if (srng->intr_timer_thres_us) {
231 		reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX0,
232 			INTERRUPT_TIMER_THRESHOLD),
233 			srng->intr_timer_thres_us);
234 		/* For HK v2 this should be (srng->intr_timer_thres_us >> 3) */
235 	}
236 
237 	if (srng->intr_batch_cntr_thres_entries) {
238 		reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX0,
239 			BATCH_COUNTER_THRESHOLD),
240 			srng->intr_batch_cntr_thres_entries *
241 			srng->entry_size);
242 	}
243 	SRNG_SRC_REG_WRITE(srng, CONSUMER_INT_SETUP_IX0, reg_val);
244 
245 	reg_val = 0;
246 	if (srng->flags & HAL_SRNG_LOW_THRES_INTR_ENABLE) {
247 		reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX1,
248 			LOW_THRESHOLD), srng->u.src_ring.low_threshold);
249 	}
250 
251 	SRNG_SRC_REG_WRITE(srng, CONSUMER_INT_SETUP_IX1, reg_val);
252 
253 	/* As per HW team, TP_ADDR and HP_ADDR for Idle link ring should
254 	 * remain 0 to avoid some WBM stability issues. Remote head/tail
255 	 * pointers are not required since this ring is completely managed
256 	 * by WBM HW
257 	 */
258 	reg_val = 0;
259 	if (srng->ring_id != HAL_SRNG_WBM_IDLE_LINK) {
260 		tp_addr = (uint64_t)(hal->shadow_rdptr_mem_paddr +
261 			((unsigned long)(srng->u.src_ring.tp_addr) -
262 			(unsigned long)(hal->shadow_rdptr_mem_vaddr)));
263 		SRNG_SRC_REG_WRITE(srng, TP_ADDR_LSB, tp_addr & 0xffffffff);
264 		SRNG_SRC_REG_WRITE(srng, TP_ADDR_MSB, tp_addr >> 32);
265 	} else {
266 		reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, RING_ID_DISABLE), 1);
267 	}
268 
269 	/* Initilaize head and tail pointers to indicate ring is empty */
270 	SRNG_SRC_REG_WRITE(srng, HP, 0);
271 	SRNG_SRC_REG_WRITE(srng, TP, 0);
272 	*(srng->u.src_ring.tp_addr) = 0;
273 
274 	reg_val |= ((srng->flags & HAL_SRNG_DATA_TLV_SWAP) ?
275 			SRNG_SM(SRNG_SRC_FLD(MISC, DATA_TLV_SWAP_BIT), 1) : 0) |
276 			((srng->flags & HAL_SRNG_RING_PTR_SWAP) ?
277 			SRNG_SM(SRNG_SRC_FLD(MISC, HOST_FW_SWAP_BIT), 1) : 0) |
278 			((srng->flags & HAL_SRNG_MSI_SWAP) ?
279 			SRNG_SM(SRNG_SRC_FLD(MISC, MSI_SWAP_BIT), 1) : 0);
280 
281 	/* Loop count is not used for SRC rings */
282 	reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, LOOPCNT_DISABLE), 1);
283 
284 	/*
285 	 * reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, SRNG_ENABLE), 1);
286 	 * todo: update fw_api and replace with above line
287 	 * (when SRNG_ENABLE field for the MISC register is available in fw_api)
288 	 * (WCSS_UMAC_CE_0_SRC_WFSS_CE_CHANNEL_SRC_R0_SRC_RING_MISC)
289 	 */
290 	reg_val |= 0x40;
291 
292 	SRNG_SRC_REG_WRITE(srng, MISC, reg_val);
293 }
294 
295 /**
296  * hal_srng_dst_hw_init - Private function to initialize SRNG
297  * destination ring HW
298  * @hal_soc: HAL SOC handle
299  * @srng: SRNG ring pointer
300  */
301 static inline
302 void hal_srng_dst_hw_init_generic(struct hal_soc *hal,
303 				  struct hal_srng *srng)
304 {
305 	uint32_t reg_val = 0;
306 	uint64_t hp_addr = 0;
307 
308 	hal_debug("hw_init srng %d", srng->ring_id);
309 
310 	if (srng->flags & HAL_SRNG_MSI_INTR) {
311 		SRNG_DST_REG_WRITE(srng, MSI1_BASE_LSB,
312 			srng->msi_addr & 0xffffffff);
313 		reg_val = SRNG_SM(SRNG_DST_FLD(MSI1_BASE_MSB, ADDR),
314 			(uint64_t)(srng->msi_addr) >> 32) |
315 			SRNG_SM(SRNG_DST_FLD(MSI1_BASE_MSB,
316 			MSI1_ENABLE), 1);
317 		SRNG_DST_REG_WRITE(srng, MSI1_BASE_MSB, reg_val);
318 		SRNG_DST_REG_WRITE(srng, MSI1_DATA,
319 				   qdf_cpu_to_le32(srng->msi_data));
320 	}
321 
322 	SRNG_DST_REG_WRITE(srng, BASE_LSB, srng->ring_base_paddr & 0xffffffff);
323 	reg_val = SRNG_SM(SRNG_DST_FLD(BASE_MSB, RING_BASE_ADDR_MSB),
324 		((uint64_t)(srng->ring_base_paddr) >> 32)) |
325 		SRNG_SM(SRNG_DST_FLD(BASE_MSB, RING_SIZE),
326 		srng->entry_size * srng->num_entries);
327 	SRNG_DST_REG_WRITE(srng, BASE_MSB, reg_val);
328 
329 	reg_val = SRNG_SM(SRNG_DST_FLD(ID, RING_ID), srng->ring_id) |
330 		SRNG_SM(SRNG_DST_FLD(ID, ENTRY_SIZE), srng->entry_size);
331 	SRNG_DST_REG_WRITE(srng, ID, reg_val);
332 
333 
334 	/**
335 	 * Interrupt setup:
336 	 * Default interrupt mode is 'pulse'. Need to setup SW_INTERRUPT_MODE
337 	 * if level mode is required
338 	 */
339 	reg_val = 0;
340 	if (srng->intr_timer_thres_us) {
341 		reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT_SETUP,
342 			INTERRUPT_TIMER_THRESHOLD),
343 			srng->intr_timer_thres_us >> 3);
344 	}
345 
346 	if (srng->intr_batch_cntr_thres_entries) {
347 		reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT_SETUP,
348 			BATCH_COUNTER_THRESHOLD),
349 			srng->intr_batch_cntr_thres_entries *
350 			srng->entry_size);
351 	}
352 
353 	SRNG_DST_REG_WRITE(srng, PRODUCER_INT_SETUP, reg_val);
354 	hp_addr = (uint64_t)(hal->shadow_rdptr_mem_paddr +
355 		((unsigned long)(srng->u.dst_ring.hp_addr) -
356 		(unsigned long)(hal->shadow_rdptr_mem_vaddr)));
357 	SRNG_DST_REG_WRITE(srng, HP_ADDR_LSB, hp_addr & 0xffffffff);
358 	SRNG_DST_REG_WRITE(srng, HP_ADDR_MSB, hp_addr >> 32);
359 
360 	/* Initilaize head and tail pointers to indicate ring is empty */
361 	SRNG_DST_REG_WRITE(srng, HP, 0);
362 	SRNG_DST_REG_WRITE(srng, TP, 0);
363 	*(srng->u.dst_ring.hp_addr) = 0;
364 
365 	reg_val = ((srng->flags & HAL_SRNG_DATA_TLV_SWAP) ?
366 			SRNG_SM(SRNG_DST_FLD(MISC, DATA_TLV_SWAP_BIT), 1) : 0) |
367 			((srng->flags & HAL_SRNG_RING_PTR_SWAP) ?
368 			SRNG_SM(SRNG_DST_FLD(MISC, HOST_FW_SWAP_BIT), 1) : 0) |
369 			((srng->flags & HAL_SRNG_MSI_SWAP) ?
370 			SRNG_SM(SRNG_DST_FLD(MISC, MSI_SWAP_BIT), 1) : 0);
371 
372 	/*
373 	 * reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, SRNG_ENABLE), 1);
374 	 * todo: update fw_api and replace with above line
375 	 * (when SRNG_ENABLE field for the MISC register is available in fw_api)
376 	 * (WCSS_UMAC_CE_0_SRC_WFSS_CE_CHANNEL_SRC_R0_SRC_RING_MISC)
377 	 */
378 	reg_val |= 0x40;
379 
380 	SRNG_DST_REG_WRITE(srng, MISC, reg_val);
381 
382 }
383 #endif /* HAL_GENERIC_API_H_ */
384