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