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