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