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(¤t_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