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  *
20  */
21 #include <stdlib.h>
22 #include "cyabs_rtos.h"
23 
24 #include "whd_bus.h"
25 #include "whd_bus_common.h"
26 #include "whd_chip_reg.h"
27 #include "whd_sdio.h"
28 #include "whd_chip_constants.h"
29 #include "whd_int.h"
30 #include "whd_chip.h"
31 #include "whd_bus_protocol_interface.h"
32 #include "whd_debug.h"
33 #include "whd_buffer_api.h"
34 #include "whd_resource_if.h"
35 #include "whd_resource_api.h"
36 #include "whd_types_int.h"
37 
38 
39 /******************************************************
40 *                      Macros
41 ******************************************************/
42 #define WHD_SAVE_INTERRUPTS(flags) do { UNUSED_PARAMETER(flags); } while (0);
43 #define WHD_RESTORE_INTERRUPTS(flags) do { } while (0);
44 
45 /******************************************************
46 *             Constants
47 ******************************************************/
48 #define INDIRECT_BUFFER_SIZE                    (1024)
49 #define WHD_BUS_ROUND_UP_ALIGNMENT              (64)
50 #define WHD_BUS_MAX_TRANSFER_SIZE               (WHD_BUS_MAX_BACKPLANE_TRANSFER_SIZE)
51 
52 #define WHD_BUS_WLAN_ALLOW_SLEEP_INVALID_MS  ( (uint32_t)-1 )
53 
54 /******************************************************
55 *             Structures
56 ******************************************************/
57 
58 struct whd_bus_common_info
59 {
60     whd_bool_t bus_is_up;
61 
62     whd_time_t delayed_bus_release_deadline;
63     whd_bool_t delayed_bus_release_scheduled;
64     uint32_t delayed_bus_release_timeout_ms;
65     volatile uint32_t delayed_bus_release_timeout_ms_request;
66 
67     uint32_t backplane_window_current_base_address;
68     whd_bool_t bus_flow_control;
69     volatile whd_bool_t resource_download_abort;
70 };
71 
72 /******************************************************
73 *             Variables
74 ******************************************************/
75 
76 /******************************************************
77 *             Function declarations
78 ******************************************************/
79 whd_result_t whd_bus_common_write_wifi_nvram_image(whd_driver_t whd_driver);
80 
81 /******************************************************
82 *             Function definitions
83 ******************************************************/
84 
whd_bus_is_up(whd_driver_t whd_driver)85 whd_bool_t whd_bus_is_up(whd_driver_t whd_driver)
86 {
87     return whd_driver->bus_common_info->bus_is_up;
88 }
89 
whd_bus_set_state(whd_driver_t whd_driver,whd_bool_t state)90 void whd_bus_set_state(whd_driver_t whd_driver, whd_bool_t state)
91 {
92     whd_driver->bus_common_info->bus_is_up = state;
93 }
94 
whd_bus_set_flow_control(whd_driver_t whd_driver,uint8_t value)95 whd_result_t whd_bus_set_flow_control(whd_driver_t whd_driver, uint8_t value)
96 {
97     if (value != 0)
98     {
99         whd_driver->bus_common_info->bus_flow_control = WHD_TRUE;
100     }
101     else
102     {
103         whd_driver->bus_common_info->bus_flow_control = WHD_FALSE;
104     }
105     return WHD_SUCCESS;
106 }
107 
whd_bus_is_flow_controlled(whd_driver_t whd_driver)108 whd_bool_t whd_bus_is_flow_controlled(whd_driver_t whd_driver)
109 {
110     return whd_driver->bus_common_info->bus_flow_control;
111 }
112 
whd_bus_set_backplane_window(whd_driver_t whd_driver,uint32_t addr)113 whd_result_t whd_bus_set_backplane_window(whd_driver_t whd_driver, uint32_t addr)
114 {
115     uint32_t *curbase = &whd_driver->bus_common_info->backplane_window_current_base_address;
116     return whd_driver->bus_if->whd_bus_set_backplane_window_fptr(whd_driver, addr, curbase);
117 }
118 
119 
whd_bus_common_info_init(whd_driver_t whd_driver)120 void whd_bus_common_info_init(whd_driver_t whd_driver)
121 {
122     struct whd_bus_common_info *bus_common = (struct whd_bus_common_info *)malloc(sizeof(struct whd_bus_common_info) );
123 
124     if (bus_common != NULL)
125     {
126         whd_driver->bus_common_info = bus_common;
127 
128         bus_common->delayed_bus_release_deadline = 0;
129         bus_common->delayed_bus_release_scheduled = WHD_FALSE;
130         bus_common->delayed_bus_release_timeout_ms = PLATFORM_WLAN_ALLOW_BUS_TO_SLEEP_DELAY_MS;
131         bus_common->delayed_bus_release_timeout_ms_request = WHD_BUS_WLAN_ALLOW_SLEEP_INVALID_MS;
132         bus_common->backplane_window_current_base_address = 0;
133 
134         bus_common->bus_is_up = WHD_FALSE;
135         bus_common->bus_flow_control = WHD_FALSE;
136 
137         bus_common->resource_download_abort = WHD_FALSE;
138     }
139     else
140     {
141         WPRINT_WHD_ERROR( ("Memory allocation failed for whd_bus_common_info in %s\n", __FUNCTION__) );
142     }
143 }
144 
whd_bus_common_info_deinit(whd_driver_t whd_driver)145 void whd_bus_common_info_deinit(whd_driver_t whd_driver)
146 {
147     if (whd_driver->bus_common_info != NULL)
148     {
149         free(whd_driver->bus_common_info);
150         whd_driver->bus_common_info = NULL;
151     }
152 }
153 
whd_delayed_bus_release_schedule_update(whd_driver_t whd_driver,whd_bool_t is_scheduled)154 void whd_delayed_bus_release_schedule_update(whd_driver_t whd_driver, whd_bool_t is_scheduled)
155 {
156     whd_driver->bus_common_info->delayed_bus_release_scheduled = is_scheduled;
157     whd_driver->bus_common_info->delayed_bus_release_deadline = 0;
158 }
159 
whd_bus_handle_delayed_release(whd_driver_t whd_driver)160 uint32_t whd_bus_handle_delayed_release(whd_driver_t whd_driver)
161 {
162     uint32_t time_until_release = 0;
163     uint32_t current_time = 0;
164     struct whd_bus_common_info *bus_common = whd_driver->bus_common_info;
165 
166     if (bus_common->delayed_bus_release_timeout_ms_request != WHD_BUS_WLAN_ALLOW_SLEEP_INVALID_MS)
167     {
168         whd_bool_t schedule =
169             ( (bus_common->delayed_bus_release_scheduled != 0) ||
170               (bus_common->delayed_bus_release_deadline != 0) ) ? WHD_TRUE : WHD_FALSE;
171         uint32_t flags;
172 
173         WHD_SAVE_INTERRUPTS(flags);
174         bus_common->delayed_bus_release_timeout_ms = bus_common->delayed_bus_release_timeout_ms_request;
175         bus_common->delayed_bus_release_timeout_ms_request = WHD_BUS_WLAN_ALLOW_SLEEP_INVALID_MS;
176         WHD_RESTORE_INTERRUPTS(flags);
177 
178         DELAYED_BUS_RELEASE_SCHEDULE(whd_driver, schedule);
179     }
180 
181     if (bus_common->delayed_bus_release_scheduled == WHD_TRUE)
182     {
183         bus_common->delayed_bus_release_scheduled = WHD_FALSE;
184 
185         if (bus_common->delayed_bus_release_timeout_ms != 0)
186         {
187             cy_rtos_get_time(&current_time);
188             bus_common->delayed_bus_release_deadline = current_time +
189                                                        bus_common->delayed_bus_release_timeout_ms;
190             time_until_release = bus_common->delayed_bus_release_timeout_ms;
191         }
192     }
193     else if (bus_common->delayed_bus_release_deadline != 0)
194     {
195         whd_time_t now;
196 
197         cy_rtos_get_time(&now);
198 
199         if (bus_common->delayed_bus_release_deadline - now <= bus_common->delayed_bus_release_timeout_ms)
200         {
201             time_until_release = bus_common->delayed_bus_release_deadline - now;
202         }
203 
204         if (time_until_release == 0)
205         {
206             bus_common->delayed_bus_release_deadline = 0;
207         }
208     }
209 
210     if (time_until_release != 0)
211     {
212         if (whd_bus_is_up(whd_driver) == WHD_FALSE)
213         {
214             time_until_release = 0;
215         }
216         else if (whd_bus_platform_mcu_power_save_deep_sleep_enabled(whd_driver) )
217         {
218             time_until_release = 0;
219         }
220     }
221 
222     return time_until_release;
223 }
224 
whd_bus_platform_mcu_power_save_deep_sleep_enabled(whd_driver_t whd_driver)225 whd_bool_t whd_bus_platform_mcu_power_save_deep_sleep_enabled(whd_driver_t whd_driver)
226 {
227     return WHD_FALSE;
228 }
229 
whd_bus_init_backplane_window(whd_driver_t whd_driver)230 void whd_bus_init_backplane_window(whd_driver_t whd_driver)
231 {
232     whd_driver->bus_common_info->backplane_window_current_base_address = 0;
233 }
234 
whd_bus_write_wifi_firmware_image(whd_driver_t whd_driver)235 whd_result_t whd_bus_write_wifi_firmware_image(whd_driver_t whd_driver)
236 {
237     whd_result_t result = WHD_SUCCESS;
238     uint32_t ram_start_address;
239     uint32_t image_size;
240 
241     /* Pass the ram_start_address to the firmware Download
242      * CR4 chips have offset and CM3 starts from 0 */
243 
244     ram_start_address = GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
245 
246     result = whd_resource_size(whd_driver, WHD_RESOURCE_WLAN_FIRMWARE, &image_size);
247 
248     if (result != WHD_SUCCESS)
249     {
250         WPRINT_WHD_ERROR( ("Fatal error: download_resource doesn't exist, %s failed at line %d \n", __func__,
251                            __LINE__) );
252         return result;
253     }
254 
255     if (image_size <= 0)
256     {
257         WPRINT_WHD_ERROR( ("Fatal error: download_resource cannot load with invalid size, %s failed at line %d \n",
258                            __func__, __LINE__) );
259         return WHD_BADARG;
260     }
261 
262     result = whd_bus_download_resource(whd_driver, WHD_RESOURCE_WLAN_FIRMWARE, WHD_FALSE, ram_start_address, image_size);
263 
264     if (result != WHD_SUCCESS)
265         WPRINT_WHD_ERROR( ("Bus common resource download failed, %s failed at %d \n", __func__, __LINE__) );
266 
267     return result;
268 }
269 
whd_bus_set_resource_download_halt(whd_driver_t whd_driver,whd_bool_t halt)270 void whd_bus_set_resource_download_halt(whd_driver_t whd_driver, whd_bool_t halt)
271 {
272     whd_driver->bus_common_info->resource_download_abort = halt;
273 }
274 
275 /* Default implementation of WHD bus resume function, which does nothing */
whd_bus_resume_after_deep_sleep(whd_driver_t whd_driver)276 whd_result_t whd_bus_resume_after_deep_sleep(whd_driver_t whd_driver)
277 {
278     whd_assert("In order to support deep-sleep platform need to implement this function", 0);
279     return WHD_UNSUPPORTED;
280 }
281 
whd_bus_mem_bytes(whd_driver_t whd_driver,uint8_t direct,uint32_t address,uint32_t size,uint8_t * data)282 whd_result_t whd_bus_mem_bytes(whd_driver_t whd_driver, uint8_t direct,
283                                uint32_t address, uint32_t size, uint8_t *data)
284 {
285     whd_bus_transfer_direction_t direction = direct ? BUS_WRITE : BUS_READ;
286     CHECK_RETURN(whd_ensure_wlan_bus_is_up(whd_driver) );
287     return whd_bus_transfer_backplane_bytes(whd_driver, direction, address, size, data);
288 }
289 
whd_bus_transfer_backplane_bytes(whd_driver_t whd_driver,whd_bus_transfer_direction_t direction,uint32_t address,uint32_t size,uint8_t * data)290 whd_result_t whd_bus_transfer_backplane_bytes(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
291                                               uint32_t address, uint32_t size, uint8_t *data)
292 {
293     whd_buffer_t pkt_buffer = NULL;
294     uint8_t *packet;
295     uint32_t transfer_size;
296     uint32_t remaining_buf_size;
297     uint32_t window_offset_address;
298 	uint32_t trans_addr;
299     whd_result_t result;
300 
301     result = whd_host_buffer_get(whd_driver, &pkt_buffer, (direction == BUS_READ) ? WHD_NETWORK_RX : WHD_NETWORK_TX,
302                                  ( uint16_t )(whd_bus_get_max_transfer_size(whd_driver) +
303                                               whd_bus_backplane_read_padd_size(
304                                                   whd_driver) + MAX_BUS_HEADER_SIZE), WHD_BACKPLAIN_BUF_TIMEOUT);
305     if (result != WHD_SUCCESS)
306     {
307         WPRINT_WHD_ERROR( ("Packet buffer allocation failed in %s at %d \n", __func__, __LINE__) );
308         goto done;
309     }
310     packet = (uint8_t *)whd_buffer_get_current_piece_data_pointer(whd_driver, pkt_buffer);
311     CHECK_PACKET_NULL(packet, WHD_NO_REGISTER_FUNCTION_POINTER);
312     for (remaining_buf_size = size; remaining_buf_size != 0;
313          remaining_buf_size -= transfer_size, address += transfer_size)
314     {
315         transfer_size = (remaining_buf_size >
316                          whd_bus_get_max_transfer_size(whd_driver) ) ? whd_bus_get_max_transfer_size(whd_driver) :
317                         remaining_buf_size;
318 
319         /* Check if the transfer crosses the backplane window boundary */
320         window_offset_address = address & BACKPLANE_ADDRESS_MASK;
321         if ( (window_offset_address + transfer_size) > BACKPLANE_ADDRESS_MASK )
322         {
323             /* Adjust the transfer size to within current window */
324             transfer_size = BACKPLANE_WINDOW_SIZE - window_offset_address;
325         }
326         result = whd_bus_set_backplane_window(whd_driver, address);
327         if (result == WHD_UNSUPPORTED)
328         {
329             /* No backplane support, write data to address directly */
330             trans_addr = address;
331         }
332         else if (result == WHD_SUCCESS)
333         {
334             trans_addr = address & BACKPLANE_ADDRESS_MASK;
335         }
336         else
337         {
338             goto done;
339         }
340 
341         if (direction == BUS_WRITE)
342         {
343             DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
344             memcpy( ( (whd_transfer_bytes_packet_t *)packet )->data, data + size - remaining_buf_size, transfer_size );
345             ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
346             result = whd_bus_transfer_bytes(whd_driver, direction, BACKPLANE_FUNCTION,
347                                             trans_addr, (uint16_t)transfer_size,
348                                             (whd_transfer_bytes_packet_t *)packet);
349             if (result != WHD_SUCCESS)
350             {
351                 goto done;
352             }
353         }
354         else
355         {
356             result = whd_bus_transfer_bytes(whd_driver, direction, BACKPLANE_FUNCTION,
357                                             trans_addr,
358                                             ( uint16_t )(transfer_size + whd_bus_backplane_read_padd_size(whd_driver) ),
359                                             (whd_transfer_bytes_packet_t *)packet);
360             if (result != WHD_SUCCESS)
361             {
362                 WPRINT_WHD_ERROR( ("whd_bus_transfer_bytes failed\n") );
363                 goto done;
364             }
365             DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
366             memcpy(data + size - remaining_buf_size, (uint8_t *)( (whd_transfer_bytes_packet_t *)packet )->data +
367                                                      whd_bus_backplane_read_padd_size(whd_driver), transfer_size);
368             ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
369         }
370     }
371 
372 done:
373     whd_bus_set_backplane_window(whd_driver, CHIPCOMMON_BASE_ADDRESS);
374     if (pkt_buffer != NULL)
375     {
376         CHECK_RETURN(whd_buffer_release(whd_driver, pkt_buffer,
377                                         (direction == BUS_READ) ? WHD_NETWORK_RX : WHD_NETWORK_TX) );
378     }
379     CHECK_RETURN(result);
380 
381     return WHD_SUCCESS;
382 }
383