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 SPI Protocol interface
20  *
21  *  Implements the WHD Bus Protocol Interface for SPI
22  *  Provides functions for initialising, de-intitialising 802.11 device,
23  *  sending/receiving raw packets etc
24  */
25 
26 #include <string.h>  /* For memcpy */
27 
28 #include "cybsp.h"
29 #if (CYBSP_WIFI_INTERFACE_TYPE == CYBSP_SPI_INTERFACE)
30 
31 
32 #include "cy_result.h"
33 #include "cyabs_rtos.h"
34 
35 #include "whd_thread.h"
36 #include "whd_chip.h"
37 #include "whd_sdpcm.h"
38 #include "whd_chip_constants.h"
39 #include "whd_int.h"
40 #include "whd_bus_spi_protocol.h"
41 #include "whd_bus_common.h"
42 #include "whd_chip_reg.h"
43 #include "whd_debug.h"
44 #include "whd_bus.h"
45 #include "whd_spi.h"
46 #include "whd_sdio.h"
47 #include "whd_buffer_api.h"
48 #include "whd_debug.h"
49 #include "whd_types_int.h"
50 #include "whd_resource_if.h"
51 #include "whd_utils.h"
52 
53 /******************************************************
54 *             Constants
55 ******************************************************/
56 
57 #define F2_READY_TIMEOUT_MS    (1000)
58 #define F2_READY_TIMEOUT_LOOPS (1000)
59 #define F1_READY_TIMEOUT_LOOPS (1000)
60 #define FEADBEAD_TIMEOUT_MS    (500)
61 #define ALP_AVAIL_TIMEOUT_MS   (100)
62 
63 /* function 1 OCP space */
64 #define SBSDIO_SB_OFT_ADDR_MASK  0x07FFF /* sb offset addr is <= 15 bits, 32k */
65 #define SBSDIO_SB_OFT_ADDR_LIMIT  0x08000
66 #define SBSDIO_SB_ACCESS_2_4B_FLAG  0x08000 /* with b15, maps to 32-bit SB access */
67 
68 #if defined(CONFIG_CYW43439)
69 /* Delay before HT is available on the CYW43439 is over 1600 mSec */
70 #define HT_AVAIL_TIMEOUT_MS    (2000)
71 #else
72 #define HT_AVAIL_TIMEOUT_MS    (1000)
73 #endif
74 
75 /* Taken from FALCON_5_90_195_26 dhd/sys/dhd_sdio.c. For 43362, MUST be >= 8 and word-aligned otherwise dongle fw crashes */
76 #define SPI_F2_WATERMARK       (32)
77 
78 #define GSPI_PACKET_AVAILABLE  (1 << 8)
79 #define GSPI_UNDERFLOW         (1 << 1)
80 
81 #define SWAP32_16BIT_PARTS(val) ( (uint32_t)( ( ( (uint32_t)(val) ) >> 16 ) + \
82                                               ( ( ( (uint32_t)(val) ) & 0xffff ) << 16 ) ) )
83 
84 #define WHD_BUS_GSPI_PACKET_OVERHEAD    (sizeof(whd_buffer_header_t) )
85 
86 #define MAX_GSPI_TRANSFER_LEN  2048
87 
88 #define H32TO16LE(x)           ( ( uint32_t )( ( ( ( uint32_t )(x) & ( uint32_t )0x000000ffU ) << 8 ) | \
89                                                ( ( ( uint32_t )(x) & ( uint32_t )0x0000ff00U ) >> 8 ) | \
90                                                ( ( ( uint32_t )(x) & ( uint32_t )0x00ff0000U ) << 8 ) | \
91                                                ( ( ( uint32_t )(x) & ( uint32_t )0xff000000U ) >> 8 ) ) )
92 
93 #define WHD_THREAD_POLL_TIMEOUT      (CY_RTOS_NEVER_TIMEOUT)
94 
95 #define WHD_THREAD_POKE_TIMEOUT      (100)
96 
97 #define HOSTINTMASK (I_HMB_SW_MASK)
98 
99 #define BT_POLLING_TIME            (100)
100 #define ALIGNED_ADDRESS            ( (uint32_t)0x3 )
101 typedef enum
102 {
103     GSPI_INCREMENT_ADDRESS = 1, GSPI_FIXED_ADDRESS = 0
104 } gspi_transfer_access_t;
105 
106 /******************************************************
107 *             Structures
108 ******************************************************/
109 
110 #pragma pack(1)
111 
112 typedef struct
113 {
114     whd_bus_gspi_header_t header;
115     uint8_t response_delay[4];
116 } gspi_backplane_f1_read_header_t;
117 
118 #pragma pack()
119 
120 typedef struct
121 {
122     gspi_backplane_f1_read_header_t gspi_header;
123     uint32_t data[1];
124 } gspi_backplane_f1_read_packet_t;
125 
126 /******************************************************
127 *             Static variables
128 ******************************************************/
129 
130 static const uint8_t whd_bus_gspi_command_mapping[] = { 0, 1 };
131 
132 /******************************************************
133 *             Structures
134 ******************************************************/
135 struct whd_bus_priv
136 {
137     whd_spi_config_t spi_config;
138     whd_spi_t *spi_obj;
139 };
140 
141 /******************************************************
142 *             Variables
143 ******************************************************/
144 
145 /******************************************************
146 *             Static Function Declarations
147 ******************************************************/
148 
149 static whd_result_t whd_spi_download_firmware(whd_driver_t whd_driver);
150 static whd_result_t whd_bus_spi_transfer_buffer(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
151                                                 whd_bus_function_t function, uint32_t address, whd_buffer_t buffer);
152 static whd_result_t whd_bus_spi_download_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
153                                                   whd_bool_t direct_resource, uint32_t address, uint32_t image_size);
154 static whd_result_t whd_bus_spi_write_wifi_nvram_image(whd_driver_t whd_driver);
155 static whd_result_t whd_bus_spi_set_backplane_window(whd_driver_t whd_driver, uint32_t addr, uint32_t *curbase);
156 
157 whd_result_t whd_bus_spi_transfer(whd_driver_t whd_driver, const uint8_t *tx, size_t tx_length, uint8_t *rx,
158                                   size_t rx_length, uint8_t write_fill);
159 
160 /******************************************************
161 *             Global Function definitions
162 ******************************************************/
163 uint32_t whd_bus_spi_bt_packet_available_to_read(whd_driver_t whd_driver);
164 
whd_bus_spi_attach(whd_driver_t whd_driver,whd_spi_config_t * whd_spi_config,whd_spi_t * spi_obj)165 uint32_t whd_bus_spi_attach(whd_driver_t whd_driver, whd_spi_config_t *whd_spi_config, whd_spi_t *spi_obj)
166 {
167     struct whd_bus_info *whd_bus_info;
168 
169     if (!whd_driver || !whd_spi_config)
170     {
171         WPRINT_WHD_ERROR( ("Invalid param in func %s at line %d \n",
172                            __func__, __LINE__) );
173         return WHD_WLAN_BADARG;
174     }
175 
176     if (whd_spi_config->oob_config.host_oob_pin == WHD_NC_PIN_VALUE)
177     {
178         WPRINT_WHD_ERROR( ("OOB interrupt pin argument must be provided in %s\n", __FUNCTION__) );
179         return WHD_BADARG;
180     }
181 
182     whd_bus_info = (whd_bus_info_t *)whd_mem_malloc(sizeof(whd_bus_info_t) );
183 
184     if (whd_bus_info == NULL)
185     {
186         WPRINT_WHD_ERROR( ("Memory allocation failed for whd_bus_info in %s\n", __FUNCTION__) );
187         return WHD_BUFFER_UNAVAILABLE_PERMANENT;
188     }
189     memset(whd_bus_info, 0, sizeof(whd_bus_info_t) );
190 
191     whd_driver->bus_if = whd_bus_info;
192 
193     whd_driver->bus_priv = (struct whd_bus_priv *)whd_mem_malloc(sizeof(struct whd_bus_priv) );
194 
195     if (whd_driver->bus_priv == NULL)
196     {
197         WPRINT_WHD_ERROR( ("Memory allocation failed for whd_bus_priv in %s\n", __FUNCTION__) );
198         return WHD_BUFFER_UNAVAILABLE_PERMANENT;
199     }
200     memset(whd_driver->bus_priv, 0, sizeof(struct whd_bus_priv) );
201 
202     /* Pass the SPI object to bus private spi_obj pointer */
203     whd_driver->bus_priv->spi_obj = spi_obj;
204     whd_driver->bus_priv->spi_config = *whd_spi_config;
205 
206     whd_bus_info->whd_bus_init_fptr = whd_bus_spi_init;
207     whd_bus_info->whd_bus_deinit_fptr = whd_bus_spi_deinit;
208 
209     whd_bus_info->whd_bus_write_backplane_value_fptr = whd_bus_spi_write_backplane_value;
210     whd_bus_info->whd_bus_read_backplane_value_fptr = whd_bus_spi_read_backplane_value;
211     whd_bus_info->whd_bus_write_register_value_fptr = whd_bus_spi_write_register_value;
212     whd_bus_info->whd_bus_read_register_value_fptr = whd_bus_spi_read_register_value;
213 
214     whd_bus_info->whd_bus_send_buffer_fptr = whd_bus_spi_send_buffer;
215     whd_bus_info->whd_bus_transfer_bytes_fptr = whd_bus_spi_transfer_bytes;
216 
217     whd_bus_info->whd_bus_read_frame_fptr = whd_bus_spi_read_frame;
218 
219     whd_bus_info->whd_bus_packet_available_to_read_fptr = whd_bus_spi_packet_available_to_read;
220     whd_bus_info->whd_bus_poke_wlan_fptr = whd_bus_spi_poke_wlan;
221     whd_bus_info->whd_bus_wait_for_wlan_event_fptr = whd_bus_spi_wait_for_wlan_event;
222 
223     whd_bus_info->whd_bus_ack_interrupt_fptr = whd_bus_spi_ack_interrupt;
224     whd_bus_info->whd_bus_wake_interrupt_present_fptr = whd_bus_spi_wake_interrupt_present;
225 
226     whd_bus_info->whd_bus_wakeup_fptr = whd_bus_spi_wakeup;
227     whd_bus_info->whd_bus_sleep_fptr = whd_bus_spi_sleep;
228 
229     whd_bus_info->whd_bus_backplane_read_padd_size_fptr = whd_bus_spi_backplane_read_padd_size;
230     whd_bus_info->whd_bus_use_status_report_scheme_fptr = whd_bus_spi_use_status_report_scheme;
231 
232     whd_bus_info->whd_bus_get_max_transfer_size_fptr = whd_bus_spi_get_max_transfer_size;
233 
234     whd_bus_info->whd_bus_init_stats_fptr = whd_bus_spi_init_stats;
235     whd_bus_info->whd_bus_print_stats_fptr = whd_bus_spi_print_stats;
236     whd_bus_info->whd_bus_reinit_stats_fptr = whd_bus_spi_reinit_stats;
237     whd_bus_info->whd_bus_irq_register_fptr = whd_bus_spi_irq_register;
238     whd_bus_info->whd_bus_irq_enable_fptr = whd_bus_spi_irq_enable;
239     whd_bus_info->whd_bus_download_resource_fptr = whd_bus_spi_download_resource;
240     whd_bus_info->whd_bus_set_backplane_window_fptr = whd_bus_spi_set_backplane_window;
241 
242     return WHD_SUCCESS;
243 }
244 
whd_bus_spi_detach(whd_driver_t whd_driver)245 void whd_bus_spi_detach(whd_driver_t whd_driver)
246 {
247     if (whd_driver->bus_if != NULL)
248     {
249         whd_mem_free(whd_driver->bus_if);
250         whd_driver->bus_if = NULL;
251     }
252     if (whd_driver->bus_priv != NULL)
253     {
254         whd_mem_free(whd_driver->bus_priv);
255         whd_driver->bus_priv = NULL;
256     }
257 }
258 
259 #ifndef WHD_USE_CUSTOM_HAL_IMPL
whd_bus_spi_transfer(whd_driver_t whd_driver,const uint8_t * tx,size_t tx_length,uint8_t * rx,size_t rx_length,uint8_t write_fill)260 whd_result_t whd_bus_spi_transfer(whd_driver_t whd_driver, const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length,
261                              uint8_t write_fill)
262 {
263     return cyhal_spi_transfer(whd_driver->bus_priv->spi_obj, tx, tx_length, rx, rx_length, write_fill);
264 }
265 #endif /* ifndef WHD_USE_CUSTOM_HAL_IMPL */
266 
267 
whd_bus_spi_send_buffer(whd_driver_t whd_driver,whd_buffer_t buffer)268 whd_result_t whd_bus_spi_send_buffer(whd_driver_t whd_driver, whd_buffer_t buffer)
269 {
270     whd_result_t result = whd_bus_spi_transfer_buffer(whd_driver, BUS_WRITE, WLAN_FUNCTION, 0, buffer);
271     CHECK_RETURN(whd_buffer_release(whd_driver, buffer, WHD_NETWORK_TX) );
272     if (result == WHD_SUCCESS)
273     {
274         DELAYED_BUS_RELEASE_SCHEDULE (whd_driver, WHD_TRUE);
275     }
276     CHECK_RETURN(result);
277 
278     return WHD_SUCCESS;
279 }
280 
281 /*
282  * Perform a transfer on the gSPI bus
283  * Prerequisites: length < MAX_GSPI_TRANSFER_LEN
284  */
whd_bus_spi_transfer_buffer(whd_driver_t whd_driver,whd_bus_transfer_direction_t direction,whd_bus_function_t function,uint32_t address,whd_buffer_t buffer)285 static whd_result_t whd_bus_spi_transfer_buffer(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
286                                                 whd_bus_function_t function, uint32_t address, whd_buffer_t buffer)
287 {
288     uint32_t *temp, addr;
289     whd_result_t result;
290     uint16_t newsize;
291     whd_buffer_header_t *header = (whd_buffer_header_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, buffer);
292     whd_buffer_header_t *aligned_header = (whd_buffer_header_t *)whd_driver->aligned_addr;
293     whd_bus_gspi_header_t *gspi_header;
294     size_t transfer_size;
295 
296     uint16_t size = ( uint16_t )(whd_buffer_get_current_piece_size(whd_driver, buffer) - sizeof(whd_buffer_header_t) );
297     CHECK_PACKET_NULL(header, WHD_NO_REGISTER_FUNCTION_POINTER);
298     /* Round size up to 32-bit alignment */
299     newsize = (uint16_t)ROUND_UP(size, 4);
300 
301     /* Send the data */
302     if (direction == BUS_WRITE)
303     {
304         /* Wait for FIFO to be ready to accept data */
305         if (function == WLAN_FUNCTION)
306         {
307             uint32_t whd_bus_gspi_status;
308             uint32_t loop_count = 0;
309             while ( ( (result =
310                            whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_STATUS_REGISTER, (uint8_t)4,
311                                                            (uint8_t *)&whd_bus_gspi_status) ) == WHD_SUCCESS ) &&
312                     ( (whd_bus_gspi_status & (1 << 5) ) == 0 ) &&
313                     (loop_count < ( uint32_t )F2_READY_TIMEOUT_LOOPS) )
314             {
315                 loop_count++;
316             }
317             if (result != WHD_SUCCESS)
318             {
319                 WPRINT_WHD_ERROR( ("Error reading register value, %s failed at %d \n", __func__, __LINE__) );
320                 return result;
321             }
322             if (loop_count >= ( uint32_t )F2_READY_TIMEOUT_LOOPS)
323             {
324                 WPRINT_WHD_ERROR( ("Timeout waiting for data FIFO to be ready\n") );
325                 return WHD_TIMEOUT;
326             }
327         }
328 
329     }
330 
331     transfer_size = (size_t)(newsize + sizeof(whd_bus_gspi_header_t) );
332     gspi_header =
333         (whd_bus_gspi_header_t *)( (char *)header->bus_header + MAX_BUS_HEADER_SIZE -
334                                    sizeof(whd_bus_gspi_header_t) );
335     /* Form the gSPI header */
336     addr = (uint32_t )header;
337     /* check 4byte alignment */
338     if ( (addr & ALIGNED_ADDRESS) )
339     {
340         if (aligned_header)
341         {
342             /* use memcpy to get aligned event message */
343             memcpy(aligned_header, header, sizeof(*aligned_header) + size);
344             gspi_header =
345                 (whd_bus_gspi_header_t *)( (char *)aligned_header->bus_header + MAX_BUS_HEADER_SIZE -
346                                            sizeof(whd_bus_gspi_header_t) );
347         }
348     }
349     /* Form the gSPI header */
350     *gspi_header =
351         ( whd_bus_gspi_header_t )( ( uint32_t )( (whd_bus_gspi_command_mapping[(int)direction] & 0x1) << 31 ) |
352                                    ( uint32_t )( (GSPI_INCREMENT_ADDRESS & 0x1) << 30 ) |
353                                    ( uint32_t )( (function & 0x3) << 28 ) |
354                                    ( uint32_t )( (address & 0x1FFFF) << 11 ) | ( uint32_t )( (size & 0x7FF) << 0 ) );
355 
356     /* Reshuffle the bits if we're not in 32 bit mode */
357     if (whd_driver->bus_gspi_32bit == WHD_FALSE)
358     {
359         /* Note: This typecast should always be valid if the buffer containing the GSpi packet has been correctly declared as 32-bit aligned */
360         temp = (uint32_t *)gspi_header;
361         *temp = H32TO16LE(*temp);
362     }
363 
364     /* Send the data */
365     if (direction == BUS_READ)
366     {
367         result =  whd_bus_spi_transfer(whd_driver, NULL,
368                                      sizeof(whd_bus_gspi_header_t),
369                                      (uint8_t *)gspi_header,
370                                      transfer_size, 0);
371 
372     }
373     else
374     {
375         result = whd_bus_spi_transfer(whd_driver, (uint8_t *)gspi_header, transfer_size, NULL, 0, 0);
376     }
377 
378     return result;
379 }
380 
whd_bus_spi_poke_wlan(whd_driver_t whd_driver)381 whd_result_t whd_bus_spi_poke_wlan(whd_driver_t whd_driver)
382 {
383     return WHD_SUCCESS;
384 }
385 
whd_bus_spi_ack_interrupt(whd_driver_t whd_driver,uint32_t intstatus)386 whd_result_t whd_bus_spi_ack_interrupt(whd_driver_t whd_driver, uint32_t intstatus)
387 {
388     return whd_bus_write_register_value(whd_driver, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, (uint8_t)2, intstatus);
389 }
390 
whd_bus_spi_bt_packet_available_to_read(whd_driver_t whd_driver)391 uint32_t whd_bus_spi_bt_packet_available_to_read(whd_driver_t whd_driver)
392 {
393     whd_bt_dev_t btdev = whd_driver->bt_dev;
394     uint32_t int_status = 0;
395 
396     if (btdev && btdev->bt_int_cb)
397     {
398         if (whd_bus_spi_read_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
399                                              (uint8_t *)&int_status) != WHD_SUCCESS)
400         {
401             WPRINT_WHD_ERROR( ("%s: Error reading interrupt status\n", __FUNCTION__) );
402             int_status = 0;
403         }
404 
405         if ( (I_HMB_FC_CHANGE & int_status) != 0 )
406         {
407 
408             if (whd_bus_spi_write_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
409                                                   int_status & I_HMB_FC_CHANGE)  != WHD_SUCCESS)
410             {
411                 WPRINT_WHD_ERROR( ("%s: Error write interrupt status\n", __FUNCTION__) );
412                 int_status = 0;
413             }
414             btdev->bt_int_cb(btdev->bt_data);
415         }
416     }
417 
418     return 0;
419 }
420 
whd_bus_spi_packet_available_to_read(whd_driver_t whd_driver)421 uint32_t whd_bus_spi_packet_available_to_read(whd_driver_t whd_driver)
422 {
423     uint16_t interrupt_register;
424     uint32_t int_status = 0;
425 
426     CHECK_RETURN(whd_ensure_wlan_bus_is_up(whd_driver) );
427 
428     whd_bus_spi_bt_packet_available_to_read(whd_driver);
429     /* Read the interrupt register */
430     if (whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, (uint8_t)2,
431                                         (uint8_t *)&interrupt_register) != WHD_SUCCESS)
432     {
433         goto return_with_error;
434     }
435 
436     if ( (interrupt_register & 0x0086) != 0 )   /* This should be 0x87, but occasional "data not available" errors are flagged seemingly for no reason */
437     {
438         /* Error condition detected */
439         WPRINT_WHD_DEBUG( ("Bus error condition detected\n") );
440     }
441     /* Read the IntStatus */
442     if (whd_bus_spi_read_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
443                                          (uint8_t *)&int_status) != WHD_SUCCESS)
444     {
445         WPRINT_WHD_ERROR( ("%s: Error reading interrupt status\n", __FUNCTION__) );
446         int_status = 0;
447         goto return_with_error;
448     }
449 
450     if ( (HOSTINTMASK & int_status) != 0 )
451     {
452         if (whd_bus_spi_write_backplane_value(whd_driver, (uint32_t)SDIO_INT_STATUS(whd_driver), (uint8_t)4,
453                                               int_status & HOSTINTMASK)  != WHD_SUCCESS)
454         {
455             int_status = 0;
456             goto return_with_error;
457         }
458 
459     }
460     /* Clear interrupt register */
461     if (interrupt_register != 0)
462     {
463         if (whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, (uint8_t)2,
464                                              interrupt_register) != WHD_SUCCESS)
465         {
466             goto return_with_error;
467         }
468     }
469 
470     return ( uint32_t )( (interrupt_register) & (F2_PACKET_AVAILABLE) );
471 
472 return_with_error: whd_assert("Error accessing backplane", 0 != 0);
473     return 0;
474 }
475 
whd_bus_spi_read_frame(whd_driver_t whd_driver,whd_buffer_t * buffer)476 whd_result_t whd_bus_spi_read_frame(whd_driver_t whd_driver, whd_buffer_t *buffer)
477 {
478     uint32_t whd_bus_gspi_status;
479     whd_result_t result;
480     uint32_t whd_gspi_bytes_pending;
481 
482     /* Ensure the wlan backplane bus is up */
483     CHECK_RETURN(whd_ensure_wlan_bus_is_up(whd_driver) );
484 
485     do
486     {
487         result = whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_STATUS_REGISTER, (uint8_t)4,
488                                                  (uint8_t *)&whd_bus_gspi_status);
489         if (result != WHD_SUCCESS)
490         {
491             WPRINT_WHD_ERROR( ("Error reading register value, %s failed at %d \n", __func__, __LINE__) );
492             return result;
493         }
494     } while (whd_bus_gspi_status == 0xFFFFFFFF);
495 
496     if ( (whd_bus_gspi_status & GSPI_PACKET_AVAILABLE) != 0 )
497     {
498         if ( ( ( (whd_bus_gspi_status >> 9) & 0x7FF ) == 0 ) ||
499              ( ( (whd_bus_gspi_status >> 9) & 0x7FF ) > (WHD_LINK_MTU - WHD_BUS_GSPI_PACKET_OVERHEAD) ) ||
500              (whd_bus_gspi_status & GSPI_UNDERFLOW) )
501         {
502             CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BACKPLANE_FUNCTION, SPI_FRAME_CONTROL, 1,
503                                                           (1 << 0) ) );
504             return WHD_NO_PACKET_TO_RECEIVE;
505         }
506     }
507 
508     whd_gspi_bytes_pending = 0;
509 
510     if ( (whd_bus_gspi_status & GSPI_PACKET_AVAILABLE) != 0 )
511     {
512         whd_gspi_bytes_pending = ( (whd_bus_gspi_status >> 9) & 0x7FF );
513     }
514 
515     if (whd_gspi_bytes_pending == 0)
516     {
517         return WHD_NO_PACKET_TO_RECEIVE;
518     }
519 
520     /* Allocate a suitable buffer */
521     result = whd_host_buffer_get(whd_driver, buffer, WHD_NETWORK_RX,
522                                  (uint16_t)(whd_gspi_bytes_pending + WHD_BUS_GSPI_PACKET_OVERHEAD),
523                                  (whd_sdpcm_has_tx_packet(whd_driver) ? 0 : WHD_RX_BUF_TIMEOUT) );
524 
525     if (result != WHD_SUCCESS)
526     {
527         /* Read out the first 12 bytes to get the bus credit information */
528         uint8_t temp_buffer[12 + MAX_BUS_HEADER_SIZE];
529         CHECK_RETURN(whd_bus_spi_transfer_bytes(whd_driver, BUS_READ, WLAN_FUNCTION, 0, 12,
530                                                 (whd_transfer_bytes_packet_t *)temp_buffer) );
531 
532         /* Abort the transfer to force the packet to be dropped */
533         if (whd_gspi_bytes_pending > 12)
534         {
535             CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BACKPLANE_FUNCTION, SPI_FRAME_CONTROL, 1,
536                                                           (1 << 0) ) );
537         }
538 
539         /* Process bus data credit information */
540         whd_sdpcm_update_credit(whd_driver, (uint8_t *)(temp_buffer + sizeof(whd_bus_header_t) ) );
541         WPRINT_WHD_ERROR( ("Packet buffer allocation failed in %s at %d \n", __func__, __LINE__) );
542         return result;
543     }
544 
545     result = whd_bus_spi_transfer_buffer(whd_driver, BUS_READ, WLAN_FUNCTION, 0, *buffer);
546     if (result != WHD_SUCCESS)
547     {
548         CHECK_RETURN(whd_buffer_release(whd_driver, *buffer, WHD_NETWORK_RX) );
549         WPRINT_WHD_ERROR( ("SPI buffer transfer failed in %s at %d \n", __func__, __LINE__) );
550         return result;
551     }
552 
553     DELAYED_BUS_RELEASE_SCHEDULE (whd_driver, WHD_TRUE);
554     return WHD_SUCCESS;
555 }
556 
whd_bus_spi_init(whd_driver_t whd_driver)557 whd_result_t whd_bus_spi_init(whd_driver_t whd_driver)
558 {
559     uint32_t data = 0;
560     uint32_t whd_bus_gspi_status;
561     uint16_t data16 = 0;
562     uint32_t loop_count;
563     whd_result_t result;
564     uint8_t init_data[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
565     uint32_t interrupt_polarity = 0;
566     uint16_t chip_id;
567     size_t transfer_size = 12;
568     uint8_t *aligned_addr = NULL;
569     whd_oob_config_t *config = &whd_driver->bus_priv->spi_config.oob_config;
570 
571     whd_driver->bus_gspi_32bit = WHD_FALSE;
572 
573     if (config->is_falling_edge == WHD_FALSE)
574         interrupt_polarity = INTERRUPT_POLARITY_HIGH;
575 
576     whd_bus_init_backplane_window(whd_driver);
577 
578     whd_bus_gspi_header_t *gspi_header = (whd_bus_gspi_header_t *)init_data;
579 
580     /* Due to an chip issue, the first transfer will be corrupted.
581      * This means a repeated safe read of a known value register is required until
582      * the correct value is returned - signalling the bus is running.
583      * This known value register must be accessed using fixed (non-incrementing) address
584      * mode, hence a custom packet header must be constructed
585      * Due to the chip issue, the data received could be left shifted by one bit.
586      */
587     loop_count = 0;
588     do
589     {
590         /* Header needs to calculated every time as init_data gets modified in whd_bus_spi_transfer() */
591         *gspi_header =
592             ( whd_bus_gspi_header_t )SWAP32_16BIT_PARTS(SWAP32( (uint32_t)( (whd_bus_gspi_command_mapping[(int)BUS_READ]
593                                                                              & 0x1) << 31 ) |
594                                                                 (uint32_t)( (GSPI_FIXED_ADDRESS & 0x1) << 30 ) |
595                                                                 (uint32_t)( (BUS_FUNCTION & 0x3) << 28 ) |
596                                                                 (uint32_t)( (SPI_READ_TEST_REGISTER & 0x1FFFFu) <<
597                                                                             11 ) |
598                                                                 (uint32_t)( (4u /*size*/ & 0x7FFu) << 0 ) ) );
599         CHECK_RETURN(whd_bus_spi_transfer(whd_driver, NULL, sizeof(whd_bus_gspi_header_t),
600                                         init_data, transfer_size, 0) );
601         loop_count++;
602     } while ( (NULL == memchr(&init_data[4], SPI_READ_TEST_REG_LSB, (size_t)8) ) &&
603               (NULL == memchr(&init_data[4], SPI_READ_TEST_REG_LSB_SFT1, (size_t)8) ) &&
604               (NULL == memchr(&init_data[4], SPI_READ_TEST_REG_LSB_SFT2, (size_t)8) ) &&
605               (NULL == memchr(&init_data[4], SPI_READ_TEST_REG_LSB_SFT3, (size_t)8) ) &&
606               (loop_count < ( uint32_t )FEADBEAD_TIMEOUT_MS) &&
607               (cy_rtos_delay_milliseconds( (uint32_t)1 ), (1 == 1) ) );
608 
609     /* Register interrupt handler */
610     whd_bus_spi_irq_register(whd_driver);
611     /* Enable SPI IRQ */
612     whd_bus_spi_irq_enable(whd_driver, WHD_TRUE);
613 
614     /* Keep/reset defaults for registers 0x0-0x4 except for, 0x0: Change word length to 32bit,
615      * set endianness, enable wakeup. 0x2: enable interrupt with status. */
616 #if defined(IL_BIGENDIAN)
617     CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, (uint8_t)4,
618                                                   (uint32_t)(WORD_LENGTH_32 | (0 & ENDIAN_BIG) |
619                                                              (interrupt_polarity & INTERRUPT_POLARITY_HIGH) | WAKE_UP |
620                                                              (0x4 << (8 * SPI_RESPONSE_DELAY) ) |
621                                                              ( (0 & STATUS_ENABLE) << (8 * SPI_STATUS_ENABLE) ) |
622                                                              (INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE) ) ) ) );
623 #else
624     CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, (uint8_t)4,
625                                                   ( uint32_t )(WORD_LENGTH_32 | ENDIAN_BIG |
626                                                                (interrupt_polarity & INTERRUPT_POLARITY_HIGH) |
627                                                                WAKE_UP | (0x4 << (8 * SPI_RESPONSE_DELAY) ) |
628                                                                ( (0 & STATUS_ENABLE) << (8 * SPI_STATUS_ENABLE) ) |
629                                                                (INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE) ) ) ) );
630 #endif
631     whd_driver->bus_gspi_32bit = WHD_TRUE;
632     CHECK_RETURN(whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, (uint8_t)4,
633                                                  (uint8_t *)&data) );
634 
635     if (whd_driver->bus_priv->spi_config.is_spi_normal_mode)
636     {
637         /* Reset host SPI interface to re-sync */
638         /*host_platform_bus_init( );*/
639     }
640 
641     /* Check feedbead can be read - i.e. the device is alive */
642     data = 0;
643     CHECK_RETURN(whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_READ_TEST_REGISTER, (uint8_t)4,
644                                                  (uint8_t *)&data) );
645 
646     if (data != SPI_READ_TEST_REGISTER_VALUE)
647     {
648         WPRINT_WHD_ERROR( ("Read %x, instead of 0xFEEDBEAD from the WLAN chip\n", (unsigned int)data) );
649         return WHD_SPI_ID_READ_FAIL;
650     }
651 
652     /* Make sure error interrupt bits are clear */
653     CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, (uint8_t)1,
654                                                   ( uint32_t )(DATA_UNAVAILABLE | COMMAND_ERROR | DATA_ERROR |
655                                                                F1_OVERFLOW) ) );
656 
657     /* Enable a selection of interrupts */
658     CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_INTERRUPT_ENABLE_REGISTER, (uint8_t)2,
659                                                   ( uint32_t )(F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW |
660                                                                COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE |
661                                                                F1_OVERFLOW) ) );
662 
663     /* Request ALP */
664     CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
665                                                   SBSDIO_ALP_AVAIL_REQ) );
666 
667     /* Wait until ALP is available */
668     loop_count = 0;
669     while ( ( (result = whd_bus_spi_read_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)2,
670                                                         (uint8_t *)&data16) ) == WHD_SUCCESS ) &&
671             ( (data16 & SBSDIO_ALP_AVAIL) == 0 ) &&
672             (loop_count < ( uint32_t )ALP_AVAIL_TIMEOUT_MS) )
673     {
674         cy_rtos_delay_milliseconds( (uint32_t)1 );
675         loop_count++;
676     }
677     if (loop_count >= ( uint32_t )ALP_AVAIL_TIMEOUT_MS)
678     {
679         WPRINT_WHD_ERROR( ("ALP Clock timeout\n") );
680         return WHD_TIMEOUT;
681     }
682     if (result != WHD_SUCCESS)
683     {
684         WPRINT_WHD_ERROR( ("Can't read SDIO_CHIP_CLOCK_CSR\n") );
685         return result;
686     }
687 
688     /* Clear request for ALP */
689     CHECK_RETURN(whd_bus_spi_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
690                                                   (uint32_t)0) );
691 
692     /* Read the chip id */
693     CHECK_RETURN(whd_bus_spi_read_backplane_value(whd_driver, CHIPCOMMON_BASE_ADDRESS, 2, (uint8_t *)&chip_id) );
694     whd_chip_set_chip_id(whd_driver, chip_id);
695 
696     /* Download the firmware */
697     result = whd_spi_download_firmware(whd_driver);
698 
699     /* user abort */
700     if (result == WHD_UNFINISHED)
701     {
702         /* host_platform_reset_wifi (WHD_TRUE); */
703         /* host_platform_power_wifi (WHD_FALSE); */
704         WPRINT_WHD_ERROR( ("User aborted download of firmware\n") );
705         return result;
706     }
707 
708     /* non user abort error */
709     if (result != WHD_SUCCESS)
710     {
711         WPRINT_WHD_ERROR( ("Could not download firmware\n") );
712         return result;
713     }
714     /* else, successfully downloaded the firmware; continue with waiting for WIFi to live */
715 
716     /* Wait for F2 to be ready */
717     loop_count = 0;
718     while ( ( (result = whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_STATUS_REGISTER, (uint8_t)4,
719                                                         (uint8_t *)&whd_bus_gspi_status) ) == WHD_SUCCESS ) &&
720             ( (whd_bus_gspi_status & (1 << 5) ) == 0 ) &&
721             (loop_count < ( uint32_t )F2_READY_TIMEOUT_MS) )
722     {
723         cy_rtos_delay_milliseconds( (uint32_t)1 );
724         loop_count++;
725     }
726     if (loop_count >= ( uint32_t )F2_READY_TIMEOUT_MS)
727     {
728         /* If your system fails here, it could be due to incorrect NVRAM variables.
729          * Check which 'wifi_nvram_image.h' file your platform is using, and
730          * check that it matches the WLAN device on your platform, including the
731          * crystal frequency.
732          */
733         WPRINT_WHD_ERROR( ("Timeout while waiting for function 2 to be ready\n") );
734         return WHD_TIMEOUT;
735     }
736     if (whd_driver->aligned_addr == NULL)
737     {
738         if ( (aligned_addr = whd_mem_malloc(WHD_LINK_MTU) ) == NULL )
739         {
740             WPRINT_WHD_ERROR( ("Memory allocation failed for aligned_addr in %s \n", __FUNCTION__) );
741             return WHD_MALLOC_FAILURE;
742         }
743         whd_driver->aligned_addr = aligned_addr;
744     }
745     result = whd_chip_specific_init(whd_driver);
746     if (result != WHD_SUCCESS)
747     {
748         whd_mem_free(whd_driver->aligned_addr);
749         whd_driver->aligned_addr = NULL;
750     }
751     CHECK_RETURN(result);
752     result = whd_ensure_wlan_bus_is_up(whd_driver);
753     if (result != WHD_SUCCESS)
754     {
755         whd_mem_free(whd_driver->aligned_addr);
756         whd_driver->aligned_addr = NULL;
757     }
758     CHECK_RETURN(result);
759 
760     return result;
761 }
762 
whd_bus_spi_deinit(whd_driver_t whd_driver)763 whd_result_t whd_bus_spi_deinit(whd_driver_t whd_driver)
764 {
765     CHECK_RETURN(whd_allow_wlan_bus_to_sleep(whd_driver) );
766 
767     /* put device in reset. */
768     //host_platform_reset_wifi (WHD_TRUE);
769     if (whd_driver->aligned_addr)
770     {
771         whd_mem_free(whd_driver->aligned_addr);
772         whd_driver->aligned_addr = NULL;
773     }
774     whd_bus_set_resource_download_halt(whd_driver, WHD_FALSE);
775     DELAYED_BUS_RELEASE_SCHEDULE (whd_driver, WHD_FALSE);
776     return WHD_SUCCESS;
777 }
778 
whd_bus_spi_wake_interrupt_present(whd_driver_t whd_driver)779 whd_bool_t whd_bus_spi_wake_interrupt_present(whd_driver_t whd_driver)
780 {
781     /* functionality is only currently needed and present on SDIO */
782     return WHD_FALSE;
783 }
784 
whd_bus_spi_wait_for_wlan_event(whd_driver_t whd_driver,cy_semaphore_t * transceive_semaphore)785 whd_result_t whd_bus_spi_wait_for_wlan_event(whd_driver_t whd_driver, cy_semaphore_t *transceive_semaphore)
786 {
787     whd_result_t result = WHD_SUCCESS;
788     uint32_t timeout_ms = 1;
789     whd_bt_dev_t btdev = whd_driver->bt_dev;
790     uint32_t delayed_release_timeout_ms;
791 
792     REFERENCE_DEBUG_ONLY_VARIABLE(result);
793 
794     delayed_release_timeout_ms = whd_bus_handle_delayed_release(whd_driver);
795     if (delayed_release_timeout_ms != 0)
796     {
797         timeout_ms = delayed_release_timeout_ms;
798     }
799     else if ( (btdev && !btdev->intr) )
800     {
801         timeout_ms = BT_POLLING_TIME;
802         whd_driver->thread_info.bus_interrupt = WHD_TRUE;
803     }
804     else
805     {
806         result = whd_allow_wlan_bus_to_sleep(whd_driver);
807         whd_assert("Error setting wlan sleep", (result == WHD_SUCCESS) || (result == WHD_PENDING) );
808 
809         if (result == WHD_SUCCESS)
810         {
811             timeout_ms = CY_RTOS_NEVER_TIMEOUT;
812         }
813     }
814 
815     /* Check if we have run out of bus credits */
816     if (whd_sdpcm_get_available_credits(whd_driver) == 0)
817     {
818         /* Keep poking the WLAN until it gives us more credits */
819         result = whd_bus_spi_poke_wlan(whd_driver);
820         whd_assert("Poking failed!", result == WHD_SUCCESS);
821 
822         result = cy_rtos_get_semaphore(transceive_semaphore, (uint32_t)MIN_OF(timeout_ms,
823                                                                               WHD_THREAD_POKE_TIMEOUT), WHD_FALSE);
824     }
825     else
826     {
827         result = cy_rtos_get_semaphore(transceive_semaphore, (uint32_t)MIN_OF(timeout_ms,
828                                                                               WHD_THREAD_POLL_TIMEOUT), WHD_FALSE);
829     }
830     whd_assert("Could not get whd sleep semaphore\n", (result == CY_RSLT_SUCCESS) || (result == CY_RTOS_TIMEOUT) );
831 
832     return result;
833 }
834 
835 /******************************************************
836 *     Function definitions for Protocol Common
837 ******************************************************/
838 
839 /*
840  * Write a value to a register NOT on the backplane
841  * Prerequisites: value_length <= 4
842  */
whd_bus_spi_write_register_value(whd_driver_t whd_driver,whd_bus_function_t function,uint32_t address,uint8_t value_length,uint32_t value)843 whd_result_t whd_bus_spi_write_register_value(whd_driver_t whd_driver, whd_bus_function_t function, uint32_t address,
844                                               uint8_t value_length, uint32_t value)
845 {
846     char gspi_internal_buffer[MAX_BUS_HEADER_SIZE + sizeof(uint32_t) + sizeof(uint32_t)] = {0};
847     whd_transfer_bytes_packet_t *internal_gspi_packet = (whd_transfer_bytes_packet_t *)gspi_internal_buffer;
848 
849     /* Flip the bytes if we're not in 32 bit mode */
850     if (whd_driver->bus_gspi_32bit == WHD_FALSE)
851     {
852         value = H32TO16LE(value);
853     }
854     /* Write the value and value_length into the packet */
855     internal_gspi_packet->data[0] = value;
856 
857     /* Send it off */
858     return whd_bus_spi_transfer_bytes(whd_driver, BUS_WRITE, function, address, value_length, internal_gspi_packet);
859 }
860 
861 /*
862  * Read the value of a register NOT on the backplane
863  * Prerequisites: value_length <= 4
864  */
whd_bus_spi_read_register_value(whd_driver_t whd_driver,whd_bus_function_t function,uint32_t address,uint8_t value_length,uint8_t * value)865 whd_result_t whd_bus_spi_read_register_value(whd_driver_t whd_driver, whd_bus_function_t function, uint32_t address,
866                                              uint8_t value_length, uint8_t *value)
867 {
868     uint32_t *data_ptr;
869     whd_result_t result;
870     uint8_t padding = 0;
871 
872     char gspi_internal_buffer[MAX_BUS_HEADER_SIZE + sizeof(uint32_t) + sizeof(uint32_t)] = {0};
873 
874     /* Clear the receiving part of memory and set the value_length */
875     if (function == BACKPLANE_FUNCTION)
876     {
877         gspi_backplane_f1_read_packet_t *pkt =
878             (gspi_backplane_f1_read_packet_t *)(gspi_internal_buffer + MAX_BUS_HEADER_SIZE -
879                                                 sizeof(whd_bus_gspi_header_t) );
880         data_ptr = pkt->data;
881         padding = 4;   /* Add response delay */
882     }
883     else
884     {
885         whd_transfer_bytes_packet_t *pkt = (whd_transfer_bytes_packet_t *)gspi_internal_buffer;
886         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
887         data_ptr = pkt->data;
888         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
889     }
890 
891     *data_ptr = 0;
892     result =
893         whd_bus_spi_transfer_bytes(whd_driver, BUS_READ, function, address, ( uint16_t )(value_length + padding),
894                                    (whd_transfer_bytes_packet_t *)gspi_internal_buffer);
895 
896     memcpy(value, data_ptr, value_length);
897 
898     return result;
899 }
900 
901 /*
902  * Write a value to a register on the backplane
903  * Prerequisites: value_length <= 4
904  */
whd_bus_spi_write_backplane_value(whd_driver_t whd_driver,uint32_t address,uint8_t register_length,uint32_t value)905 whd_result_t whd_bus_spi_write_backplane_value(whd_driver_t whd_driver, uint32_t address, uint8_t register_length,
906                                                uint32_t value)
907 {
908     CHECK_RETURN(whd_bus_set_backplane_window(whd_driver, address) );
909 
910     address &= SBSDIO_SB_OFT_ADDR_MASK;
911 
912     if (register_length == 4)
913         address |= SBSDIO_SB_ACCESS_2_4B_FLAG;
914 
915     return whd_bus_spi_write_register_value(whd_driver, BACKPLANE_FUNCTION, address, register_length, value);
916 }
917 
918 /*
919  * Read the value of a register on the backplane
920  * Prerequisites: value_length <= 4
921  */
whd_bus_spi_read_backplane_value(whd_driver_t whd_driver,uint32_t address,uint8_t register_length,uint8_t * value)922 whd_result_t whd_bus_spi_read_backplane_value(whd_driver_t whd_driver, uint32_t address, uint8_t register_length,
923                                               uint8_t *value)
924 {
925     *value = 0;
926     CHECK_RETURN(whd_bus_set_backplane_window(whd_driver, address) );
927 
928     address &= SBSDIO_SB_OFT_ADDR_MASK;
929 
930     if (register_length == 4)
931         address |= SBSDIO_SB_ACCESS_2_4B_FLAG;
932 
933     return whd_bus_spi_read_register_value(whd_driver, BACKPLANE_FUNCTION, address, register_length, value);
934 }
935 
whd_bus_spi_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 * packet)936 whd_result_t whd_bus_spi_transfer_bytes(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
937                                         whd_bus_function_t function, uint32_t address, uint16_t size,
938                                         whd_transfer_bytes_packet_t *packet)
939 {
940     uint32_t *temp;
941     whd_result_t result;
942     uint16_t newsize;
943     DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
944     whd_bus_gspi_header_t *gspi_header =
945         (whd_bus_gspi_header_t *)( (char *)packet->data - sizeof(whd_bus_gspi_header_t) );
946     ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
947     size_t transfer_size;
948 
949     *gspi_header =
950         ( whd_bus_gspi_header_t )( ( uint32_t )( (whd_bus_gspi_command_mapping[(int)direction] & 0x1) << 31 ) |
951                                    ( uint32_t )( (GSPI_INCREMENT_ADDRESS & 0x1) << 30 ) |
952                                    ( uint32_t )( (function & 0x3) << 28 ) |
953                                    ( uint32_t )( (address & 0x1FFFF) << 11 ) | ( uint32_t )( (size & 0x7FF) << 0 ) );
954 
955     /* Reshuffle the bits if we're not in 32 bit mode */
956     if (whd_driver->bus_gspi_32bit == WHD_FALSE)
957     {
958         /* Note: This typecast should always be valid if the buffer
959          * containing the GSpi packet has been correctly declared as 32-bit aligned */
960         temp = (uint32_t *)gspi_header;
961         *temp = H32TO16LE(*temp);
962     }
963 
964     /* Round size up to 32-bit alignment */
965     newsize = (uint16_t)ROUND_UP(size, 4);
966 
967     /* Ensure we are clear to write */
968     if ( (direction == BUS_WRITE) && (function == WLAN_FUNCTION) )
969     {
970         uint32_t whd_bus_gspi_status;
971         uint32_t loop_count = 0;
972 
973         /* Verify the SDPCM size and stated size match */
974         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
975         uint16_t *frametag_ptr = (uint16_t *)&packet->data;
976         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
977         if (size != *frametag_ptr)
978         {
979             WPRINT_WHD_DEBUG( ("Error - gSPI size does not match SDPCM size!\n") );
980             return WHD_SPI_SIZE_MISMATCH;
981         }
982 
983         /* Wait for WLAN FIFO to be ready to accept data */
984         while ( ( (result =
985                        whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_STATUS_REGISTER, (uint8_t)4,
986                                                        (uint8_t *)&whd_bus_gspi_status) ) == WHD_SUCCESS ) &&
987                 ( (whd_bus_gspi_status & (1 << 5) ) == 0 ) &&
988                 (loop_count < ( uint32_t )F2_READY_TIMEOUT_LOOPS) )
989         {
990             ++loop_count;
991         }
992 
993         if (result != WHD_SUCCESS)
994         {
995             WPRINT_WHD_ERROR( ("Failed to read SPI register value in %s at %d \n", __func__, __LINE__) );
996             return result;
997         }
998 
999         if (loop_count >= ( uint32_t )F2_READY_TIMEOUT_LOOPS)
1000         {
1001             WPRINT_WHD_DEBUG( ("Timeout waiting for data FIFO to be ready\n") );
1002             return WHD_TIMEOUT;
1003         }
1004 
1005     }
1006 
1007     transfer_size = (size_t)(newsize + sizeof(whd_bus_gspi_header_t) );
1008 
1009     /* Send the data */
1010     if (direction == BUS_READ)
1011     {
1012         result = whd_bus_spi_transfer(whd_driver, NULL, sizeof(whd_bus_gspi_header_t),
1013                                     (uint8_t *)gspi_header,transfer_size, 0);
1014     }
1015     else
1016     {
1017         result = whd_bus_spi_transfer(whd_driver, (uint8_t *)gspi_header,
1018                                       transfer_size, NULL,0, 0);
1019     }
1020 
1021     CHECK_RETURN(result);
1022     return WHD_SUCCESS;
1023 }
1024 
1025 /******************************************************
1026 *             Static  Function definitions
1027 ******************************************************/
1028 
whd_spi_download_firmware(whd_driver_t whd_driver)1029 static whd_result_t whd_spi_download_firmware(whd_driver_t whd_driver)
1030 {
1031     uint8_t csr_val;
1032     whd_result_t result;
1033     uint32_t loop_count = 0;
1034 
1035     CHECK_RETURN(whd_disable_device_core(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_NONE) );
1036     CHECK_RETURN(whd_disable_device_core(whd_driver, SOCRAM_CORE, WLAN_CORE_FLAG_NONE) );
1037     CHECK_RETURN(whd_reset_device_core(whd_driver, SOCRAM_CORE, WLAN_CORE_FLAG_NONE) );
1038 
1039     CHECK_RETURN(whd_chip_specific_socsram_init(whd_driver) );
1040 
1041     CHECK_RETURN(whd_bus_write_wifi_firmware_image(whd_driver) );
1042     CHECK_RETURN(whd_bus_spi_write_wifi_nvram_image(whd_driver) );
1043 
1044     /* Take the ARM core out of reset */
1045     CHECK_RETURN(whd_reset_device_core(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_NONE) );
1046     result = whd_device_core_is_up(whd_driver, WLAN_ARM_CORE);
1047     if (result != WHD_SUCCESS)
1048     {
1049         WPRINT_WHD_ERROR( ("Could not bring ARM core up\n") );
1050         return result;
1051     }
1052 
1053     /* Wait until the HT clock is available */
1054     while ( ( (result =
1055                    whd_bus_spi_read_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_CHIP_CLOCK_CSR, (uint8_t)1,
1056                                                    &csr_val) ) == WHD_SUCCESS ) &&
1057             ( (csr_val & SBSDIO_HT_AVAIL) == 0 ) &&
1058             (loop_count < ( uint32_t )HT_AVAIL_TIMEOUT_MS) )
1059     {
1060         cy_rtos_delay_milliseconds( (uint32_t)1 );
1061         loop_count++;
1062     }
1063     if (loop_count >= ( uint32_t )HT_AVAIL_TIMEOUT_MS)
1064     {
1065         return WHD_TIMEOUT;
1066     }
1067     if (result != WHD_SUCCESS)
1068     {
1069         WPRINT_WHD_ERROR( ("HT clock not available\n") );
1070         return result;
1071     }
1072 
1073     /* Set up the interrupt mask and enable interrupts */
1074     CHECK_RETURN(whd_bus_spi_write_backplane_value(whd_driver, SDIO_INT_HOST_MASK(
1075                                                        whd_driver), (uint8_t)4, I_HMB_SW_MASK) );
1076 
1077     /* Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped. */
1078     return whd_bus_spi_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_FUNCTION2_WATERMARK, (uint8_t)1,
1079                                             ( uint32_t )SPI_F2_WATERMARK);
1080 }
1081 
whd_bus_spi_wakeup(whd_driver_t whd_driver)1082 whd_result_t whd_bus_spi_wakeup(whd_driver_t whd_driver)
1083 {
1084     uint32_t spi_bus_reg_value;
1085 
1086     /* Wake up WLAN SPI interface module */
1087     CHECK_RETURN(whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, sizeof(uint32_t),
1088                                                  (uint8_t *)&spi_bus_reg_value) );
1089     spi_bus_reg_value |= ( uint32_t )(WAKE_UP);
1090     return whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, sizeof(uint32_t),
1091                                             spi_bus_reg_value);
1092 }
1093 
whd_bus_spi_sleep(whd_driver_t whd_driver)1094 whd_result_t whd_bus_spi_sleep(whd_driver_t whd_driver)
1095 {
1096     uint32_t spi_bus_reg_value;
1097 
1098     /* Put SPI interface block to sleep */
1099     CHECK_RETURN(whd_bus_spi_read_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, sizeof(uint32_t),
1100                                                  (uint8_t *)&spi_bus_reg_value) );
1101     spi_bus_reg_value &= ~( uint32_t )(WAKE_UP);
1102     return whd_bus_spi_write_register_value(whd_driver, BUS_FUNCTION, SPI_BUS_CONTROL, sizeof(uint32_t),
1103                                             spi_bus_reg_value);
1104 }
1105 
whd_bus_spi_init_stats(whd_driver_t whd_driver)1106 void whd_bus_spi_init_stats(whd_driver_t whd_driver)
1107 {
1108     whd_bt_dev_t btdev = whd_driver->bt_dev;
1109 
1110     if (btdev && btdev->intr)
1111     {
1112         whd_result_t res;
1113         /* Enable F1 INT in order to receive interrupt from BT FW with HMB_FC_CHANGED in SPI */
1114         res = whd_bus_write_register_value(whd_driver, BUS_FUNCTION, (uint32_t)SPI_INTERRUPT_ENABLE_REGISTER,
1115                                            (uint8_t)2,
1116                                            ( uint32_t )(F1_INTR | F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW |
1117                                                         COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE |
1118                                                         F1_OVERFLOW) );
1119         if (res != WHD_SUCCESS)
1120         {
1121             WPRINT_WHD_ERROR( ("spi interrupt register failed to enable\n") );
1122         }
1123 
1124         res = whd_bus_spi_write_backplane_value(whd_driver, SDIO_INT_HOST_MASK(
1125                                                     whd_driver), (uint8_t)4, I_HMB_FC_CHANGE);
1126         if (res != WHD_SUCCESS)
1127         {
1128             WPRINT_WHD_ERROR( ("sdio int host mask failed to enable\n") );
1129         }
1130     }
1131 }
1132 
whd_bus_spi_print_stats(whd_driver_t whd_driver,whd_bool_t reset_after_print)1133 whd_result_t whd_bus_spi_print_stats(whd_driver_t whd_driver, whd_bool_t reset_after_print)
1134 {
1135     return WHD_TRUE;
1136 }
1137 
1138 /* Waking the firmware up from Deep Sleep */
whd_bus_spi_reinit_stats(whd_driver_t whd_driver,whd_bool_t wake_from_firmware)1139 whd_result_t whd_bus_spi_reinit_stats(whd_driver_t whd_driver, whd_bool_t wake_from_firmware)
1140 {
1141     return WHD_TRUE;
1142 }
1143 
whd_bus_spi_backplane_read_padd_size(whd_driver_t whd_driver)1144 uint8_t whd_bus_spi_backplane_read_padd_size(whd_driver_t whd_driver)
1145 {
1146     return WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE;
1147 }
1148 
whd_bus_spi_use_status_report_scheme(whd_driver_t whd_driver)1149 whd_bool_t whd_bus_spi_use_status_report_scheme(whd_driver_t whd_driver)
1150 {
1151     return WHD_FALSE;
1152 }
1153 
whd_bus_spi_get_max_transfer_size(whd_driver_t whd_driver)1154 uint32_t whd_bus_spi_get_max_transfer_size(whd_driver_t whd_driver)
1155 {
1156     return WHD_BUS_SPI_MAX_BACKPLANE_TRANSFER_SIZE;
1157 }
1158 
1159 #ifndef WHD_USE_CUSTOM_HAL_IMPL
1160 #if (CYHAL_API_VERSION >= 2)
whd_bus_spi_oob_irq_handler(void * arg,cyhal_gpio_event_t event)1161 static void whd_bus_spi_oob_irq_handler(void *arg, cyhal_gpio_event_t event)
1162 #else
1163 static void whd_bus_spi_oob_irq_handler(void *arg, cyhal_gpio_irq_event_t event)
1164 #endif /* (CYHAL_API_VERSION >= 2) */
1165 {
1166     whd_driver_t whd_driver = (whd_driver_t)arg;
1167     const whd_oob_config_t *config = &whd_driver->bus_priv->spi_config.oob_config;
1168 #if (CYHAL_API_VERSION >= 2)
1169     const cyhal_gpio_event_t expected_event = (config->is_falling_edge == WHD_TRUE)
1170                                               ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1171 #else
1172     const cyhal_gpio_irq_event_t expected_event = (config->is_falling_edge == WHD_TRUE)
1173                                                   ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1174 #endif /* (CYHAL_API_VERSION >= 2) */
1175     if (event != expected_event)
1176     {
1177         WPRINT_WHD_ERROR( ("Unexpected interrupt event %d\n", event) );
1178 
1179         return;
1180     }
1181 
1182     /* call thread notify to wake up WHD thread */
1183     whd_thread_notify_irq(whd_driver);
1184 }
1185 
1186 /* XXX FIXME */
1187 #define WLAN_INTR_PRIORITY 1
whd_bus_spi_irq_register(whd_driver_t whd_driver)1188 whd_result_t whd_bus_spi_irq_register(whd_driver_t whd_driver)
1189 {
1190     const whd_oob_config_t *config = &whd_driver->bus_priv->spi_config.oob_config;
1191 
1192     cyhal_gpio_init(config->host_oob_pin, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_ANALOG,
1193                     (config->is_falling_edge == WHD_TRUE) ? 1 : 0);
1194 #if (CYHAL_API_VERSION >= 2)
1195     static cyhal_gpio_callback_data_t cbdata;
1196     cbdata.callback = whd_bus_spi_oob_irq_handler;
1197     cbdata.callback_arg = whd_driver;
1198     cyhal_gpio_register_callback(config->host_oob_pin, &cbdata);
1199 #else
1200     cyhal_gpio_register_irq(config->host_oob_pin, WLAN_INTR_PRIORITY, whd_bus_spi_oob_irq_handler,
1201                             whd_driver);
1202 #endif /* (CYHAL_API_VERSION >= 2) */
1203     return WHD_TRUE;
1204 }
1205 
whd_bus_spi_irq_enable(whd_driver_t whd_driver,whd_bool_t enable)1206 whd_result_t whd_bus_spi_irq_enable(whd_driver_t whd_driver, whd_bool_t enable)
1207 {
1208     const whd_oob_config_t *config = &whd_driver->bus_priv->spi_config.oob_config;
1209 #if (CYHAL_API_VERSION >= 2)
1210     const cyhal_gpio_event_t event =
1211         (config->is_falling_edge == WHD_TRUE) ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1212 
1213     cyhal_gpio_enable_event(config->host_oob_pin, event, WLAN_INTR_PRIORITY, (enable == WHD_TRUE) ? true : false);
1214 #else
1215     const cyhal_gpio_irq_event_t event =
1216         (config->is_falling_edge == WHD_TRUE) ? CYHAL_GPIO_IRQ_FALL : CYHAL_GPIO_IRQ_RISE;
1217 
1218     cyhal_gpio_irq_enable(config->host_oob_pin, event, (enable == WHD_TRUE) ? true : false);
1219 #endif /* (CYHAL_API_VERSION >= 2) */
1220     return WHD_TRUE;
1221 }
1222 #endif /* ifndef WHD_USE_CUSTOM_HAL_IMPL */
1223 
whd_bus_spi_download_resource(whd_driver_t whd_driver,whd_resource_type_t resource,whd_bool_t direct_resource,uint32_t address,uint32_t image_size)1224 static whd_result_t whd_bus_spi_download_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
1225                                                   whd_bool_t direct_resource, uint32_t address, uint32_t image_size)
1226 {
1227     whd_result_t result = WHD_SUCCESS;
1228     uint8_t *image;
1229     uint32_t blocks_count = 0;
1230     uint32_t i;
1231     uint32_t size_out;
1232     uint32_t reset_instr = 0;
1233 
1234     result = whd_get_resource_no_of_blocks(whd_driver, resource, &blocks_count);
1235     if (result != WHD_SUCCESS)
1236     {
1237         WPRINT_WHD_ERROR( ("Fatal error: download_resource blocks count not known, %s failed at line %d \n", __func__,
1238                            __LINE__) );
1239         goto exit;
1240     }
1241 
1242     for (i = 0; i < blocks_count; i++)
1243     {
1244         CHECK_RETURN(whd_get_resource_block(whd_driver, resource, i, (const uint8_t **)&image, &size_out) );
1245         if ( (resource == WHD_RESOURCE_WLAN_FIRMWARE) && (reset_instr == 0) )
1246         {
1247             /* Copy the starting address of the firmware into a global variable */
1248             reset_instr = *( (uint32_t *)(&image[0]) );
1249         }
1250         result = whd_bus_transfer_backplane_bytes(whd_driver, BUS_WRITE, address, size_out, &image[0]);
1251         if (result != WHD_SUCCESS)
1252         {
1253             WPRINT_WHD_ERROR( ("%s: Failed to write firmware image\n", __FUNCTION__) );
1254             goto exit;
1255         }
1256         address += size_out;
1257     }
1258 
1259     /* Below part of the code is applicable to arm_CR4 type chips only
1260      * The CR4 chips by default firmware is not loaded at 0. So we need
1261      * load the first 32 bytes with the offset of the firmware load address
1262      * which is been copied before during the firmware download
1263      */
1264     if ( (address != 0) && (reset_instr != 0) )
1265     {
1266         /* write address 0 with reset instruction */
1267         result = whd_bus_write_backplane_value(whd_driver, 0, sizeof(reset_instr), reset_instr);
1268 
1269         if (result == WHD_SUCCESS)
1270         {
1271             uint32_t tmp;
1272 
1273             /* verify reset instruction value */
1274             result = whd_bus_read_backplane_value(whd_driver, 0, sizeof(tmp), (uint8_t *)&tmp);
1275 
1276             if ( (result == WHD_SUCCESS) && (tmp != reset_instr) )
1277             {
1278                 WPRINT_WHD_ERROR( ("%s: Failed to write 0x%08" PRIx32 " to addr 0\n", __FUNCTION__, reset_instr) );
1279                 WPRINT_WHD_ERROR( ("%s: contents of addr 0 is 0x%08" PRIx32 "\n", __FUNCTION__, tmp) );
1280                 return WHD_WLAN_SDIO_ERROR;
1281             }
1282         }
1283     }
1284 exit: return result;
1285 }
1286 
whd_bus_spi_write_wifi_nvram_image(whd_driver_t whd_driver)1287 static whd_result_t whd_bus_spi_write_wifi_nvram_image(whd_driver_t whd_driver)
1288 {
1289     uint32_t img_base;
1290     uint32_t img_end;
1291     uint32_t image_size;
1292 
1293     /* Get the size of the variable image */
1294     CHECK_RETURN(whd_resource_size(whd_driver, WHD_RESOURCE_WLAN_NVRAM, &image_size) );
1295 
1296     /* Round up the size of the image */
1297     image_size = ROUND_UP(image_size, 4);
1298 
1299     /* Write image */
1300     img_end = GET_C_VAR(whd_driver, CHIP_RAM_SIZE) - 4;
1301     img_base = (img_end - image_size);
1302     img_base += GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
1303 
1304     CHECK_RETURN(whd_bus_spi_download_resource(whd_driver, WHD_RESOURCE_WLAN_NVRAM, WHD_FALSE, img_base, image_size) );
1305 
1306     /* Write the variable image size at the end */
1307     image_size = (~(image_size / 4) << 16) | (image_size / 4);
1308 
1309     img_end += GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
1310 
1311     CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, (uint32_t)img_end, 4, image_size) );
1312     return WHD_SUCCESS;
1313 }
1314 
1315 /*
1316  * Update the backplane window registers
1317  */
whd_bus_spi_set_backplane_window(whd_driver_t whd_driver,uint32_t addr,uint32_t * curbase)1318 static whd_result_t whd_bus_spi_set_backplane_window(whd_driver_t whd_driver, uint32_t addr, uint32_t *curbase)
1319 {
1320     whd_result_t result = WHD_BUS_WRITE_REGISTER_ERROR;
1321     uint32_t base = addr & ( (uint32_t) ~BACKPLANE_ADDRESS_MASK );
1322     const uint32_t upper_32bit_mask = 0xFF000000;
1323     const uint32_t upper_middle_32bit_mask = 0x00FF0000;
1324     const uint32_t lower_middle_32bit_mask = 0x0000FF00;
1325 
1326     if (base == *curbase)
1327     {
1328         return WHD_SUCCESS;
1329     }
1330     if ( (base & upper_32bit_mask) != (*curbase & upper_32bit_mask) )
1331     {
1332         if (WHD_SUCCESS !=
1333             (result = whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_BACKPLANE_ADDRESS_HIGH,
1334                                                    (uint8_t)1, (base >> 24) ) ) )
1335         {
1336             WPRINT_WHD_ERROR( ("Failed to write register value to the bus, %s failed at %d \n", __func__,
1337                                __LINE__) );
1338             return result;
1339         }
1340         /* clear old */
1341         *curbase &= ~upper_32bit_mask;
1342         /* set new */
1343         *curbase |= (base & upper_32bit_mask);
1344     }
1345 
1346     if ( (base & upper_middle_32bit_mask) !=
1347          (*curbase & upper_middle_32bit_mask) )
1348     {
1349         if (WHD_SUCCESS !=
1350             (result = whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_BACKPLANE_ADDRESS_MID,
1351                                                    (uint8_t)1, (base >> 16) ) ) )
1352         {
1353             WPRINT_WHD_ERROR( ("Failed to write register value to the bus, %s failed at %d \n", __func__,
1354                                __LINE__) );
1355             return result;
1356         }
1357         /* clear old */
1358         *curbase &= ~upper_middle_32bit_mask;
1359         /* set new */
1360         *curbase |= (base & upper_middle_32bit_mask);
1361     }
1362 
1363     if ( (base & lower_middle_32bit_mask) !=
1364          (*curbase & lower_middle_32bit_mask) )
1365     {
1366         if (WHD_SUCCESS !=
1367             (result = whd_bus_write_register_value(whd_driver, BACKPLANE_FUNCTION, SDIO_BACKPLANE_ADDRESS_LOW,
1368                                                    (uint8_t)1, (base >> 8) ) ) )
1369         {
1370             WPRINT_WHD_ERROR( ("Failed to write register value to the bus, %s failed at %d \n", __func__,
1371                                __LINE__) );
1372             return result;
1373         }
1374 
1375         /* clear old */
1376         *curbase &= ~lower_middle_32bit_mask;
1377         /* set new */
1378         *curbase |= (base & lower_middle_32bit_mask);
1379     }
1380 
1381     return WHD_SUCCESS;
1382 }
1383 
1384 #endif /* (CYBSP_WIFI_INTERFACE_TYPE == CYBSP_SPI_INTERFACE) */
1385 
1386