1 /*
2 * Copyright 2023, Cypress Semiconductor Corporation (an Infineon company)
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /** @file
19 * Broadcom WLAN SDIO Protocol interface
20 *
21 * Implements the WHD Bus Protocol Interface for SDIO
22 * Provides functions for initialising, de-intitialising 802.11 device,
23 * sending/receiving raw packets etc
24 */
25
26 #include "cybsp.h"
27 #include "whd_utils.h"
28 #if (CYBSP_WIFI_INTERFACE_TYPE == CYBSP_SDIO_INTERFACE)
29
30 #include "cyabs_rtos.h"
31
32 #include "whd_bus_sdio_protocol.h"
33 #include "whd_bus.h"
34 #include "whd_bus_common.h"
35 #include "whd_chip_reg.h"
36 #include "whd_chip_constants.h"
37 #include "whd_int.h"
38 #include "whd_chip.h"
39 #include "whd_sdpcm.h"
40 #include "whd_debug.h"
41 #include "whd_sdio.h"
42 #include "whd_buffer_api.h"
43 #include "whd_resource_if.h"
44 #include "whd_types_int.h"
45 #include "whd_types.h"
46
47
48 /******************************************************
49 * Constants
50 ******************************************************/
51 /* function 1 OCP space */
52 #define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */
53 #define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
54 #define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */
55
56 #define F0_WORKING_TIMEOUT_MS (500)
57 #define F1_AVAIL_TIMEOUT_MS (500)
58 #define F2_AVAIL_TIMEOUT_MS (500)
59 #define F2_READY_TIMEOUT_MS (1000)
60 #define ALP_AVAIL_TIMEOUT_MS (100)
61 #define HT_AVAIL_TIMEOUT_MS (500)
62 #define ABORT_TIMEOUT_MS (100)
63 /* Taken from FALCON_5_90_195_26 dhd/sys/dhd_sdio.c. */
64 #define SDIO_F2_WATERMARK (8)
65
66 #define INITIAL_READ 4
67
68 #define WHD_THREAD_POLL_TIMEOUT (CY_RTOS_NEVER_TIMEOUT)
69
70 #define WHD_THREAD_POKE_TIMEOUT (100)
71
72 #define HOSTINTMASK (I_HMB_SW_MASK)
73
74
75 /******************************************************
76 * Structures
77 ******************************************************/
78 struct whd_bus_priv
79 {
80 whd_sdio_config_t sdio_config;
81 whd_bus_stats_t whd_bus_stats;
82 whd_sdio_t *sdio_obj;
83
84 };
85
86 #ifndef WHD_USE_CUSTOM_HAL_IMPL
87 /* For BSP backward compatible, should be removed the macro once 1.0 is not supported */
88 #if (CYHAL_API_VERSION >= 2)
89 typedef cyhal_sdio_transfer_type_t cyhal_sdio_transfer_t;
90 #else
91 typedef cyhal_transfer_t cyhal_sdio_transfer_t;
92 #endif /* (CYHAL_API_VERSION >= 2) */
93 #endif /* WHD_USE_CUSTOM_HAL_IMPL */
94
95 /******************************************************
96 * Variables
97 ******************************************************/
98
99 /******************************************************
100 * Static Function Declarations
101 ******************************************************/
102
103 static whd_result_t whd_bus_sdio_transfer(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
104 whd_bus_function_t function, uint32_t address, uint16_t data_size,
105 uint8_t *data, sdio_response_needed_t response_expected);
106 whd_result_t whd_bus_sdio_cmd52(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
107 whd_bus_function_t function, uint32_t address, uint8_t value,
108 sdio_response_needed_t response_expected, uint8_t *response);
109 whd_result_t whd_bus_sdio_cmd53(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
110 whd_bus_function_t function, sdio_transfer_mode_t mode, uint32_t address,
111 uint16_t data_size, uint8_t *data,
112 sdio_response_needed_t response_expected,
113 uint32_t *response);
114 static whd_result_t whd_bus_sdio_abort_read(whd_driver_t whd_driver, whd_bool_t retry);
115 static whd_result_t whd_bus_sdio_download_firmware(whd_driver_t whd_driver);
116
117 static whd_result_t whd_bus_sdio_set_oob_interrupt(whd_driver_t whd_driver, uint8_t gpio_pin_number);
118
119 #ifndef WHD_USE_CUSTOM_HAL_IMPL
120 #if (CYHAL_API_VERSION >= 2)
121 static void whd_bus_sdio_irq_handler(void *handler_arg, cyhal_sdio_event_t event);
122 static void whd_bus_sdio_oob_irq_handler(void *arg, cyhal_gpio_event_t event);
123 #else
124 static void whd_bus_sdio_irq_handler(void *handler_arg, cyhal_sdio_irq_event_t event);
125 static void whd_bus_sdio_oob_irq_handler(void *arg, cyhal_gpio_irq_event_t event);
126 #endif /* (CYHAL_API_VERSION >= 2) */
127 #endif /* WHD_USE_CUSTOM_HAL_IMPL */
128
129 whd_result_t whd_bus_sdio_irq_enable(whd_driver_t whd_driver, whd_bool_t enable);
130 whd_result_t whd_bus_sdio_irq_register(whd_driver_t whd_driver);
131 whd_result_t whd_bus_sdio_enable_oob_intr(whd_driver_t whd_driver, whd_bool_t enable);
132 whd_result_t whd_bus_sdio_register_oob_intr(whd_driver_t whd_driver);
133 whd_result_t whd_bus_sdio_unregister_oob_intr(whd_driver_t whd_driver);
134
135 static whd_result_t whd_bus_sdio_init_oob_intr(whd_driver_t whd_driver);
136 static whd_result_t whd_bus_sdio_deinit_oob_intr(whd_driver_t whd_driver);
137 static whd_result_t whd_bus_sdio_download_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
138 whd_bool_t direct_resource, uint32_t address, uint32_t image_size);
139 static whd_result_t whd_bus_sdio_write_wifi_nvram_image(whd_driver_t whd_driver);
140 /******************************************************
141 * Global Function definitions
142 ******************************************************/
143
whd_bus_sdio_attach(whd_driver_t whd_driver,whd_sdio_config_t * whd_sdio_config,whd_sdio_t * sdio_obj)144 uint32_t whd_bus_sdio_attach(whd_driver_t whd_driver, whd_sdio_config_t *whd_sdio_config, whd_sdio_t *sdio_obj)
145 {
146 struct whd_bus_info *whd_bus_info;
147
148 if (!whd_driver || !whd_sdio_config)
149 {
150 WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
151 __func__, __LINE__) );
152 return WHD_WLAN_BADARG;
153 }
154
155 whd_bus_info = (whd_bus_info_t *)whd_mem_malloc(sizeof(whd_bus_info_t) );
156
157 if (whd_bus_info == NULL)
158 {
159 WPRINT_WHD_ERROR( ("Memory allocation failed for whd_bus_info in %s\n", __FUNCTION__) );
160 return WHD_BUFFER_UNAVAILABLE_PERMANENT;
161 }
162 memset(whd_bus_info, 0, sizeof(whd_bus_info_t) );
163
164 whd_driver->bus_if = whd_bus_info;
165
166 whd_driver->bus_priv = (struct whd_bus_priv *)whd_mem_malloc(sizeof(struct whd_bus_priv) );
167
168 if (whd_driver->bus_priv == NULL)
169 {
170 WPRINT_WHD_ERROR( ("Memory allocation failed for whd_bus_priv in %s\n", __FUNCTION__) );
171 return WHD_BUFFER_UNAVAILABLE_PERMANENT;
172 }
173 memset(whd_driver->bus_priv, 0, sizeof(struct whd_bus_priv) );
174
175 whd_driver->bus_priv->sdio_obj = sdio_obj;
176 whd_driver->bus_priv->sdio_config = *whd_sdio_config;
177
178 whd_bus_info->whd_bus_init_fptr = whd_bus_sdio_init;
179 whd_bus_info->whd_bus_deinit_fptr = whd_bus_sdio_deinit;
180
181 whd_bus_info->whd_bus_write_backplane_value_fptr = whd_bus_sdio_write_backplane_value;
182 whd_bus_info->whd_bus_read_backplane_value_fptr = whd_bus_sdio_read_backplane_value;
183 whd_bus_info->whd_bus_write_register_value_fptr = whd_bus_sdio_write_register_value;
184 whd_bus_info->whd_bus_read_register_value_fptr = whd_bus_sdio_read_register_value;
185
186 whd_bus_info->whd_bus_send_buffer_fptr = whd_bus_sdio_send_buffer;
187 whd_bus_info->whd_bus_transfer_bytes_fptr = whd_bus_sdio_transfer_bytes;
188
189 whd_bus_info->whd_bus_read_frame_fptr = whd_bus_sdio_read_frame;
190
191 whd_bus_info->whd_bus_packet_available_to_read_fptr = whd_bus_sdio_packet_available_to_read;
192 whd_bus_info->whd_bus_poke_wlan_fptr = whd_bus_sdio_poke_wlan;
193 whd_bus_info->whd_bus_wait_for_wlan_event_fptr = whd_bus_sdio_wait_for_wlan_event;
194
195 whd_bus_info->whd_bus_ack_interrupt_fptr = whd_bus_sdio_ack_interrupt;
196 whd_bus_info->whd_bus_wake_interrupt_present_fptr = whd_bus_sdio_wake_interrupt_present;
197
198 whd_bus_info->whd_bus_wakeup_fptr = whd_bus_sdio_wakeup;
199 whd_bus_info->whd_bus_sleep_fptr = whd_bus_sdio_sleep;
200
201 whd_bus_info->whd_bus_backplane_read_padd_size_fptr = whd_bus_sdio_backplane_read_padd_size;
202 whd_bus_info->whd_bus_use_status_report_scheme_fptr = whd_bus_sdio_use_status_report_scheme;
203
204 whd_bus_info->whd_bus_get_max_transfer_size_fptr = whd_bus_sdio_get_max_transfer_size;
205
206 whd_bus_info->whd_bus_init_stats_fptr = whd_bus_sdio_init_stats;
207 whd_bus_info->whd_bus_print_stats_fptr = whd_bus_sdio_print_stats;
208 whd_bus_info->whd_bus_reinit_stats_fptr = whd_bus_sdio_reinit_stats;
209 whd_bus_info->whd_bus_irq_register_fptr = whd_bus_sdio_irq_register;
210 whd_bus_info->whd_bus_irq_enable_fptr = whd_bus_sdio_irq_enable;
211 whd_bus_info->whd_bus_download_resource_fptr = whd_bus_sdio_download_resource;
212 whd_bus_info->whd_bus_set_backplane_window_fptr = whd_bus_sdio_set_backplane_window;
213 return WHD_SUCCESS;
214 }
215
whd_bus_sdio_detach(whd_driver_t whd_driver)216 void whd_bus_sdio_detach(whd_driver_t whd_driver)
217 {
218 if (whd_driver->bus_if != NULL)
219 {
220 whd_mem_free(whd_driver->bus_if);
221 whd_driver->bus_if = NULL;
222 }
223 if (whd_driver->bus_priv != NULL)
224 {
225 whd_mem_free(whd_driver->bus_priv);
226 whd_driver->bus_priv = NULL;
227 }
228 }
229
whd_bus_sdio_ack_interrupt(whd_driver_t whd_driver,uint32_t intstatus)230 whd_result_t whd_bus_sdio_ack_interrupt(whd_driver_t whd_driver, uint32_t intstatus)
231 {
232 return whd_bus_write_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4, intstatus);
233 }
234
whd_bus_sdio_wait_for_wlan_event(whd_driver_t whd_driver,cy_semaphore_t * transceive_semaphore)235 whd_result_t whd_bus_sdio_wait_for_wlan_event(whd_driver_t whd_driver, cy_semaphore_t *transceive_semaphore)
236 {
237 whd_result_t result = WHD_SUCCESS;
238 uint32_t timeout_ms = 1;
239 uint32_t delayed_release_timeout_ms;
240
241 REFERENCE_DEBUG_ONLY_VARIABLE(result);
242
243 delayed_release_timeout_ms = whd_bus_handle_delayed_release(whd_driver);
244 if (delayed_release_timeout_ms != 0)
245 {
246 timeout_ms = delayed_release_timeout_ms;
247 }
248 else
249 {
250 result = whd_allow_wlan_bus_to_sleep(whd_driver);
251 whd_assert("Error setting wlan sleep", (result == WHD_SUCCESS) || (result == WHD_PENDING) );
252
253 if (result == WHD_SUCCESS)
254 {
255 timeout_ms = CY_RTOS_NEVER_TIMEOUT;
256 }
257 }
258
259 /* Check if we have run out of bus credits */
260 if ( (whd_sdpcm_has_tx_packet(whd_driver) == WHD_TRUE) && (whd_sdpcm_get_available_credits(whd_driver) == 0) )
261 {
262 /* Keep poking the WLAN until it gives us more credits */
263 result = whd_bus_poke_wlan(whd_driver);
264 whd_assert("Poking failed!", result == WHD_SUCCESS);
265
266 result = cy_rtos_get_semaphore(transceive_semaphore, (uint32_t)MIN_OF(timeout_ms,
267 WHD_THREAD_POKE_TIMEOUT), WHD_FALSE);
268 }
269 else
270 {
271 result = cy_rtos_get_semaphore(transceive_semaphore, (uint32_t)MIN_OF(timeout_ms,
272 WHD_THREAD_POLL_TIMEOUT), WHD_FALSE);
273 }
274 whd_assert("Could not get whd sleep semaphore\n", (result == CY_RSLT_SUCCESS) || (result == CY_RTOS_TIMEOUT) );
275
276 return result;
277 }
278
279 /* Device data transfer functions */
whd_bus_sdio_send_buffer(whd_driver_t whd_driver,whd_buffer_t buffer)280 whd_result_t whd_bus_sdio_send_buffer(whd_driver_t whd_driver, whd_buffer_t buffer)
281 {
282 whd_result_t retval;
283 retval =
284 whd_bus_transfer_bytes(whd_driver, BUS_WRITE, WLAN_FUNCTION, 0,
285 (uint16_t)(whd_buffer_get_current_piece_size(whd_driver,
286 buffer) - sizeof(whd_buffer_t) ),
287 (whd_transfer_bytes_packet_t *)(whd_buffer_get_current_piece_data_pointer(whd_driver,
288 buffer) +
289 sizeof(whd_buffer_t) ) );
290 CHECK_RETURN(whd_buffer_release(whd_driver, buffer, WHD_NETWORK_TX) );
291 if (retval == WHD_SUCCESS)
292 {
293 DELAYED_BUS_RELEASE_SCHEDULE(whd_driver, WHD_TRUE);
294 }
295 CHECK_RETURN (retval);
296
297 return WHD_SUCCESS;
298 }
299
whd_bus_sdio_init(whd_driver_t whd_driver)300 whd_result_t whd_bus_sdio_init(whd_driver_t whd_driver)
301 {
302 uint8_t byte_data;
303 whd_result_t result;
304 uint32_t loop_count;
305 whd_time_t elapsed_time, current_time;
306 uint32_t wifi_firmware_image_size = 0;
307 uint16_t chip_id;
308 uint8_t *aligned_addr = NULL;
309
310 whd_bus_set_flow_control(whd_driver, WHD_FALSE);
311
312 whd_bus_init_backplane_window(whd_driver);
313
314 /* Setup the backplane*/
315 loop_count = 0;
316 do
317 {
318 /* Enable function 1 (backplane) */
319 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOEN, (uint8_t)1,
320 SDIO_FUNC_ENABLE_1) );
321 if (loop_count != 0)
322 {
323 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
324 }
325 CHECK_RETURN(whd_bus_read_register_value (whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOEN, (uint8_t)1, &byte_data) );
326 loop_count++;
327 if (loop_count >= (uint32_t)F0_WORKING_TIMEOUT_MS)
328 {
329 WPRINT_WHD_ERROR( ("Timeout while setting up the backplane, %s failed at %d \n", __func__, __LINE__) );
330 return WHD_TIMEOUT;
331 }
332 } while (byte_data != (uint8_t)SDIO_FUNC_ENABLE_1);
333
334 if (whd_driver->bus_priv->sdio_config.sdio_1bit_mode == WHD_FALSE)
335 {
336 /* Read the bus width and set to 4 bits */
337 CHECK_RETURN(whd_bus_read_register_value (whd_driver, BUS_FUNCTION, SDIOD_CCCR_BICTRL, (uint8_t)1,
338 &byte_data) );
339 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_BICTRL, (uint8_t)1,
340 (byte_data & (~BUS_SD_DATA_WIDTH_MASK) ) |
341 BUS_SD_DATA_WIDTH_4BIT) );
342 /* NOTE: We don't need to change our local bus settings since we're not sending any data (only using CMD52)
343 * until after we change the bus speed further down */
344 }
345
346 /* Set the block size */
347
348 /* Wait till the backplane is ready */
349 loop_count = 0;
350 while ( ( (result = whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_BLKSIZE_0, (uint8_t)1,
351 (uint32_t)SDIO_64B_BLOCK) ) == WHD_SUCCESS ) &&
352 ( (result = whd_bus_read_register_value (whd_driver, BUS_FUNCTION, SDIOD_CCCR_BLKSIZE_0, (uint8_t)1,
353 &byte_data) ) == WHD_SUCCESS ) &&
354 (byte_data != (uint8_t)SDIO_64B_BLOCK) &&
355 (loop_count < (uint32_t)F0_WORKING_TIMEOUT_MS) )
356 {
357 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
358 loop_count++;
359 if (loop_count >= (uint32_t)F0_WORKING_TIMEOUT_MS)
360 {
361 /* If the system fails here, check the high frequency crystal is working */
362 WPRINT_WHD_ERROR( ("Timeout while setting block size, %s failed at %d \n", __func__, __LINE__) );
363 return WHD_TIMEOUT;
364 }
365 }
366
367 CHECK_RETURN(result);
368
369 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_BLKSIZE_0, (uint8_t)1,
370 (uint32_t)SDIO_64B_BLOCK) );
371 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_F1BLKSIZE_0, (uint8_t)1,
372 (uint32_t)SDIO_64B_BLOCK) );
373 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_F2BLKSIZE_0, (uint8_t)1,
374 (uint32_t)SDIO_64B_BLOCK) );
375 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_F2BLKSIZE_1, (uint8_t)1,
376 (uint32_t)0) ); /* Function 2 = 64 */
377
378 /* Register interrupt handler*/
379 whd_bus_sdio_irq_register(whd_driver);
380 /* Enable SDIO IRQ */
381 whd_bus_sdio_irq_enable(whd_driver, WHD_TRUE);
382
383 /* Enable/Disable Client interrupts */
384 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_INTEN, (uint8_t)1,
385 INTR_CTL_MASTER_EN | INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN) );
386
387 if (whd_driver->bus_priv->sdio_config.high_speed_sdio_clock)
388 {
389 /* This code is required if we want more than 25 MHz clock */
390 CHECK_RETURN(whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_SPEED_CONTROL, 1, &byte_data) );
391 if ( (byte_data & 0x1) != 0 )
392 {
393 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_SPEED_CONTROL, 1,
394 byte_data | SDIO_SPEED_EHS) );
395 }
396 else
397 {
398 WPRINT_WHD_ERROR( ("Error reading bus register, %s failed at %d \n", __func__, __LINE__) );
399 return WHD_BUS_READ_REGISTER_ERROR;
400 }
401 }/* HIGH_SPEED_SDIO_CLOCK */
402
403
404
405 /* Wait till the backplane is ready */
406 loop_count = 0;
407 while ( ( (result = whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IORDY, (uint8_t)1,
408 &byte_data) ) == WHD_SUCCESS ) &&
409 ( (byte_data & SDIO_FUNC_READY_1) == 0 ) &&
410 (loop_count < (uint32_t)F1_AVAIL_TIMEOUT_MS) )
411 {
412 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
413 loop_count++;
414 }
415 if (loop_count >= (uint32_t)F1_AVAIL_TIMEOUT_MS)
416 {
417 WPRINT_WHD_ERROR( ("Timeout while waiting for backplane to be ready\n") );
418 return WHD_TIMEOUT;
419 }
420 CHECK_RETURN(result);
421
422 /* Set the ALP */
423 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
424 (uint32_t)(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ |
425 SBSDIO_FORCE_ALP) ) );
426
427 loop_count = 0;
428 while ( ( (result = whd_bus_read_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
429 &byte_data) ) == WHD_SUCCESS ) &&
430 ( (byte_data & SBSDIO_ALP_AVAIL) == 0 ) &&
431 (loop_count < (uint32_t)ALP_AVAIL_TIMEOUT_MS) )
432 {
433 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
434 loop_count++;
435 }
436 if (loop_count >= (uint32_t)ALP_AVAIL_TIMEOUT_MS)
437 {
438 WPRINT_WHD_ERROR( ("Timeout while waiting for alp clock\n") );
439 return WHD_TIMEOUT;
440 }
441 CHECK_RETURN(result);
442
443 /* Clear request for ALP */
444 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1, 0) );
445
446 /* Disable the extra SDIO pull-ups */
447 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_PULL_UP, (uint8_t)1, 0) );
448 /* Enable F1 and F2 */
449 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOEN, (uint8_t)1,
450 SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2) );
451
452 /* Setup host-wake signals */
453 CHECK_RETURN(whd_bus_sdio_init_oob_intr(whd_driver) );
454
455 /* Enable F2 interrupt only */
456 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_INTEN, (uint8_t)1,
457 INTR_CTL_MASTER_EN | INTR_CTL_FUNC2_EN) );
458
459 CHECK_RETURN(whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IORDY, (uint8_t)1, &byte_data) );
460
461 /* Read the chip id */
462 CHECK_RETURN(whd_bus_read_backplane_value(whd_driver, CHIPCOMMON_BASE_ADDRESS, 2, (uint8_t *)&chip_id) );
463 whd_chip_set_chip_id(whd_driver, chip_id);
464
465 cy_rtos_get_time(&elapsed_time);
466 result = whd_bus_sdio_download_firmware(whd_driver);
467 cy_rtos_get_time(¤t_time);
468 elapsed_time = current_time - elapsed_time;
469 CHECK_RETURN(whd_resource_size(whd_driver, WHD_RESOURCE_WLAN_FIRMWARE, &wifi_firmware_image_size) );
470 WPRINT_WHD_INFO( ("WLAN FW download size: %" PRIu32 " bytes\n", wifi_firmware_image_size) );
471 WPRINT_WHD_INFO( ("WLAN FW download time: %" PRIu32 " ms\n", elapsed_time) );
472
473 if (result != WHD_SUCCESS)
474 {
475 /* either an error or user abort */
476 WPRINT_WHD_ERROR( ("SDIO firmware download error, %s failed at %d \n", __func__, __LINE__) );
477 return result;
478 }
479
480 /* Wait for F2 to be ready */
481 loop_count = 0;
482 while ( ( (result = whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IORDY, (uint8_t)1,
483 &byte_data) ) == WHD_SUCCESS ) &&
484 ( (byte_data & SDIO_FUNC_READY_2) == 0 ) &&
485 (loop_count < (uint32_t)F2_READY_TIMEOUT_MS) )
486 {
487 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
488 loop_count++;
489 }
490 if (loop_count >= (uint32_t)F2_READY_TIMEOUT_MS)
491 {
492 /* If your system fails here, it could be due to incorrect NVRAM variables.
493 * Check which 'wifi_nvram_image.h' file your platform is using, and
494 * check that it matches the WLAN device on your platform, including the
495 * crystal frequency.
496 */
497 WPRINT_WHD_ERROR( ("Timeout while waiting for function 2 to be ready\n") );
498 /* Reachable after hitting assert */
499 return WHD_TIMEOUT;
500 }
501 if (whd_driver->aligned_addr == NULL)
502 {
503 if ( (aligned_addr = whd_mem_malloc(WHD_LINK_MTU) ) == NULL )
504 {
505 WPRINT_WHD_ERROR( ("Memory allocation failed for aligned_addr in %s \n", __FUNCTION__) );
506 return WHD_MALLOC_FAILURE;
507 }
508 whd_driver->aligned_addr = aligned_addr;
509 }
510 result = whd_chip_specific_init(whd_driver);
511 if (result != WHD_SUCCESS)
512 {
513 whd_mem_free(whd_driver->aligned_addr);
514 whd_driver->aligned_addr = NULL;
515 }
516 CHECK_RETURN(result);
517 result = whd_ensure_wlan_bus_is_up(whd_driver);
518 if (result != WHD_SUCCESS)
519 {
520 whd_mem_free(whd_driver->aligned_addr);
521 whd_driver->aligned_addr = NULL;
522 }
523 CHECK_RETURN(result);
524
525 whd_bus_sdio_irq_enable(whd_driver, WHD_TRUE);
526
527 UNUSED_PARAMETER(elapsed_time);
528 return result;
529 }
530
whd_bus_sdio_deinit(whd_driver_t whd_driver)531 whd_result_t whd_bus_sdio_deinit(whd_driver_t whd_driver)
532 {
533 if (whd_driver->aligned_addr)
534 {
535 whd_mem_free(whd_driver->aligned_addr);
536 whd_driver->aligned_addr = NULL;
537 }
538
539 CHECK_RETURN(whd_bus_sdio_deinit_oob_intr(whd_driver) );
540
541 whd_bus_sdio_irq_enable(whd_driver, WHD_FALSE);
542
543 CHECK_RETURN(whd_allow_wlan_bus_to_sleep(whd_driver) );
544 whd_bus_set_resource_download_halt(whd_driver, WHD_FALSE);
545
546 DELAYED_BUS_RELEASE_SCHEDULE(whd_driver, WHD_FALSE);
547
548 return WHD_SUCCESS;
549 }
550
whd_bus_sdio_wake_interrupt_present(whd_driver_t whd_driver)551 whd_bool_t whd_bus_sdio_wake_interrupt_present(whd_driver_t whd_driver)
552 {
553 uint32_t int_status = 0;
554
555 /* Ensure the wlan backplane bus is up */
556 if (WHD_SUCCESS != whd_ensure_wlan_bus_is_up(whd_driver) )
557 return WHD_FALSE;
558
559 if (whd_bus_read_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
560 (uint8_t *)&int_status) != WHD_SUCCESS)
561 {
562 WPRINT_WHD_ERROR( ("%s: Error reading interrupt status\n", __FUNCTION__) );
563 goto exit;
564 }
565 if ( (I_HMB_HOST_INT & int_status) != 0 )
566 {
567 /* Clear any interrupts */
568 if (whd_bus_write_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
569 I_HMB_HOST_INT) != WHD_SUCCESS)
570 {
571 WPRINT_WHD_ERROR( ("%s: Error clearing interrupts\n", __FUNCTION__) );
572 goto exit;
573 }
574 if (whd_bus_read_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
575 (uint8_t *)&int_status) != WHD_SUCCESS)
576 {
577 WPRINT_WHD_ERROR( ("%s: Error reading interrupt status\n", __FUNCTION__) );
578 goto exit;
579 }
580 WPRINT_WHD_DEBUG( ("whd_bus_sdio_wake_interrupt_present after clearing int_status = [%x]\n",
581 (uint8_t)int_status) );
582 return WHD_TRUE;
583 }
584 exit:
585 return WHD_FALSE;
586 }
587
whd_bus_sdio_packet_available_to_read(whd_driver_t whd_driver)588 uint32_t whd_bus_sdio_packet_available_to_read(whd_driver_t whd_driver)
589 {
590 uint32_t int_status = 0;
591 uint32_t hmb_data = 0;
592 uint8_t error_type = 0;
593 whd_bt_dev_t btdev = whd_driver->bt_dev;
594
595 /* Ensure the wlan backplane bus is up */
596 CHECK_RETURN(whd_ensure_wlan_bus_is_up(whd_driver) );
597
598 /* Read the IntStatus */
599 if (whd_bus_read_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
600 (uint8_t *)&int_status) != WHD_SUCCESS)
601 {
602 WPRINT_WHD_ERROR( ("%s: Error reading interrupt status\n", __FUNCTION__) );
603 int_status = 0;
604 return WHD_BUS_FAIL;
605 }
606
607 if ( (I_HMB_HOST_INT & int_status) != 0 )
608 {
609 /* Read mailbox data and ack that we did so */
610 if (whd_bus_read_backplane_value(whd_driver, SDIO_TO_HOST_MAILBOX_DATA(whd_driver), 4,
611 (uint8_t *)&hmb_data) == WHD_SUCCESS)
612 if (whd_bus_write_backplane_value(whd_driver, SDIO_TO_SB_MAILBOX(whd_driver), (uint8_t)4,
613 SMB_INT_ACK) != WHD_SUCCESS)
614 WPRINT_WHD_ERROR( ("%s: Failed writing SMB_INT_ACK\n", __FUNCTION__) );
615
616 /* dongle indicates the firmware has halted/crashed */
617 if ( (I_HMB_DATA_FWHALT & hmb_data) != 0 )
618 {
619 WPRINT_WHD_ERROR( ("%s: mailbox indicates firmware halted\n", __FUNCTION__) );
620 whd_wifi_print_whd_log(whd_driver);
621 error_type = WLC_ERR_FW;
622 whd_set_error_handler_locally(whd_driver, &error_type, NULL, NULL, NULL);
623 }
624 }
625 if (btdev && btdev->bt_int_cb)
626 {
627 if ( (I_HMB_FC_CHANGE & int_status) != 0 )
628 {
629 btdev->bt_int_cb(btdev->bt_data);
630 int_status = 0;
631 }
632 }
633
634 if ( (HOSTINTMASK & int_status) != 0 )
635 {
636 /* Clear any interrupts */
637 if (whd_bus_write_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
638 int_status & HOSTINTMASK) != WHD_SUCCESS)
639 {
640 WPRINT_WHD_ERROR( ("%s: Error clearing interrupts\n", __FUNCTION__) );
641 int_status = 0;
642 goto exit;
643 }
644 }
645 exit:
646 return ( (int_status) & (FRAME_AVAILABLE_MASK) );
647 }
648
649 /*
650 * From internal documentation: hwnbu-twiki/SdioMessageEncapsulation
651 * When data is available on the device, the device will issue an interrupt:
652 * - the device should signal the interrupt as a hint that one or more data frames may be available on the device for reading
653 * - the host may issue reads of the 4 byte length tag at any time -- that is, whether an interupt has been issued or not
654 * - if a frame is available, the tag read should return a nonzero length (>= 4) and the host can then read the remainder of the frame by issuing one or more CMD53 reads
655 * - if a frame is not available, the 4byte tag read should return zero
656 */
whd_bus_sdio_read_frame(whd_driver_t whd_driver,whd_buffer_t * buffer)657 whd_result_t whd_bus_sdio_read_frame(whd_driver_t whd_driver, whd_buffer_t *buffer)
658 {
659 uint16_t hwtag[8];
660 uint16_t extra_space_required;
661 whd_result_t result;
662 uint8_t *data = NULL;
663
664 *buffer = NULL;
665
666 /* Ensure the wlan backplane bus is up */
667 CHECK_RETURN(whd_ensure_wlan_bus_is_up(whd_driver) );
668
669 /* Read the frame header and verify validity */
670 memset(hwtag, 0, sizeof(hwtag) );
671
672 result = whd_bus_sdio_transfer(whd_driver, BUS_READ, WLAN_FUNCTION, 0, (uint16_t)INITIAL_READ, (uint8_t *)hwtag,
673 RESPONSE_NEEDED);
674 if (result != WHD_SUCCESS)
675 {
676 (void)whd_bus_sdio_abort_read(whd_driver, WHD_FALSE); /* ignore return - not much can be done if this fails */
677 WPRINT_WHD_ERROR( ("Error during SDIO receive, %s failed at %d \n", __func__, __LINE__) );
678 return WHD_SDIO_RX_FAIL;
679 }
680
681 if ( ( (hwtag[0] | hwtag[1]) == 0 ) ||
682 ( (hwtag[0] ^ hwtag[1]) != (uint16_t)0xFFFF ) )
683 {
684 return WHD_HWTAG_MISMATCH;
685 }
686
687 if ( (hwtag[0] == (uint16_t)12) &&
688 (whd_driver->internal_info.whd_wlan_status.state == WLAN_UP) )
689 {
690 result = whd_bus_sdio_transfer(whd_driver, BUS_READ, WLAN_FUNCTION, 0, (uint16_t)8, (uint8_t *)&hwtag[2],
691 RESPONSE_NEEDED);
692 if (result != WHD_SUCCESS)
693 {
694 /* ignore return - not much can be done if this fails */
695 (void)whd_bus_sdio_abort_read(whd_driver, WHD_FALSE);
696 WPRINT_WHD_ERROR( ("Error during SDIO receive, %s failed at %d \n", __func__, __LINE__) );
697 return WHD_SDIO_RX_FAIL;
698 }
699 whd_sdpcm_update_credit(whd_driver, (uint8_t *)hwtag);
700 return WHD_SUCCESS;
701 }
702
703 /* Calculate the space we need to store entire packet */
704 if ( (hwtag[0] > (uint16_t)INITIAL_READ) )
705 {
706 extra_space_required = (uint16_t)(hwtag[0] - (uint16_t)INITIAL_READ);
707 }
708 else
709 {
710 extra_space_required = 0;
711 }
712
713 /* Allocate a suitable buffer */
714 result = whd_host_buffer_get(whd_driver, buffer, WHD_NETWORK_RX,
715 (uint16_t)(INITIAL_READ + extra_space_required + sizeof(whd_buffer_header_t) ),
716 (whd_sdpcm_has_tx_packet(whd_driver) ? 0 : WHD_RX_BUF_TIMEOUT) );
717 if (result != WHD_SUCCESS)
718 {
719 /* Read out the first 12 bytes to get the bus credit information, 4 bytes are already read in hwtag */
720 whd_assert("Get buffer error",
721 ( (result == WHD_BUFFER_UNAVAILABLE_TEMPORARY) || (result == WHD_BUFFER_UNAVAILABLE_PERMANENT) ) );
722 result = whd_bus_sdio_transfer(whd_driver, BUS_READ, WLAN_FUNCTION, 0, (uint16_t)8, (uint8_t *)&hwtag[2],
723 RESPONSE_NEEDED);
724 if (result != WHD_SUCCESS)
725 {
726 /* ignore return - not much can be done if this fails */
727 (void)whd_bus_sdio_abort_read(whd_driver, WHD_FALSE);
728 WPRINT_WHD_ERROR( ("Error during SDIO receive, %s failed at %d \n", __func__, __LINE__) );
729 return WHD_SDIO_RX_FAIL;
730 }
731 result = whd_bus_sdio_abort_read(whd_driver, WHD_FALSE);
732 whd_assert("Read-abort failed", result == WHD_SUCCESS);
733 REFERENCE_DEBUG_ONLY_VARIABLE(result);
734
735 whd_sdpcm_update_credit(whd_driver, (uint8_t *)hwtag);
736 WPRINT_WHD_ERROR( ("Failed to allocate a buffer to receive into, %s failed at %d \n", __func__, __LINE__) );
737 return WHD_RX_BUFFER_ALLOC_FAIL;
738 }
739 data = whd_buffer_get_current_piece_data_pointer(whd_driver, *buffer);
740 CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
741 /* Copy the data already read */
742 memcpy(data + sizeof(whd_buffer_header_t), hwtag, (size_t)INITIAL_READ);
743
744 /* Read the rest of the data */
745 if (extra_space_required > 0)
746 {
747 data = whd_buffer_get_current_piece_data_pointer(whd_driver, *buffer);
748 CHECK_PACKET_NULL(data, WHD_NO_REGISTER_FUNCTION_POINTER);
749 result = whd_bus_sdio_transfer(whd_driver, BUS_READ, WLAN_FUNCTION, 0, extra_space_required,
750 data + sizeof(whd_buffer_header_t) +
751 INITIAL_READ, RESPONSE_NEEDED);
752
753 if (result != WHD_SUCCESS)
754 {
755 (void)whd_bus_sdio_abort_read(whd_driver, WHD_FALSE); /* ignore return - not much can be done if this fails */
756 CHECK_RETURN(whd_buffer_release(whd_driver, *buffer, WHD_NETWORK_RX) );
757 WPRINT_WHD_ERROR( ("Error during SDIO receive, %s failed at %d \n", __func__, __LINE__) );
758 return WHD_SDIO_RX_FAIL;
759 }
760 }
761 DELAYED_BUS_RELEASE_SCHEDULE(whd_driver, WHD_TRUE);
762 return WHD_SUCCESS;
763 }
764
765 /******************************************************
766 * Function definitions for Protocol Common
767 ******************************************************/
768
769 /* Device register access functions */
whd_bus_sdio_write_backplane_value(whd_driver_t whd_driver,uint32_t address,uint8_t register_length,uint32_t value)770 whd_result_t whd_bus_sdio_write_backplane_value(whd_driver_t whd_driver, uint32_t address, uint8_t register_length,
771 uint32_t value)
772 {
773 CHECK_RETURN(whd_bus_set_backplane_window(whd_driver, address) );
774
775 address &= SBSDIO_SB_OFT_ADDR_MASK;
776
777 if (register_length == 4)
778 address |= SBSDIO_SB_ACCESS_2_4B_FLAG;
779
780 CHECK_RETURN(whd_bus_sdio_transfer(whd_driver, BUS_WRITE, BACKPLANE_FUNCTION, address, register_length,
781 (uint8_t *)&value, RESPONSE_NEEDED) );
782
783 return whd_bus_set_backplane_window(whd_driver, CHIPCOMMON_BASE_ADDRESS);
784 }
785
whd_bus_sdio_read_backplane_value(whd_driver_t whd_driver,uint32_t address,uint8_t register_length,uint8_t * value)786 whd_result_t whd_bus_sdio_read_backplane_value(whd_driver_t whd_driver, uint32_t address, uint8_t register_length,
787 uint8_t *value)
788 {
789 *value = 0;
790 CHECK_RETURN(whd_bus_set_backplane_window(whd_driver, address) );
791
792 address &= SBSDIO_SB_OFT_ADDR_MASK;
793
794 if (register_length == 4)
795 address |= SBSDIO_SB_ACCESS_2_4B_FLAG;
796
797 CHECK_RETURN(whd_bus_sdio_transfer(whd_driver, BUS_READ, BACKPLANE_FUNCTION, address, register_length, value,
798 RESPONSE_NEEDED) );
799
800 return whd_bus_set_backplane_window(whd_driver, CHIPCOMMON_BASE_ADDRESS);
801 }
802
whd_bus_sdio_write_register_value(whd_driver_t whd_driver,whd_bus_function_t function,uint32_t address,uint8_t value_length,uint32_t value)803 whd_result_t whd_bus_sdio_write_register_value(whd_driver_t whd_driver, whd_bus_function_t function, uint32_t address,
804 uint8_t value_length, uint32_t value)
805 {
806 return whd_bus_sdio_transfer(whd_driver, BUS_WRITE, function, address, value_length, (uint8_t *)&value,
807 RESPONSE_NEEDED);
808 }
809
whd_bus_sdio_transfer_bytes(whd_driver_t whd_driver,whd_bus_transfer_direction_t direction,whd_bus_function_t function,uint32_t address,uint16_t size,whd_transfer_bytes_packet_t * data)810 whd_result_t whd_bus_sdio_transfer_bytes(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
811 whd_bus_function_t function, uint32_t address, uint16_t size,
812 whd_transfer_bytes_packet_t *data)
813 {
814 DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
815 return whd_bus_sdio_transfer(whd_driver, direction, function, address, size, (uint8_t *)data->data,
816 RESPONSE_NEEDED);
817 ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
818 }
819
820 /******************************************************
821 * Static Function definitions
822 ******************************************************/
823
whd_bus_sdio_transfer(whd_driver_t whd_driver,whd_bus_transfer_direction_t direction,whd_bus_function_t function,uint32_t address,uint16_t data_size,uint8_t * data,sdio_response_needed_t response_expected)824 static whd_result_t whd_bus_sdio_transfer(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
825 whd_bus_function_t function, uint32_t address, uint16_t data_size,
826 uint8_t *data, sdio_response_needed_t response_expected)
827 {
828 /* Note: this function had broken retry logic (never retried), which has been removed.
829 * Failing fast helps problems on the bus get brought to light more quickly
830 * and preserves the original behavior.
831 */
832 whd_result_t result = WHD_SUCCESS;
833 uint16_t data_byte_size;
834 uint16_t data_blk_size;
835
836 if (data_size == 0)
837 {
838 return WHD_BADARG;
839 }
840 else if (data_size == (uint16_t)1)
841 {
842 return whd_bus_sdio_cmd52(whd_driver, direction, function, address, *data, response_expected, data);
843 }
844 else if (whd_driver->internal_info.whd_wlan_status.state == WLAN_UP)
845 {
846 return whd_bus_sdio_cmd53(whd_driver, direction, function,
847 (data_size >= (uint16_t)64) ? SDIO_BLOCK_MODE : SDIO_BYTE_MODE, address, data_size,
848 data, response_expected, NULL);
849 }
850 else
851 {
852 /* We need to handle remaining size for source image download */
853 data_byte_size = data_size % SDIO_64B_BLOCK;
854 data_blk_size = data_size - data_byte_size;
855 if (data_blk_size != 0)
856 {
857 result = whd_bus_sdio_cmd53(whd_driver, direction, function, SDIO_BLOCK_MODE, address,
858 data_blk_size, data, response_expected, NULL);
859 if (result != WHD_SUCCESS)
860 {
861 return result;
862 }
863 data += data_blk_size;
864 address += data_blk_size;
865 }
866 if (data_byte_size)
867 {
868 result = whd_bus_sdio_cmd53(whd_driver, direction, function, SDIO_BYTE_MODE, address,
869 data_byte_size, data, response_expected, NULL);
870 }
871 return result;
872 }
873 }
874
875 #ifndef WHD_USE_CUSTOM_HAL_IMPL
whd_bus_sdio_cmd52(whd_driver_t whd_driver,whd_bus_transfer_direction_t direction,whd_bus_function_t function,uint32_t address,uint8_t value,sdio_response_needed_t response_expected,uint8_t * response)876 whd_result_t whd_bus_sdio_cmd52(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
877 whd_bus_function_t function, uint32_t address, uint8_t value,
878 sdio_response_needed_t response_expected, uint8_t *response)
879 {
880 uint32_t sdio_response;
881 whd_result_t result;
882 sdio_cmd_argument_t arg;
883 arg.value = 0;
884 arg.cmd52.function_number = (uint32_t)(function & BUS_FUNCTION_MASK);
885 arg.cmd52.register_address = (uint32_t)(address & 0x00001ffff);
886 arg.cmd52.rw_flag = (uint32_t)( (direction == BUS_WRITE) ? 1 : 0 );
887 arg.cmd52.write_data = value;
888
889 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd52);
890 result = cyhal_sdio_send_cmd(whd_driver->bus_priv->sdio_obj, (cyhal_sdio_transfer_t)direction,
891 CYHAL_SDIO_CMD_IO_RW_DIRECT, arg.value,
892 &sdio_response);
893 WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE(whd_driver->bus_priv, (result != WHD_SUCCESS), cmd52_fail);
894
895 if (response != NULL)
896 {
897 *response = (uint8_t)(sdio_response & 0x00000000ff);
898 }
899
900 /* Possibly device might not respond to this cmd. So, don't check return value here */
901 if ( (result != WHD_SUCCESS) && (address == SDIO_SLEEP_CSR) )
902 {
903 return result;
904 }
905
906 CHECK_RETURN(result);
907 return WHD_SUCCESS;
908 }
909
whd_bus_sdio_cmd53(whd_driver_t whd_driver,whd_bus_transfer_direction_t direction,whd_bus_function_t function,sdio_transfer_mode_t mode,uint32_t address,uint16_t data_size,uint8_t * data,sdio_response_needed_t response_expected,uint32_t * response)910 whd_result_t whd_bus_sdio_cmd53(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
911 whd_bus_function_t function, sdio_transfer_mode_t mode, uint32_t address,
912 uint16_t data_size, uint8_t *data,
913 sdio_response_needed_t response_expected, uint32_t *response)
914 {
915 sdio_cmd_argument_t arg;
916 whd_result_t result;
917
918 if (direction == BUS_WRITE)
919 {
920 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd53_write);
921 }
922
923 arg.value = 0;
924 arg.cmd53.function_number = (uint32_t)(function & BUS_FUNCTION_MASK);
925 arg.cmd53.register_address = (uint32_t)(address & BIT_MASK(17) );
926 arg.cmd53.op_code = (uint32_t)1;
927 arg.cmd53.rw_flag = (uint32_t)( (direction == BUS_WRITE) ? 1 : 0 );
928
929 if (mode == SDIO_BYTE_MODE)
930 {
931 whd_assert("whd_bus_sdio_cmd53: data_size > 512 for byte mode", (data_size <= (uint16_t )512) );
932 arg.cmd53.count = (uint32_t)(data_size & 0x1FF);
933
934 result =
935 cyhal_sdio_bulk_transfer(whd_driver->bus_priv->sdio_obj, (cyhal_sdio_transfer_t)direction, arg.value,
936 (uint32_t *)data, data_size, response);
937
938 if (result != CY_RSLT_SUCCESS)
939 {
940 WPRINT_WHD_ERROR( ("%s:%d cyhal_sdio_bulk_transfer SDIO_BYTE_MODE failed\n", __func__, __LINE__) );
941 goto done;
942 }
943 }
944 else
945 {
946 arg.cmd53.count = (uint32_t)( (data_size / (uint16_t)SDIO_64B_BLOCK) & BIT_MASK(9) );
947 if ( (uint32_t)(arg.cmd53.count * (uint16_t)SDIO_64B_BLOCK) < data_size )
948 {
949 ++arg.cmd53.count;
950 }
951 arg.cmd53.block_mode = (uint32_t)1;
952
953 result =
954 cyhal_sdio_bulk_transfer(whd_driver->bus_priv->sdio_obj, (cyhal_sdio_transfer_t)direction, arg.value,
955 (uint32_t *)data, data_size, response);
956
957 if (result != CY_RSLT_SUCCESS)
958 {
959 WPRINT_WHD_ERROR( ("%s:%d cyhal_sdio_bulk_transfer failed\n", __func__, __LINE__) );
960 goto done;
961 }
962 }
963
964 if (direction == BUS_READ)
965 {
966 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd53_read);
967 }
968
969 done:
970 WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE(whd_driver->bus_priv,
971 ( (result != WHD_SUCCESS) && (direction == BUS_READ) ),
972 cmd53_read_fail);
973 WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE(whd_driver->bus_priv,
974 ( (result != WHD_SUCCESS) && (direction == BUS_WRITE) ),
975 cmd53_write_fail);
976 CHECK_RETURN(result);
977 return WHD_SUCCESS;
978 }
979 #endif /* WHD_USE_CUSTOM_HAL_IMPL */
980
whd_bus_sdio_download_firmware(whd_driver_t whd_driver)981 static whd_result_t whd_bus_sdio_download_firmware(whd_driver_t whd_driver)
982 {
983 uint8_t csr_val = 0;
984 whd_result_t result;
985 uint32_t loop_count;
986 uint32_t ram_start_address;
987
988 ram_start_address = GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
989 if (ram_start_address != 0)
990 {
991 CHECK_RETURN(whd_reset_core(whd_driver, WLAN_ARM_CORE, SICF_CPUHALT, SICF_CPUHALT) );
992 }
993 else
994 {
995 CHECK_RETURN(whd_disable_device_core(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_NONE) );
996 CHECK_RETURN(whd_disable_device_core(whd_driver, SOCRAM_CORE, WLAN_CORE_FLAG_NONE) );
997 CHECK_RETURN(whd_reset_device_core(whd_driver, SOCRAM_CORE, WLAN_CORE_FLAG_NONE) );
998
999 CHECK_RETURN(whd_chip_specific_socsram_init(whd_driver) );
1000 }
1001
1002 #if 0
1003 /* 43362 specific: Remap JTAG pins to UART output */
1004 uint32_t data = 0;
1005 CHECK_RETURN(whd_bus_write_backplane_value(0x18000650, 1, 1) );
1006 CHECK_RETURN(whd_bus_read_backplane_value(0x18000654, 4, (uint8_t *)&data) );
1007 data |= (1 << 24);
1008 CHECK_RETURN(whd_bus_write_backplane_value(0x18000654, 4, data) );
1009 #endif
1010
1011 result = whd_bus_write_wifi_firmware_image(whd_driver);
1012
1013 if (result == WHD_UNFINISHED)
1014 {
1015 WPRINT_WHD_INFO( ("User aborted fw download\n") );
1016 /* user aborted */
1017 return result;
1018 }
1019 else if (result != WHD_SUCCESS)
1020 {
1021 whd_assert("Failed to load wifi firmware\n", result == WHD_SUCCESS);
1022 return result;
1023 }
1024
1025 CHECK_RETURN(whd_bus_sdio_write_wifi_nvram_image(whd_driver) );
1026
1027 /* Take the ARM core out of reset */
1028 if (ram_start_address != 0)
1029 {
1030 CHECK_RETURN(whd_reset_core(whd_driver, WLAN_ARM_CORE, 0, 0) );
1031 }
1032 else
1033 {
1034 CHECK_RETURN(whd_reset_device_core(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_NONE) );
1035
1036 result = whd_device_core_is_up(whd_driver, WLAN_ARM_CORE);
1037 if (result != WHD_SUCCESS)
1038 {
1039 WPRINT_WHD_ERROR( ("Could not bring ARM core up\n") );
1040 /* Reachable after hitting assert */
1041 return result;
1042 }
1043 }
1044
1045 /* Wait until the High Throughput clock is available */
1046 loop_count = 0;
1047 while ( ( (result = whd_bus_read_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
1048 &csr_val) ) == WHD_SUCCESS ) &&
1049 ( (csr_val & SBSDIO_HT_AVAIL) == 0 ) &&
1050 (loop_count < (uint32_t)HT_AVAIL_TIMEOUT_MS) )
1051 {
1052 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
1053 loop_count++;
1054 }
1055 if (loop_count >= (uint32_t)HT_AVAIL_TIMEOUT_MS)
1056 {
1057 /* If your system times out here, it means that the WLAN firmware is not booting.
1058 * Check that your WLAN chip matches the 'wifi_image.c' being built - in GNU toolchain, $(CHIP)
1059 * makefile variable must be correct.
1060 */
1061 WPRINT_WHD_ERROR( ("Timeout while waiting for high throughput clock\n") );
1062 /* Reachable after hitting assert */
1063 return WHD_TIMEOUT;
1064 }
1065 if (result != WHD_SUCCESS)
1066 {
1067 WPRINT_WHD_ERROR( ("Error while waiting for high throughput clock\n") );
1068 /* Reachable after hitting assert */
1069 return result;
1070 }
1071
1072 /* Set up the interrupt mask and enable interrupts */
1073 CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, SDIO_INT_HOST_MASK(whd_driver), (uint8_t)4, HOSTINTMASK) );
1074
1075 /* Enable F2 interrupts. This wasn't required for 4319 but is for the 43362 */
1076 CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, SDIO_FUNCTION_INT_MASK(whd_driver), (uint8_t)1,
1077 SDIO_FUNC_MASK_F1 | SDIO_FUNC_MASK_F2) );
1078
1079 /* Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped. */
1080 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_FUNCTION2_WATERMARK, (uint8_t)1,
1081 (uint32_t)SDIO_F2_WATERMARK) );
1082
1083 return WHD_SUCCESS;
1084 }
1085
1086 /** Aborts a SDIO read of a packet from the 802.11 device
1087 *
1088 * This function is necessary because the only way to obtain the size of the next
1089 * available received packet is to read the first four bytes of the packet.
1090 * If the system reads these four bytes, and then fails to allocate the required
1091 * memory, then this function allows the system to abort the packet read cleanly,
1092 * and to optionally tell the 802.11 device to keep it allowing reception once
1093 * memory is available.
1094 *
1095 * In order to do this abort, the following actions are performed:
1096 * - Sets abort bit for Function 2 (WLAN Data) to request stopping transfer
1097 * - Sets Read Frame Termination bit to flush and reset fifos
1098 * - If packet is to be kept and resent by 802.11 device, a NAK is sent
1099 * - Wait whilst the Fifo is emptied of the packet ( reading during this period would cause all zeros to be read )
1100 *
1101 * @param retry : WHD_TRUE if 802.11 device is to keep and resend packet
1102 * WHD_FALSE if 802.11 device is to drop packet
1103 *
1104 * @return WHD_SUCCESS if successful, otherwise error code
1105 */
whd_bus_sdio_abort_read(whd_driver_t whd_driver,whd_bool_t retry)1106 static whd_result_t whd_bus_sdio_abort_read(whd_driver_t whd_driver, whd_bool_t retry)
1107 {
1108 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, read_aborts);
1109
1110 /* Abort transfer on WLAN_FUNCTION */
1111 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOABORT, (uint8_t)1,
1112 (uint32_t)WLAN_FUNCTION) );
1113
1114 /* Send frame terminate */
1115 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_FRAME_CONTROL, (uint8_t)1,
1116 SFC_RF_TERM) );
1117
1118 /* If we want to retry message, send NAK */
1119 if (retry == WHD_TRUE)
1120 {
1121 CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, (uint32_t)SDIO_TO_SB_MAILBOX(whd_driver), (uint8_t)1,
1122 SMB_NAK) );
1123 }
1124
1125 return WHD_SUCCESS;
1126 }
1127
whd_bus_sdio_read_register_value(whd_driver_t whd_driver,whd_bus_function_t function,uint32_t address,uint8_t value_length,uint8_t * value)1128 whd_result_t whd_bus_sdio_read_register_value(whd_driver_t whd_driver, whd_bus_function_t function, uint32_t address,
1129 uint8_t value_length, uint8_t *value)
1130 {
1131 memset(value, 0, (size_t)value_length);
1132 return whd_bus_sdio_transfer(whd_driver, BUS_READ, function, address, value_length, value, RESPONSE_NEEDED);
1133 }
1134
whd_bus_sdio_poke_wlan(whd_driver_t whd_driver)1135 whd_result_t whd_bus_sdio_poke_wlan(whd_driver_t whd_driver)
1136 {
1137 return whd_bus_write_backplane_value(whd_driver, SDIO_TO_SB_MAILBOX(whd_driver), (uint8_t)4, SMB_DEV_INT);
1138 }
1139
whd_bus_sdio_wakeup(whd_driver_t whd_driver)1140 whd_result_t whd_bus_sdio_wakeup(whd_driver_t whd_driver)
1141 {
1142 return WHD_SUCCESS;
1143 }
1144
whd_bus_sdio_sleep(whd_driver_t whd_driver)1145 whd_result_t whd_bus_sdio_sleep(whd_driver_t whd_driver)
1146 {
1147 return WHD_SUCCESS;
1148 }
1149
whd_bus_sdio_set_oob_interrupt(whd_driver_t whd_driver,uint8_t gpio_pin_number)1150 static whd_result_t whd_bus_sdio_set_oob_interrupt(whd_driver_t whd_driver, uint8_t gpio_pin_number)
1151 {
1152 if (gpio_pin_number != 0)
1153 {
1154 /* Redirect to OOB interrupt to GPIO1 */
1155 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_GPIO_SELECT, (uint8_t)1,
1156 (uint32_t)0xF) );
1157 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_GPIO_OUTPUT, (uint8_t)1,
1158 (uint32_t)0x0) );
1159
1160 /* Enable GPIOx (bit x) */
1161 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_GPIO_ENABLE, (uint8_t)1,
1162 (uint32_t)0x2) );
1163
1164 /* Set GPIOx (bit x) on Chipcommon GPIO Control register */
1165 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, CHIPCOMMON_GPIO_CONTROL, (uint8_t)4,
1166 (uint32_t)0x2) );
1167 }
1168
1169 return WHD_SUCCESS;
1170 }
1171
whd_bus_sdio_init_stats(whd_driver_t whd_driver)1172 void whd_bus_sdio_init_stats(whd_driver_t whd_driver)
1173 {
1174 memset(&whd_driver->bus_priv->whd_bus_stats, 0, sizeof(whd_bus_stats_t) );
1175 }
1176
whd_bus_sdio_print_stats(whd_driver_t whd_driver,whd_bool_t reset_after_print)1177 whd_result_t whd_bus_sdio_print_stats(whd_driver_t whd_driver, whd_bool_t reset_after_print)
1178 {
1179 WPRINT_MACRO( ("Bus Stats.. \n"
1180 "cmd52:%" PRIu32 ", cmd53_read:%" PRIu32 ", cmd53_write:%" PRIu32 "\n"
1181 "cmd52_fail:%" PRIu32 ", cmd53_read_fail:%" PRIu32 ", cmd53_write_fail:%" PRIu32 "\n"
1182 "oob_intrs:%" PRIu32 ", sdio_intrs:%" PRIu32 ", error_intrs:%" PRIu32 ", read_aborts:%" PRIu32
1183 "\n",
1184 whd_driver->bus_priv->whd_bus_stats.cmd52, whd_driver->bus_priv->whd_bus_stats.cmd53_read,
1185 whd_driver->bus_priv->whd_bus_stats.cmd53_write,
1186 whd_driver->bus_priv->whd_bus_stats.cmd52_fail,
1187 whd_driver->bus_priv->whd_bus_stats.cmd53_read_fail,
1188 whd_driver->bus_priv->whd_bus_stats.cmd53_write_fail,
1189 whd_driver->bus_priv->whd_bus_stats.oob_intrs,
1190 whd_driver->bus_priv->whd_bus_stats.sdio_intrs,
1191 whd_driver->bus_priv->whd_bus_stats.error_intrs,
1192 whd_driver->bus_priv->whd_bus_stats.read_aborts) );
1193
1194 if (reset_after_print == WHD_TRUE)
1195 {
1196 memset(&whd_driver->bus_priv->whd_bus_stats, 0, sizeof(whd_bus_stats_t) );
1197 }
1198
1199 return WHD_SUCCESS;
1200 }
1201
1202 /* Waking the firmware up from Deep Sleep */
whd_bus_sdio_reinit_stats(whd_driver_t whd_driver,whd_bool_t wake_from_firmware)1203 whd_result_t whd_bus_sdio_reinit_stats(whd_driver_t whd_driver, whd_bool_t wake_from_firmware)
1204 {
1205 whd_result_t result = WHD_SUCCESS;
1206 uint8_t byte_data;
1207 uint32_t loop_count;
1208 loop_count = 0;
1209
1210 /* Setup the backplane*/
1211 loop_count = 0;
1212
1213 do
1214 {
1215 /* Enable function 1 (backplane) */
1216 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOEN, (uint8_t)1,
1217 SDIO_FUNC_ENABLE_1) );
1218 if (loop_count != 0)
1219 {
1220 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
1221 }
1222
1223 CHECK_RETURN(whd_bus_read_register_value (whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOEN, (uint8_t)1, &byte_data) );
1224 loop_count++;
1225 if (loop_count >= (uint32_t)F0_WORKING_TIMEOUT_MS)
1226 {
1227 WPRINT_WHD_ERROR( ("Timeout on CCCR update\n") );
1228 return WHD_TIMEOUT;
1229 }
1230 } while (byte_data != (uint8_t)SDIO_FUNC_ENABLE_1);
1231
1232 if (whd_driver->bus_priv->sdio_config.sdio_1bit_mode == WHD_FALSE)
1233 {
1234 /* Read the bus width and set to 4 bits */
1235 CHECK_RETURN(whd_bus_read_register_value (whd_driver, BUS_FUNCTION, SDIOD_CCCR_BICTRL, (uint8_t)1,
1236 &byte_data) );
1237 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_BICTRL, (uint8_t)1,
1238 (byte_data & (~BUS_SD_DATA_WIDTH_MASK) ) | BUS_SD_DATA_WIDTH_4BIT) );
1239 /* NOTE: We don't need to change our local bus settings since we're not sending any data (only using CMD52)
1240 * until after we change the bus speed further down */
1241 }
1242
1243 /* Set the block size */
1244 /* Wait till the backplane is ready */
1245 loop_count = 0;
1246 while ( ( (result = whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_BLKSIZE_0, (uint8_t)1,
1247 (uint32_t)SDIO_64B_BLOCK) ) == WHD_SUCCESS ) &&
1248 ( (result = whd_bus_read_register_value (whd_driver, BUS_FUNCTION, SDIOD_CCCR_BLKSIZE_0, (uint8_t)1,
1249 &byte_data) ) == WHD_SUCCESS ) &&
1250 (byte_data != (uint8_t)SDIO_64B_BLOCK) &&
1251 (loop_count < (uint32_t)F0_WORKING_TIMEOUT_MS) )
1252 {
1253 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
1254 loop_count++;
1255 if (loop_count >= (uint32_t)F0_WORKING_TIMEOUT_MS)
1256 {
1257 /* If the system fails here, check the high frequency crystal is working */
1258 WPRINT_WHD_ERROR( ("Timeout while setting block size\n") );
1259 return WHD_TIMEOUT;
1260 }
1261 }
1262
1263 CHECK_RETURN(result);
1264
1265 WPRINT_WHD_DEBUG( ("Modding registers for blocks\n") );
1266
1267 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_BLKSIZE_0, (uint8_t)1,
1268 (uint32_t)SDIO_64B_BLOCK) );
1269 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_F1BLKSIZE_0, (uint8_t)1,
1270 (uint32_t)SDIO_64B_BLOCK) );
1271 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_F2BLKSIZE_0, (uint8_t)1,
1272 (uint32_t)SDIO_64B_BLOCK) );
1273 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_F2BLKSIZE_1, (uint8_t)1,
1274 (uint32_t)0) ); /* Function 2 = 64 */
1275
1276 /* Enable/Disable Client interrupts */
1277 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_INTEN, (uint8_t)1,
1278 INTR_CTL_MASTER_EN | INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN) );
1279
1280
1281 if (whd_driver->bus_priv->sdio_config.high_speed_sdio_clock)
1282 {
1283 WPRINT_WHD_DEBUG( ("SDIO HS clock enable\n") );
1284
1285 /* This code is required if we want more than 25 MHz clock */
1286 CHECK_RETURN(whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_SPEED_CONTROL, 1, &byte_data) );
1287 if ( (byte_data & 0x1) != 0 )
1288 {
1289 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_SPEED_CONTROL, 1,
1290 byte_data | SDIO_SPEED_EHS) );
1291 }
1292 else
1293 {
1294 WPRINT_WHD_ERROR( ("Error writing to WLAN register, %s failed at %d \n", __func__, __LINE__) );
1295 return WHD_BUS_READ_REGISTER_ERROR;
1296 }
1297 } /* HIGH_SPEED_SDIO_CLOCK */
1298
1299 /* Wait till the backplane is ready */
1300 loop_count = 0;
1301 while ( ( (result = whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IORDY, (uint8_t)1,
1302 &byte_data) ) == WHD_SUCCESS ) &&
1303 ( (byte_data & SDIO_FUNC_READY_1) == 0 ) &&
1304 (loop_count < (uint32_t)F1_AVAIL_TIMEOUT_MS) )
1305 {
1306 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
1307 loop_count++;
1308 }
1309
1310 if (loop_count >= (uint32_t)F1_AVAIL_TIMEOUT_MS)
1311 {
1312 WPRINT_WHD_ERROR( ("Timeout while waiting for backplane to be ready\n") );
1313 return WHD_TIMEOUT;
1314 }
1315 CHECK_RETURN(result);
1316
1317 /* Set the ALP */
1318 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
1319 (uint32_t)(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ |
1320 SBSDIO_FORCE_ALP) ) );
1321 loop_count = 0;
1322 while ( ( (result = whd_bus_read_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
1323 &byte_data) ) != WHD_SUCCESS ) ||
1324 ( ( (byte_data & SBSDIO_ALP_AVAIL) == 0 ) &&
1325 (loop_count < (uint32_t)ALP_AVAIL_TIMEOUT_MS) ) )
1326 {
1327 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
1328 loop_count++;
1329 }
1330 if (loop_count >= (uint32_t)ALP_AVAIL_TIMEOUT_MS)
1331 {
1332 WPRINT_WHD_ERROR( ("Timeout while waiting for alp clock\n") );
1333 return WHD_TIMEOUT;
1334 }
1335 CHECK_RETURN(result);
1336
1337 /* Clear request for ALP */
1338 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1, 0) );
1339
1340 /* Disable the extra SDIO pull-ups */
1341 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_PULL_UP, (uint8_t)1, 0) );
1342
1343 /* Enable F1 and F2 */
1344 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IOEN, (uint8_t)1,
1345 SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2) );
1346
1347 /* Setup host-wake signals */
1348 CHECK_RETURN(whd_bus_sdio_init_oob_intr(whd_driver) );
1349
1350 /* Enable F2 interrupt only */
1351 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_INTEN, (uint8_t)1,
1352 INTR_CTL_MASTER_EN | INTR_CTL_FUNC2_EN) );
1353
1354 CHECK_RETURN(whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IORDY, (uint8_t)1, &byte_data) );
1355
1356 result = whd_bus_sdio_download_firmware(whd_driver);
1357
1358 if (result != WHD_SUCCESS)
1359 {
1360 /* either an error or user abort */
1361 WPRINT_WHD_DEBUG( ("FW download failed\n") );
1362 return result;
1363 }
1364
1365 /* Wait for F2 to be ready */
1366 loop_count = 0;
1367 while ( ( (result = whd_bus_read_register_value(whd_driver, BUS_FUNCTION, SDIOD_CCCR_IORDY, (uint8_t)1,
1368 &byte_data) ) != WHD_SUCCESS ) ||
1369 ( ( (byte_data & SDIO_FUNC_READY_2) == 0 ) &&
1370 (loop_count < (uint32_t)F2_READY_TIMEOUT_MS) ) )
1371 {
1372 (void)cy_rtos_delay_milliseconds( (uint32_t)1 ); /* Ignore return - nothing can be done if it fails */
1373 loop_count++;
1374 }
1375
1376 if (loop_count >= (uint32_t)F2_READY_TIMEOUT_MS)
1377 {
1378 WPRINT_WHD_DEBUG( ("Timeout while waiting for function 2 to be ready\n") );
1379
1380 if (WHD_TRUE == wake_from_firmware)
1381 {
1382 /* If your system fails here, it could be due to incorrect NVRAM variables.
1383 * Check which 'wifi_nvram_image.h' file your platform is using, and
1384 * check that it matches the WLAN device on your platform, including the
1385 * crystal frequency.
1386 */
1387 WPRINT_WHD_ERROR( ("F2 failed on wake fr FW\n") );
1388 /* Reachable after hitting assert */
1389 return WHD_TIMEOUT;
1390 }
1391 /* Else: Ignore this failure if we're doing a reinit due to host wake: Linux DHD also ignores */
1392
1393 }
1394
1395 /* Do chip specific init */
1396 CHECK_RETURN(whd_chip_specific_init(whd_driver) );
1397
1398 /* Ensure Bus is up */
1399 CHECK_RETURN(whd_ensure_wlan_bus_is_up(whd_driver) );
1400
1401 /* Allow bus to go to sleep */
1402 CHECK_RETURN(whd_allow_wlan_bus_to_sleep(whd_driver) );
1403
1404 WPRINT_WHD_INFO( ("whd_bus_reinit Completed \n") );
1405 return WHD_SUCCESS;
1406 }
1407
whd_bus_sdio_backplane_read_padd_size(whd_driver_t whd_driver)1408 uint8_t whd_bus_sdio_backplane_read_padd_size(whd_driver_t whd_driver)
1409 {
1410 return WHD_BUS_SDIO_BACKPLANE_READ_PADD_SIZE;
1411 }
1412
whd_bus_sdio_use_status_report_scheme(whd_driver_t whd_driver)1413 whd_bool_t whd_bus_sdio_use_status_report_scheme(whd_driver_t whd_driver)
1414 {
1415 return WHD_FALSE;
1416 }
1417
whd_bus_sdio_get_max_transfer_size(whd_driver_t whd_driver)1418 uint32_t whd_bus_sdio_get_max_transfer_size(whd_driver_t whd_driver)
1419 {
1420 return WHD_BUS_SDIO_MAX_BACKPLANE_TRANSFER_SIZE;
1421 }
1422
1423 #ifndef WHD_USE_CUSTOM_HAL_IMPL
1424 #if (CYHAL_API_VERSION >= 2)
whd_bus_sdio_irq_handler(void * handler_arg,cyhal_sdio_event_t event)1425 static void whd_bus_sdio_irq_handler(void *handler_arg, cyhal_sdio_event_t event)
1426 #else
1427 static void whd_bus_sdio_irq_handler(void *handler_arg, cyhal_sdio_irq_event_t event)
1428 #endif /* (CYHAL_API_VERSION >= 2) */
1429 {
1430 whd_driver_t whd_driver = (whd_driver_t)handler_arg;
1431
1432 /* WHD registered only for CY_CYHAL_SDIO_CARD_INTERRUPT */
1433 if (event != CYHAL_SDIO_CARD_INTERRUPT)
1434 {
1435 WPRINT_WHD_ERROR( ("Unexpected interrupt event %d\n", event) );
1436 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, error_intrs);
1437 return;
1438 }
1439
1440 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, sdio_intrs);
1441
1442 /* call thread notify to wake up WHD thread */
1443 whd_thread_notify_irq(whd_driver);
1444 }
1445
whd_bus_sdio_irq_register(whd_driver_t whd_driver)1446 whd_result_t whd_bus_sdio_irq_register(whd_driver_t whd_driver)
1447 {
1448 #if (CYHAL_API_VERSION >= 2)
1449 cyhal_sdio_register_callback(whd_driver->bus_priv->sdio_obj, whd_bus_sdio_irq_handler, whd_driver);
1450 #else
1451 cyhal_sdio_register_irq(whd_driver->bus_priv->sdio_obj, whd_bus_sdio_irq_handler, whd_driver);
1452 #endif /* (CYHAL_API_VERSION >= 2) */
1453 return WHD_SUCCESS;
1454 }
1455
whd_bus_sdio_irq_enable(whd_driver_t whd_driver,whd_bool_t enable)1456 whd_result_t whd_bus_sdio_irq_enable(whd_driver_t whd_driver, whd_bool_t enable)
1457 {
1458 #if (CYHAL_API_VERSION >= 2)
1459 cyhal_sdio_enable_event(whd_driver->bus_priv->sdio_obj, CYHAL_SDIO_CARD_INTERRUPT, CYHAL_ISR_PRIORITY_DEFAULT,
1460 enable);
1461 #else
1462 cyhal_sdio_irq_enable(whd_driver->bus_priv->sdio_obj, CYHAL_SDIO_CARD_INTERRUPT, enable);
1463 #endif /* (CYHAL_API_VERSION >= 2) */
1464 return WHD_SUCCESS;
1465 }
1466
1467 #if (CYHAL_API_VERSION >= 2)
whd_bus_sdio_oob_irq_handler(void * arg,cyhal_gpio_event_t event)1468 static void whd_bus_sdio_oob_irq_handler(void *arg, cyhal_gpio_event_t event)
1469 #else
1470 static void whd_bus_sdio_oob_irq_handler(void *arg, cyhal_gpio_irq_event_t event)
1471 #endif /* (CYHAL_API_VERSION >= 2) */
1472 {
1473 whd_driver_t whd_driver = (whd_driver_t)arg;
1474 const whd_oob_config_t *config = &whd_driver->bus_priv->sdio_config.oob_config;
1475 #if (CYHAL_API_VERSION >= 2)
1476 const cyhal_gpio_event_t expected_event = (config->is_falling_edge == WHD_TRUE)
1477 ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1478 #else
1479 const cyhal_gpio_irq_event_t expected_event = (config->is_falling_edge == WHD_TRUE)
1480 ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1481 #endif /* (CYHAL_API_VERSION >= 2) */
1482 if (event != expected_event)
1483 {
1484 WPRINT_WHD_ERROR( ("Unexpected interrupt event %d\n", event) );
1485 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, error_intrs);
1486 return;
1487 }
1488
1489 WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, oob_intrs);
1490
1491 /* Call thread notify to wake up WHD thread */
1492 whd_thread_notify_irq(whd_driver);
1493 }
1494
whd_bus_sdio_register_oob_intr(whd_driver_t whd_driver)1495 static whd_result_t whd_bus_sdio_register_oob_intr(whd_driver_t whd_driver)
1496 {
1497 const whd_oob_config_t *config = &whd_driver->bus_priv->sdio_config.oob_config;
1498 whd_result_t result;
1499
1500 result = cyhal_gpio_init(config->host_oob_pin, CYHAL_GPIO_DIR_INPUT, config->drive_mode, config->init_drive_state);
1501 if (result != CY_RSLT_SUCCESS)
1502 WPRINT_WHD_ERROR( ("%s: Failed at cyhal_gpio_init for host_oob_pin, result code = %u \n", __func__, (unsigned int)result) );
1503
1504 #if (CYHAL_API_VERSION >= 2)
1505 static cyhal_gpio_callback_data_t cbdata;
1506 cbdata.callback = whd_bus_sdio_oob_irq_handler;
1507 cbdata.callback_arg = whd_driver;
1508 cyhal_gpio_register_callback(config->host_oob_pin, &cbdata);
1509 #else
1510 cyhal_gpio_register_irq(config->host_oob_pin, config->intr_priority, whd_bus_sdio_oob_irq_handler,
1511 whd_driver);
1512 #endif /* (CYHAL_API_VERSION >= 2) */
1513 return WHD_SUCCESS;
1514 }
1515
whd_bus_sdio_unregister_oob_intr(whd_driver_t whd_driver)1516 static whd_result_t whd_bus_sdio_unregister_oob_intr(whd_driver_t whd_driver)
1517 {
1518 const whd_oob_config_t *config = &whd_driver->bus_priv->sdio_config.oob_config;
1519 #if (CYHAL_API_VERSION >= 2)
1520 cyhal_gpio_register_callback(config->host_oob_pin, NULL);
1521 #else
1522 cyhal_gpio_register_irq(config->host_oob_pin, config->intr_priority, NULL, NULL);
1523 #endif /* (CYHAL_API_VERSION >= 2) */
1524 return WHD_SUCCESS;
1525 }
1526
whd_bus_sdio_enable_oob_intr(whd_driver_t whd_driver,whd_bool_t enable)1527 static whd_result_t whd_bus_sdio_enable_oob_intr(whd_driver_t whd_driver, whd_bool_t enable)
1528 {
1529 const whd_oob_config_t *config = &whd_driver->bus_priv->sdio_config.oob_config;
1530 #if (CYHAL_API_VERSION >= 2)
1531 const cyhal_gpio_event_t event =
1532 (config->is_falling_edge == WHD_TRUE) ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1533
1534 cyhal_gpio_enable_event(config->host_oob_pin, event, config->intr_priority, (enable == WHD_TRUE) ? true : false);
1535 #else
1536 const cyhal_gpio_irq_event_t event =
1537 (config->is_falling_edge == WHD_TRUE) ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1538
1539 cyhal_gpio_irq_enable(config->host_oob_pin, event, (enable == WHD_TRUE) ? true : false);
1540 #endif /* (CYHAL_API_VERSION >= 2) */
1541 return WHD_SUCCESS;
1542 }
1543 #endif /* WHD_USE_CUSTOM_HAL_IMPL */
1544
1545
whd_bus_sdio_init_oob_intr(whd_driver_t whd_driver)1546 static whd_result_t whd_bus_sdio_init_oob_intr(whd_driver_t whd_driver)
1547 {
1548 const whd_oob_config_t *config = &whd_driver->bus_priv->sdio_config.oob_config;
1549 uint8_t sepintpol;
1550
1551 /* OOB isn't configured so bail */
1552 if (config->host_oob_pin == WHD_NC_PIN_VALUE)
1553 return WHD_SUCCESS;
1554
1555 /* Choose out-of-band interrupt polarity */
1556 if (config->is_falling_edge == WHD_FALSE)
1557 {
1558 sepintpol = SEP_INTR_CTL_POL;
1559 }
1560 else
1561 {
1562 sepintpol = 0;
1563 }
1564
1565 /* Set OOB interrupt to the correct WLAN GPIO pin (default to GPIO0) */
1566 if (config->dev_gpio_sel)
1567 CHECK_RETURN(whd_bus_sdio_set_oob_interrupt(whd_driver, config->dev_gpio_sel) );
1568
1569 /* Enable out-of-band interrupt on the device */
1570 CHECK_RETURN(whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SDIOD_SEP_INT_CTL, (uint8_t)1,
1571 SEP_INTR_CTL_MASK | SEP_INTR_CTL_EN | sepintpol) );
1572
1573 /* Register and enable OOB */
1574 /* XXX Remove this when BSP377 is implemented */
1575 CHECK_RETURN(whd_bus_sdio_register_oob_intr(whd_driver) );
1576 CHECK_RETURN(whd_bus_sdio_enable_oob_intr(whd_driver, WHD_TRUE) );
1577
1578 return WHD_SUCCESS;
1579 }
1580
whd_bus_sdio_deinit_oob_intr(whd_driver_t whd_driver)1581 static whd_result_t whd_bus_sdio_deinit_oob_intr(whd_driver_t whd_driver)
1582 {
1583 const whd_oob_config_t *config = &whd_driver->bus_priv->sdio_config.oob_config;
1584
1585 if (config->host_oob_pin != WHD_NC_PIN_VALUE)
1586 {
1587 CHECK_RETURN(whd_bus_sdio_enable_oob_intr(whd_driver, WHD_FALSE) );
1588 CHECK_RETURN(whd_bus_sdio_unregister_oob_intr(whd_driver) );
1589 }
1590
1591 return WHD_SUCCESS;
1592 }
1593
1594 #ifdef WPRINT_ENABLE_WHD_DEBUG
1595 #define WHD_BLOCK_SIZE (1024)
whd_bus_sdio_verify_resource(whd_driver_t whd_driver,whd_resource_type_t resource,whd_bool_t direct_resource,uint32_t address,uint32_t image_size)1596 static whd_result_t whd_bus_sdio_verify_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
1597 whd_bool_t direct_resource, uint32_t address, uint32_t image_size)
1598 {
1599 whd_result_t result = WHD_SUCCESS;
1600 uint8_t *image;
1601 uint8_t *cmd_img = NULL;
1602 uint32_t blocks_count = 0;
1603 uint32_t i;
1604 uint32_t size_out;
1605
1606 result = whd_get_resource_no_of_blocks(whd_driver, resource, &blocks_count);
1607 if (result != WHD_SUCCESS)
1608 {
1609 WPRINT_WHD_ERROR( ("Fatal error: download_resource blocks count not known, %s failed at line %d \n", __func__,
1610 __LINE__) );
1611 goto exit;
1612 }
1613 cmd_img = whd_mem_malloc(WHD_BLOCK_SIZE);
1614 memset(cmd_img, 0, WHD_BLOCK_SIZE);
1615 if (cmd_img != NULL)
1616 {
1617 for (i = 0; i < blocks_count; i++)
1618 {
1619 CHECK_RETURN(whd_get_resource_block(whd_driver, resource, i, (const uint8_t **)&image, &size_out) );
1620 result = whd_bus_transfer_backplane_bytes(whd_driver, BUS_READ, address, size_out, cmd_img);
1621 if (result != WHD_SUCCESS)
1622 {
1623 WPRINT_WHD_ERROR( ("%s: Failed to read firmware image\n", __FUNCTION__) );
1624 goto exit;
1625 }
1626 if (memcmp(cmd_img, &image[0], size_out) )
1627 {
1628 WPRINT_WHD_ERROR( ("%s: Downloaded image is corrupted, address is %d, len is %d, resource is %d \n",
1629 __FUNCTION__, (int)address, (int)size_out, (int)resource) );
1630 }
1631 address += size_out;
1632 }
1633 }
1634 exit:
1635 if (cmd_img)
1636 whd_mem_free(cmd_img);
1637 return WHD_SUCCESS;
1638 }
1639
1640 #endif
whd_bus_sdio_download_resource(whd_driver_t whd_driver,whd_resource_type_t resource,whd_bool_t direct_resource,uint32_t address,uint32_t image_size)1641 static whd_result_t whd_bus_sdio_download_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
1642 whd_bool_t direct_resource, uint32_t address, uint32_t image_size)
1643 {
1644 whd_result_t result = WHD_SUCCESS;
1645 uint8_t *image;
1646 uint32_t blocks_count = 0;
1647 uint32_t i;
1648 uint32_t size_out;
1649 uint32_t reset_instr = 0;
1650 #ifdef WPRINT_ENABLE_WHD_DEBUG
1651 uint32_t pre_addr = address;
1652 #endif
1653
1654 result = whd_get_resource_no_of_blocks(whd_driver, resource, &blocks_count);
1655 if (result != WHD_SUCCESS)
1656 {
1657 WPRINT_WHD_ERROR( ("Fatal error: download_resource blocks count not known, %s failed at line %d \n", __func__,
1658 __LINE__) );
1659 goto exit;
1660 }
1661
1662 for (i = 0; i < blocks_count; i++)
1663 {
1664 CHECK_RETURN(whd_get_resource_block(whd_driver, resource, i, (const uint8_t **)&image, &size_out) );
1665 if ( (resource == WHD_RESOURCE_WLAN_FIRMWARE) && (reset_instr == 0) )
1666 {
1667 /* Copy the starting address of the firmware into a global variable */
1668 reset_instr = *( (uint32_t *)(&image[0]) );
1669 }
1670 result = whd_bus_transfer_backplane_bytes(whd_driver, BUS_WRITE, address, size_out, &image[0]);
1671 if (result != WHD_SUCCESS)
1672 {
1673 WPRINT_WHD_ERROR( ("%s: Failed to write firmware image\n", __FUNCTION__) );
1674 goto exit;
1675 }
1676 address += size_out;
1677 }
1678 #ifdef WPRINT_ENABLE_WHD_DEBUG
1679 whd_bus_sdio_verify_resource(whd_driver, resource, direct_resource, pre_addr, image_size);
1680 #endif
1681 /* Below part of the code is applicable to arm_CR4 type chips only
1682 * The CR4 chips by default firmware is not loaded at 0. So we need
1683 * load the first 32 bytes with the offset of the firmware load address
1684 * which is been copied before during the firmware download
1685 */
1686 if ( (address != 0) && (reset_instr != 0) )
1687 {
1688 /* write address 0 with reset instruction */
1689 result = whd_bus_write_backplane_value(whd_driver, 0, sizeof(reset_instr), reset_instr);
1690
1691 if (result == WHD_SUCCESS)
1692 {
1693 uint32_t tmp;
1694
1695 /* verify reset instruction value */
1696 result = whd_bus_read_backplane_value(whd_driver, 0, sizeof(tmp), (uint8_t *)&tmp);
1697
1698 if ( (result == WHD_SUCCESS) && (tmp != reset_instr) )
1699 {
1700 WPRINT_WHD_ERROR( ("%s: Failed to write 0x%08" PRIx32 " to addr 0\n", __FUNCTION__, reset_instr) );
1701 WPRINT_WHD_ERROR( ("%s: contents of addr 0 is 0x%08" PRIx32 "\n", __FUNCTION__, tmp) );
1702 return WHD_WLAN_SDIO_ERROR;
1703 }
1704 }
1705 }
1706 exit: return result;
1707 }
1708
whd_bus_sdio_write_wifi_nvram_image(whd_driver_t whd_driver)1709 static whd_result_t whd_bus_sdio_write_wifi_nvram_image(whd_driver_t whd_driver)
1710 {
1711 uint32_t img_base;
1712 uint32_t img_end;
1713 uint32_t image_size;
1714
1715 /* Get the size of the variable image */
1716 CHECK_RETURN(whd_resource_size(whd_driver, WHD_RESOURCE_WLAN_NVRAM, &image_size) );
1717
1718 /* Round up the size of the image */
1719 image_size = ROUND_UP(image_size, NVM_IMAGE_SIZE_ALIGNMENT);
1720
1721 /* Write image */
1722 img_end = GET_C_VAR(whd_driver, CHIP_RAM_SIZE) - 4;
1723 img_base = (img_end - image_size);
1724 img_base += GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
1725
1726 CHECK_RETURN(whd_bus_sdio_download_resource(whd_driver, WHD_RESOURCE_WLAN_NVRAM, WHD_FALSE, img_base, image_size) );
1727
1728 /* Write the variable image size at the end */
1729 image_size = (~(image_size / 4) << 16) | (image_size / 4);
1730
1731 img_end += GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
1732
1733 CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, (uint32_t)img_end, 4, image_size) );
1734 return WHD_SUCCESS;
1735 }
1736
1737 /*
1738 * Update the backplane window registers
1739 */
whd_bus_sdio_set_backplane_window(whd_driver_t whd_driver,uint32_t addr,uint32_t * curbase)1740 whd_result_t whd_bus_sdio_set_backplane_window(whd_driver_t whd_driver, uint32_t addr, uint32_t *curbase)
1741 {
1742 whd_result_t result = WHD_BUS_WRITE_REGISTER_ERROR;
1743 uint32_t base = addr & ( (uint32_t) ~BACKPLANE_ADDRESS_MASK );
1744 const uint32_t upper_32bit_mask = 0xFF000000;
1745 const uint32_t upper_middle_32bit_mask = 0x00FF0000;
1746 const uint32_t lower_middle_32bit_mask = 0x0000FF00;
1747
1748 if (base == *curbase)
1749 {
1750 return WHD_SUCCESS;
1751 }
1752 if ( (base & upper_32bit_mask) != (*curbase & upper_32bit_mask) )
1753 {
1754 if (WHD_SUCCESS !=
1755 (result = whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_BACKPLANE_ADDRESS_HIGH,
1756 (uint8_t)1, (base >> 24) ) ) )
1757 {
1758 WPRINT_WHD_ERROR( ("Failed to write register value to the bus, %s failed at %d \n", __func__,
1759 __LINE__) );
1760 return result;
1761 }
1762 /* clear old */
1763 *curbase &= ~upper_32bit_mask;
1764 /* set new */
1765 *curbase |= (base & upper_32bit_mask);
1766 }
1767
1768 if ( (base & upper_middle_32bit_mask) !=
1769 (*curbase & upper_middle_32bit_mask) )
1770 {
1771 if (WHD_SUCCESS !=
1772 (result = whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_BACKPLANE_ADDRESS_MID,
1773 (uint8_t)1, (base >> 16) ) ) )
1774 {
1775 WPRINT_WHD_ERROR( ("Failed to write register value to the bus, %s failed at %d \n", __func__,
1776 __LINE__) );
1777 return result;
1778 }
1779 /* clear old */
1780 *curbase &= ~upper_middle_32bit_mask;
1781 /* set new */
1782 *curbase |= (base & upper_middle_32bit_mask);
1783 }
1784
1785 if ( (base & lower_middle_32bit_mask) !=
1786 (*curbase & lower_middle_32bit_mask) )
1787 {
1788 if (WHD_SUCCESS !=
1789 (result = whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_BACKPLANE_ADDRESS_LOW,
1790 (uint8_t)1, (base >> 8) ) ) )
1791 {
1792 WPRINT_WHD_ERROR( ("Failed to write register value to the bus, %s failed at %d \n", __func__,
1793 __LINE__) );
1794 return result;
1795 }
1796
1797 /* clear old */
1798 *curbase &= ~lower_middle_32bit_mask;
1799 /* set new */
1800 *curbase |= (base & lower_middle_32bit_mask);
1801 }
1802
1803 return WHD_SUCCESS;
1804 }
1805
1806 #endif /* (CYBSP_WIFI_INTERFACE_TYPE == CYBSP_SDIO_INTERFACE) */
1807
1808