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(&current_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