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