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