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 M2M Protocol interface
20  *
21  *  Implements the WHD Bus Protocol Interface for M2M
22  *  Provides functions for initialising, de-intitialising 802.11 device,
23  *  sending/receiving raw packets etc
24  */
25 
26 #include "cybsp.h"
27 #if (CYBSP_WIFI_INTERFACE_TYPE == CYBSP_M2M_INTERFACE)
28 
29 #include "cyhal_dma.h"
30 #include "cyhal_hw_types.h"
31 #include "whd_bus_m2m_protocol.h"
32 
33 #include "whd_bus.h"
34 #include "whd_bus_common.h"
35 #include "whd_chip_reg.h"
36 #include "whd_chip_constants.h"
37 #include "whd_buffer_api.h"
38 #include "whd_types_int.h"
39 #include "whd_types.h"
40 #include "whd_thread_internal.h"
41 #include "whd_resource_if.h"
42 #include "whd_wlioctl.h"
43 
44 /******************************************************
45 *             Constants
46 ******************************************************/
47 
48 #define WHD_BUS_M2M_BACKPLANE_READ_PADD_SIZE    (0)
49 #define WHD_BUS_M2M_MAX_BACKPLANE_TRANSFER_SIZE (WHD_PAYLOAD_MTU)
50 #define BOOT_WLAN_WAIT_TIME                     (5)     /* 5ms wait time */
51 #define M2M_DMA_RX_BUFFER_SIZE                  (WHD_PHYSICAL_HEADER + WLC_IOCTL_MEDLEN)
52 
53 #define ARMCR4_SW_INT0                      (0x1 << 0)
54 
55 #if !defined (__IAR_SYSTEMS_ICC__)
56 /* assume registers are Device memory, so have implicit CPU memory barriers */
57 #define MEMORY_BARRIER_AGAINST_COMPILER_REORDERING()  __asm__ __volatile__ ("" : : : "memory")
58 #define REGISTER_WRITE_WITH_BARRIER(type, address, value) \
59     do {*(volatile type *)(address) = (type)(value); \
60         MEMORY_BARRIER_AGAINST_COMPILER_REORDERING();} while (0)
61 #define REGISTER_READ(type, address) \
62     (*(volatile type *)(address) )
63 #endif
64 
65 /******************************************************
66 *             Structures
67 ******************************************************/
68 struct whd_bus_priv
69 {
70     whd_m2m_config_t m2m_config;
71     cyhal_m2m_t *m2m_obj;
72 };
73 
74 /******************************************************
75 *             Variables
76 ******************************************************/
77 static whd_bus_info_t whd_bus_m2m_info;
78 static struct whd_bus_priv whd_bus_priv;
79 
80 /******************************************************
81 *             Function declarations
82 ******************************************************/
83 static whd_result_t whd_bus_m2m_init(whd_driver_t whd_driver);
84 static whd_result_t whd_bus_m2m_deinit(whd_driver_t whd_driver);
85 static whd_result_t whd_bus_m2m_ack_interrupt(whd_driver_t whd_driver, uint32_t intstatus);
86 static whd_result_t whd_bus_m2m_send_buffer(whd_driver_t whd_driver, whd_buffer_t buffer);
87 
88 static whd_bool_t whd_bus_m2m_wake_interrupt_present(whd_driver_t whd_driver);
89 static uint32_t whd_bus_m2m_packet_available_to_read(whd_driver_t whd_driver);
90 static whd_result_t whd_bus_m2m_read_frame(whd_driver_t whd_driver, whd_buffer_t *buffer);
91 
92 static whd_result_t whd_bus_m2m_write_backplane_value(whd_driver_t whd_driver, uint32_t address,
93                                                       uint8_t register_length, uint32_t value);
94 static whd_result_t whd_bus_m2m_read_backplane_value(whd_driver_t whd_driver, uint32_t address, uint8_t register_length,
95                                                      uint8_t *value);
96 static whd_result_t whd_bus_m2m_write_register_value(whd_driver_t whd_driver, whd_bus_function_t function,
97                                                      uint32_t address, uint8_t value_length, uint32_t value);
98 static whd_result_t whd_bus_m2m_read_register_value(whd_driver_t whd_driver, whd_bus_function_t function,
99                                                     uint32_t address, uint8_t value_length, uint8_t *value);
100 static whd_result_t whd_bus_m2m_transfer_bytes(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
101                                                whd_bus_function_t function, uint32_t address, uint16_t size,
102                                                whd_transfer_bytes_packet_t *data);
103 
104 static whd_result_t whd_bus_m2m_poke_wlan(whd_driver_t whd_driver);
105 static whd_result_t whd_bus_m2m_wakeup(whd_driver_t whd_driver);
106 static whd_result_t whd_bus_m2m_sleep(whd_driver_t whd_driver);
107 static uint8_t whd_bus_m2m_backplane_read_padd_size(whd_driver_t whd_driver);
108 static whd_result_t whd_bus_m2m_wait_for_wlan_event(whd_driver_t whd_driver, cy_semaphore_t *transceive_semaphore);
109 static whd_bool_t whd_bus_m2m_use_status_report_scheme(whd_driver_t whd_driver);
110 static uint32_t whd_bus_m2m_get_max_transfer_size(whd_driver_t whd_driver);
111 static void whd_bus_m2m_init_stats(whd_driver_t whd_driver);
112 static whd_result_t whd_bus_m2m_print_stats(whd_driver_t whd_driver, whd_bool_t reset_after_print);
113 static whd_result_t whd_bus_m2m_reinit_stats(whd_driver_t whd_driver, whd_bool_t wake_from_firmware);
114 static whd_result_t whd_bus_m2m_irq_register(whd_driver_t whd_driver);
115 static whd_result_t whd_bus_m2m_irq_enable(whd_driver_t whd_driver, whd_bool_t enable);
116 static whd_result_t whd_bus_m2m_download_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
117                                                   whd_bool_t direct_resource, uint32_t address, uint32_t image_size);
118 static whd_result_t whd_bus_m2m_write_wifi_nvram_image(whd_driver_t whd_driver);
119 static whd_result_t whd_bus_m2m_set_backplane_window(whd_driver_t whd_driver, uint32_t addr, uint32_t *curaddr);
120 
121 static whd_result_t boot_wlan(whd_driver_t whd_driver);
122 whd_bool_t whd_ensure_wlan_is_up(whd_driver_t whd_driver);
123 whd_result_t m2m_bus_write_wifi_firmware_image(whd_driver_t whd_driver);
124 void whd_bus_m2m_irq_handler(void *callback_arg, cyhal_m2m_event_t events);
125 
126 
127 /******************************************************
128 *             Function definitions
129 ******************************************************/
130 
131 // Functions for whd_driver->bus_if function list
whd_bus_m2m_attach(whd_driver_t whd_driver,whd_m2m_config_t * whd_m2m_config,cyhal_m2m_t * m2m_obj)132 uint32_t whd_bus_m2m_attach(whd_driver_t whd_driver, whd_m2m_config_t *whd_m2m_config, cyhal_m2m_t *m2m_obj)
133 {
134     WPRINT_WHD_INFO( ("m2m_attach\n") );
135 
136     whd_driver->bus_if   = &whd_bus_m2m_info;
137     whd_driver->bus_priv = &whd_bus_priv;
138 
139     memset(whd_driver->bus_if, 0, sizeof(whd_bus_info_t) );
140     memset(whd_driver->bus_priv, 0, sizeof(struct whd_bus_priv) );
141 
142     whd_driver->bus_priv->m2m_obj = m2m_obj;
143     whd_driver->bus_priv->m2m_config = *whd_m2m_config;
144 
145     whd_driver->bus_if->whd_bus_init_fptr = whd_bus_m2m_init;
146     whd_driver->bus_if->whd_bus_deinit_fptr = whd_bus_m2m_deinit;
147 
148     whd_driver->bus_if->whd_bus_ack_interrupt_fptr = whd_bus_m2m_ack_interrupt;
149     whd_driver->bus_if->whd_bus_send_buffer_fptr = whd_bus_m2m_send_buffer;
150 
151     whd_driver->bus_if->whd_bus_wake_interrupt_present_fptr = whd_bus_m2m_wake_interrupt_present;
152     whd_driver->bus_if->whd_bus_packet_available_to_read_fptr = whd_bus_m2m_packet_available_to_read;
153     whd_driver->bus_if->whd_bus_read_frame_fptr = whd_bus_m2m_read_frame;
154 
155 
156     whd_driver->bus_if->whd_bus_write_backplane_value_fptr = whd_bus_m2m_write_backplane_value;
157     whd_driver->bus_if->whd_bus_read_backplane_value_fptr = whd_bus_m2m_read_backplane_value;
158 
159     whd_driver->bus_if->whd_bus_write_register_value_fptr = whd_bus_m2m_write_register_value;
160     whd_driver->bus_if->whd_bus_read_register_value_fptr = whd_bus_m2m_read_register_value;
161 
162     whd_driver->bus_if->whd_bus_transfer_bytes_fptr = whd_bus_m2m_transfer_bytes;
163 
164     whd_driver->bus_if->whd_bus_poke_wlan_fptr = whd_bus_m2m_poke_wlan;
165 
166     whd_driver->bus_if->whd_bus_wakeup_fptr = whd_bus_m2m_wakeup;
167     whd_driver->bus_if->whd_bus_sleep_fptr = whd_bus_m2m_sleep;
168 
169     whd_driver->bus_if->whd_bus_backplane_read_padd_size_fptr = whd_bus_m2m_backplane_read_padd_size;
170 
171     whd_driver->bus_if->whd_bus_wait_for_wlan_event_fptr = whd_bus_m2m_wait_for_wlan_event;
172     whd_driver->bus_if->whd_bus_use_status_report_scheme_fptr = whd_bus_m2m_use_status_report_scheme;
173 
174     whd_driver->bus_if->whd_bus_get_max_transfer_size_fptr = whd_bus_m2m_get_max_transfer_size;
175 
176     whd_driver->bus_if->whd_bus_init_stats_fptr = whd_bus_m2m_init_stats;
177     whd_driver->bus_if->whd_bus_print_stats_fptr = whd_bus_m2m_print_stats;
178     whd_driver->bus_if->whd_bus_reinit_stats_fptr = whd_bus_m2m_reinit_stats;
179     whd_driver->bus_if->whd_bus_irq_register_fptr = whd_bus_m2m_irq_register;
180     whd_driver->bus_if->whd_bus_irq_enable_fptr = whd_bus_m2m_irq_enable;
181     whd_driver->bus_if->whd_bus_download_resource_fptr = whd_bus_m2m_download_resource;
182     whd_driver->bus_if->whd_bus_set_backplane_window_fptr = whd_bus_m2m_set_backplane_window;
183 
184     return WHD_SUCCESS;
185 }
186 
whd_bus_m2m_detach(whd_driver_t whd_driver)187 void whd_bus_m2m_detach(whd_driver_t whd_driver)
188 {
189     whd_driver->bus_if = NULL;
190     whd_driver->bus_priv = NULL;
191 }
192 
whd_bus_m2m_irq_handler(void * callback_arg,cyhal_m2m_event_t events)193 void whd_bus_m2m_irq_handler(void *callback_arg, cyhal_m2m_event_t events)
194 {
195     whd_driver_t whd_driver = (whd_driver_t)callback_arg;
196 
197     whd_bus_m2m_irq_enable(whd_driver, WHD_FALSE);
198     whd_thread_notify_irq(whd_driver);
199 }
200 
whd_bus_m2m_init(whd_driver_t whd_driver)201 static whd_result_t whd_bus_m2m_init(whd_driver_t whd_driver)
202 {
203     whd_result_t result = WHD_SUCCESS;
204 
205 #if !defined (__IAR_SYSTEMS_ICC__)
206     /* Get chip id */
207     whd_chip_set_chip_id(whd_driver, (uint16_t)REGISTER_READ(uint32_t, CHIPCOMMON_BASE_ADDRESS) );
208 #endif
209 
210     result = boot_wlan(whd_driver);
211 
212     if (result == WHD_SUCCESS)
213     {
214         cyhal_m2m_init(whd_driver->bus_priv->m2m_obj, M2M_DMA_RX_BUFFER_SIZE);
215         cyhal_m2m_register_callback(whd_driver->bus_priv->m2m_obj, whd_bus_m2m_irq_handler, whd_driver);
216     }
217     return result;
218 }
219 
whd_bus_m2m_deinit(whd_driver_t whd_driver)220 static whd_result_t whd_bus_m2m_deinit(whd_driver_t whd_driver)
221 {
222     //PLATFORM_WLAN_POWERSAVE_RES_UP();
223 
224     /* Down M2M and WLAN */
225     CHECK_RETURN(whd_disable_device_core(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_CPU_HALT) );
226     cyhal_m2m_free(whd_driver->bus_priv->m2m_obj);
227 
228     /* Put WLAN to reset. */
229     //host_platform_reset_wifi( WICED_TRUE );
230 
231     //PLATFORM_WLAN_POWERSAVE_RES_DOWN( NULL, WICED_FALSE );
232 
233     /* Force resource down even if resource up/down is unbalanced */
234     //PLATFORM_WLAN_POWERSAVE_RES_DOWN( NULL, WICED_TRUE );
235 
236     CHECK_RETURN(whd_allow_wlan_bus_to_sleep(whd_driver) );
237 
238     whd_bus_set_resource_download_halt(whd_driver, WHD_FALSE);
239 
240     DELAYED_BUS_RELEASE_SCHEDULE(whd_driver, WHD_FALSE);
241 
242     return WHD_SUCCESS;
243 }
244 
whd_bus_m2m_ack_interrupt(whd_driver_t whd_driver,uint32_t intstatus)245 static whd_result_t whd_bus_m2m_ack_interrupt(whd_driver_t whd_driver, uint32_t intstatus)
246 {
247     return WHD_SUCCESS;
248 }
249 
whd_bus_m2m_send_buffer(whd_driver_t whd_driver,whd_buffer_t buffer)250 static whd_result_t whd_bus_m2m_send_buffer(whd_driver_t whd_driver, whd_buffer_t buffer)
251 {
252     whd_result_t result = WHD_SUCCESS;
253 
254     if (cyhal_m2m_tx_send(whd_driver->bus_priv->m2m_obj, buffer) != CY_RSLT_SUCCESS)
255     {
256         result = WHD_WLAN_ERROR;
257     }
258 
259     return result;
260 }
261 
whd_bus_m2m_wake_interrupt_present(whd_driver_t whd_driver)262 static whd_bool_t whd_bus_m2m_wake_interrupt_present(whd_driver_t whd_driver)
263 {
264     /* functionality is only currently needed and present on SDIO */
265     return WHD_FALSE;
266 }
267 
whd_bus_m2m_packet_available_to_read(whd_driver_t whd_driver)268 static uint32_t whd_bus_m2m_packet_available_to_read(whd_driver_t whd_driver)
269 {
270     return 1;
271 }
272 
whd_bus_m2m_read_frame(whd_driver_t whd_driver,whd_buffer_t * buffer)273 static whd_result_t whd_bus_m2m_read_frame(whd_driver_t whd_driver, whd_buffer_t *buffer)
274 {
275     whd_result_t result = WHD_SUCCESS;
276     cyhal_m2m_event_t m2m_event;
277     uint16_t *hwtag;
278     void *packet = NULL;
279     bool signal_txdone;
280 
281     cyhal_m2m_rx_prepare(whd_driver->bus_priv->m2m_obj);
282 
283     m2m_event = cyhal_m2m_intr_status(whd_driver->bus_priv->m2m_obj, &signal_txdone);
284     if (signal_txdone)
285     {
286         /* Signal WLAN core there is a TX done by setting wlancr4 SW interrupt 0 */
287         CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, GET_C_VAR(whd_driver, PMU_BASE_ADDRESS) + 0x1c,
288                                                    (uint8_t)4, ARMCR4_SW_INT0) );
289     }
290 
291     /* Handle DMA interrupts */
292     if ( (m2m_event & CYHAL_M2M_TX_CHANNEL_INTERRUPT) != 0 )
293     {
294         cyhal_m2m_tx_release(whd_driver->bus_priv->m2m_obj);
295     }
296 
297     /* Handle DMA receive interrupt */
298     cyhal_m2m_rx_receive(whd_driver->bus_priv->m2m_obj, &packet, &hwtag);
299     if (packet == NULL)
300     {
301         result = WHD_NO_PACKET_TO_RECEIVE;
302     }
303     else
304     {
305         *buffer = packet;
306 
307         /* move the data pointer 12 bytes(sizeof(wwd_buffer_header_t))
308          * back to the start of the pakcet
309          */
310         whd_buffer_add_remove_at_front(whd_driver, buffer, -(int)sizeof(whd_buffer_header_t) );
311         whd_sdpcm_update_credit(whd_driver, (uint8_t *)hwtag);
312     }
313 
314     cyhal_m2m_rx_prepare(whd_driver->bus_priv->m2m_obj);
315 
316     return result;
317 }
318 
whd_bus_m2m_write_backplane_value(whd_driver_t whd_driver,uint32_t address,uint8_t register_length,uint32_t value)319 static whd_result_t whd_bus_m2m_write_backplane_value(whd_driver_t whd_driver, uint32_t address,
320                                                       uint8_t register_length, uint32_t value)
321 {
322 #if !defined (__IAR_SYSTEMS_ICC__)
323     MEMORY_BARRIER_AGAINST_COMPILER_REORDERING();
324 
325     if (register_length == 4)
326     {
327         REGISTER_WRITE_WITH_BARRIER(uint32_t, address, value);
328     }
329     else if (register_length == 2)
330     {
331         REGISTER_WRITE_WITH_BARRIER(uint16_t, address, value);
332     }
333     else if (register_length == 1)
334     {
335         REGISTER_WRITE_WITH_BARRIER(uint8_t, address, value);
336     }
337     else
338     {
339         return WHD_WLAN_ERROR;
340     }
341 #endif
342     return WHD_SUCCESS;
343 }
344 
whd_bus_m2m_read_backplane_value(whd_driver_t whd_driver,uint32_t address,uint8_t register_length,uint8_t * value)345 static whd_result_t whd_bus_m2m_read_backplane_value(whd_driver_t whd_driver, uint32_t address,
346                                                      uint8_t register_length, /*@out@*/ uint8_t *value)
347 {
348 #if !defined (__IAR_SYSTEMS_ICC__)
349     MEMORY_BARRIER_AGAINST_COMPILER_REORDERING();
350 
351     if (register_length == 4)
352     {
353         *( (uint32_t *)value ) = REGISTER_READ(uint32_t, address);
354     }
355     else if (register_length == 2)
356     {
357         *( (uint16_t *)value ) = REGISTER_READ(uint16_t, address);
358     }
359     else if (register_length == 1)
360     {
361         *value = REGISTER_READ(uint8_t, address);
362     }
363     else
364     {
365         return WHD_WLAN_ERROR;
366     }
367 #endif
368     return WHD_SUCCESS;
369 }
370 
whd_bus_m2m_write_register_value(whd_driver_t whd_driver,whd_bus_function_t function,uint32_t address,uint8_t value_length,uint32_t value)371 static whd_result_t whd_bus_m2m_write_register_value(whd_driver_t whd_driver, whd_bus_function_t function,
372                                                      uint32_t address, uint8_t value_length, uint32_t value)
373 {
374     // Not used by M2M bus
375     return WHD_SUCCESS;
376 }
377 
whd_bus_m2m_read_register_value(whd_driver_t whd_driver,whd_bus_function_t function,uint32_t address,uint8_t value_length,uint8_t * value)378 static whd_result_t whd_bus_m2m_read_register_value(whd_driver_t whd_driver, whd_bus_function_t function,
379                                                     uint32_t address, uint8_t value_length, uint8_t *value)
380 {
381     // Not used by M2M bus
382     return WHD_SUCCESS;
383 }
384 
whd_bus_m2m_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 * data)385 static whd_result_t whd_bus_m2m_transfer_bytes(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction,
386                                                whd_bus_function_t function, uint32_t address, uint16_t size,
387                                                whd_transfer_bytes_packet_t *data)
388 {
389     if (function != BACKPLANE_FUNCTION)
390     {
391         return WHD_DOES_NOT_EXIST;
392     }
393 
394     if (direction == BUS_WRITE)
395     {
396         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
397         memcpy( (uint8_t *)address, data->data, size );
398         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
399         if (address == 0)
400         {
401             uint32_t resetinst = *( (uint32_t *)data->data );
402 
403             /* CR4_FF_ROM_SHADOW_INDEX_REGISTER */
404             CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, GET_C_VAR(whd_driver, PMU_BASE_ADDRESS) + 0x080,
405                                                        (uint8_t)1, 0) );
406 
407             /* CR4_FF_ROM_SHADOW_DATA_REGISTER */
408             CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, GET_C_VAR(whd_driver, PMU_BASE_ADDRESS) + 0x084,
409                                                        (uint8_t)4, resetinst) );
410         }
411     }
412     else
413     {
414         DISABLE_COMPILER_WARNING(diag_suppress = Pa039)
415         memcpy(data->data, (uint8_t *)address, size);
416         ENABLE_COMPILER_WARNING(diag_suppress = Pa039)
417     }
418 
419     return WHD_SUCCESS;
420 }
421 
whd_bus_m2m_poke_wlan(whd_driver_t whd_driver)422 static whd_result_t whd_bus_m2m_poke_wlan(whd_driver_t whd_driver)
423 {
424     // Not used by M2M bus
425     return WHD_SUCCESS;
426 }
427 
whd_bus_m2m_wakeup(whd_driver_t whd_driver)428 static whd_result_t whd_bus_m2m_wakeup(whd_driver_t whd_driver)
429 {
430     WPRINT_WHD_INFO( ("bus_m2m_wakeup\n") );
431     return WHD_SUCCESS;
432 }
433 
whd_bus_m2m_sleep(whd_driver_t whd_driver)434 static whd_result_t whd_bus_m2m_sleep(whd_driver_t whd_driver)
435 {
436     WPRINT_WHD_INFO( ("bus_m2m_sleep\n") );
437     return WHD_SUCCESS;
438 }
439 
whd_bus_m2m_backplane_read_padd_size(whd_driver_t whd_driver)440 static uint8_t whd_bus_m2m_backplane_read_padd_size(whd_driver_t whd_driver)
441 {
442     return WHD_BUS_M2M_BACKPLANE_READ_PADD_SIZE;
443 }
444 
whd_bus_m2m_wait_for_wlan_event(whd_driver_t whd_driver,cy_semaphore_t * transceive_semaphore)445 static whd_result_t whd_bus_m2m_wait_for_wlan_event(whd_driver_t whd_driver, cy_semaphore_t *transceive_semaphore)
446 {
447     whd_result_t result = WHD_SUCCESS;
448     uint32_t timeout_ms;
449 
450     timeout_ms = CY_RTOS_NEVER_TIMEOUT;
451 
452     whd_bus_m2m_irq_enable(whd_driver, WHD_TRUE);
453     result = cy_rtos_get_semaphore(transceive_semaphore, timeout_ms, WHD_FALSE);
454 
455     return result;
456 }
457 
whd_bus_m2m_use_status_report_scheme(whd_driver_t whd_driver)458 static whd_bool_t whd_bus_m2m_use_status_report_scheme(whd_driver_t whd_driver)
459 {
460     /* !M2M_RX_POLL_MODE */
461     return WHD_FALSE;
462 }
463 
whd_bus_m2m_get_max_transfer_size(whd_driver_t whd_driver)464 static uint32_t whd_bus_m2m_get_max_transfer_size(whd_driver_t whd_driver)
465 {
466     return WHD_BUS_M2M_MAX_BACKPLANE_TRANSFER_SIZE;
467 }
468 
whd_bus_m2m_init_stats(whd_driver_t whd_driver)469 static void whd_bus_m2m_init_stats(whd_driver_t whd_driver)
470 {
471     /* To be implemented */
472 }
473 
whd_bus_m2m_print_stats(whd_driver_t whd_driver,whd_bool_t reset_after_print)474 static whd_result_t whd_bus_m2m_print_stats(whd_driver_t whd_driver, whd_bool_t reset_after_print)
475 {
476     /* To be implemented */
477     UNUSED_VARIABLE(reset_after_print);
478     WPRINT_MACRO( ("Bus stats not available\n") );
479     return WHD_SUCCESS;
480 }
481 
whd_bus_m2m_reinit_stats(whd_driver_t whd_driver,whd_bool_t wake_from_firmware)482 static whd_result_t whd_bus_m2m_reinit_stats(whd_driver_t whd_driver, whd_bool_t wake_from_firmware)
483 {
484     UNUSED_PARAMETER(wake_from_firmware);
485     /* functionality is only currently needed and present on SDIO */
486     return WHD_UNSUPPORTED;
487 }
488 
whd_bus_m2m_irq_register(whd_driver_t whd_driver)489 static whd_result_t whd_bus_m2m_irq_register(whd_driver_t whd_driver)
490 {
491     return WHD_TRUE;
492 }
493 
whd_bus_m2m_irq_enable(whd_driver_t whd_driver,whd_bool_t enable)494 static whd_result_t whd_bus_m2m_irq_enable(whd_driver_t whd_driver, whd_bool_t enable)
495 {
496     if (enable)
497     {
498         WPRINT_WHD_INFO( ("M2M interrupt enable\n") );
499         _cyhal_system_m2m_enable_irq();
500         _cyhal_system_sw0_enable_irq();
501     }
502     else
503     {
504         WPRINT_WHD_INFO( ("M2M interrupt disable\n") );
505         _cyhal_system_m2m_disable_irq();
506         _cyhal_system_sw0_disable_irq();
507     }
508     return WHD_TRUE;
509 }
510 
m2m_bus_write_wifi_firmware_image(whd_driver_t whd_driver)511 whd_result_t m2m_bus_write_wifi_firmware_image(whd_driver_t whd_driver)
512 {
513     /* Halt ARM and remove from reset */
514     WPRINT_WHD_INFO( ("Reset wlan core..\n") );
515     VERIFY_RESULT(whd_reset_device_core(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_CPU_HALT) );
516 
517     return whd_bus_write_wifi_firmware_image(whd_driver);
518 }
519 
boot_wlan(whd_driver_t whd_driver)520 static whd_result_t boot_wlan(whd_driver_t whd_driver)
521 {
522     whd_result_t result = WHD_SUCCESS;
523 
524     /* Load wlan firmware from sflash */
525     result = m2m_bus_write_wifi_firmware_image(whd_driver);
526     if ( (result == WHD_UNFINISHED) || (result != WHD_SUCCESS) )
527     {
528         /* for user abort, then put wifi module into known good state */
529         return result;
530     }
531 
532     VERIFY_RESULT(whd_bus_m2m_write_wifi_nvram_image(whd_driver) );
533 
534     /* Release ARM core */
535     WPRINT_WHD_INFO( ("Release WLAN core..\n") );
536     VERIFY_RESULT(whd_wlan_armcore_run(whd_driver, WLAN_ARM_CORE, WLAN_CORE_FLAG_NONE) );
537 
538 #if (PLATFORM_BACKPLANE_ON_CPU_CLOCK_ENABLE == 0)
539     /*
540      * Wifi firmware initialization will change some BBPLL settings. When backplane clock
541      * source is not on CPU clock, accessing backplane during that period might wedge the
542      * ACPU. Running a delay loop in cache can avoid the wedge. At least 3ms is required
543      * to avoid the problem.
544      */
545     cy_rtos_delay_milliseconds(10);
546 #endif  /* PLATFORM_BACKPLANE_ON_CPU_CLOCK_ENABLE == 0 */
547 
548     return result;
549 }
550 
whd_bus_m2m_download_resource(whd_driver_t whd_driver,whd_resource_type_t resource,whd_bool_t direct_resource,uint32_t address,uint32_t image_size)551 static whd_result_t whd_bus_m2m_download_resource(whd_driver_t whd_driver, whd_resource_type_t resource,
552                                                   whd_bool_t direct_resource, uint32_t address,
553                                                   uint32_t image_size)
554 {
555     whd_result_t result = WHD_SUCCESS;
556     uint32_t size_out;
557     uint32_t reset_instr = 0;
558 
559     CHECK_RETURN(whd_resource_read(whd_driver, resource, 0,
560                                    GET_C_VAR(whd_driver, CHIP_RAM_SIZE), &size_out,
561                                    (uint8_t *)(address) ) );
562 
563     CHECK_RETURN(whd_resource_read(whd_driver, resource, 0, 4, &size_out, &reset_instr) );
564 
565     /* CR4_FF_ROM_SHADOW_INDEX_REGISTER */
566     CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, GET_C_VAR(whd_driver, PMU_BASE_ADDRESS) + 0x080,
567                                                (uint8_t)1, 0) );
568 
569     /* CR4_FF_ROM_SHADOW_DATA_REGISTER */
570     CHECK_RETURN(whd_bus_write_backplane_value(whd_driver, GET_C_VAR(whd_driver, PMU_BASE_ADDRESS) + 0x084,
571                                                (uint8_t)4, reset_instr) );
572 
573     return result;
574 }
575 
whd_bus_m2m_write_wifi_nvram_image(whd_driver_t whd_driver)576 static whd_result_t whd_bus_m2m_write_wifi_nvram_image(whd_driver_t whd_driver)
577 {
578     uint32_t nvram_size;
579     uint32_t nvram_destination_address;
580     uint32_t nvram_size_in_words;
581     uint32_t size_out;
582     uint32_t image_size;
583 
584     /* Get the size of the variable image */
585     CHECK_RETURN(whd_resource_size(whd_driver, WHD_RESOURCE_WLAN_NVRAM, &image_size) );
586 
587     /* Round up the size of the image */
588     nvram_size = ROUND_UP(image_size, 4);
589 
590     /* Put the NVRAM image at the end of RAM leaving the last 4 bytes for the size */
591     nvram_destination_address = (GET_C_VAR(whd_driver, CHIP_RAM_SIZE) - 4) - nvram_size;
592     nvram_destination_address += GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS);
593 
594     /* Write NVRAM image into WLAN RAM */
595     CHECK_RETURN(whd_resource_read(whd_driver, WHD_RESOURCE_WLAN_NVRAM, 0,
596                                    image_size, &size_out, (uint8_t *)nvram_destination_address) );
597 
598 
599     /* Calculate the NVRAM image size in words (multiples of 4 bytes) and its bitwise inverse */
600     nvram_size_in_words = nvram_size / 4;
601     nvram_size_in_words = (~nvram_size_in_words << 16) | (nvram_size_in_words & 0x0000FFFF);
602 
603     memcpy( (uint8_t *)(GET_C_VAR(whd_driver, ATCM_RAM_BASE_ADDRESS) + GET_C_VAR(whd_driver, CHIP_RAM_SIZE) - 4),
604             (uint8_t *)&nvram_size_in_words, 4 );
605 
606     return WHD_SUCCESS;
607 }
608 
whd_bus_m2m_set_backplane_window(whd_driver_t whd_driver,uint32_t addr,uint32_t * cur_addr)609 whd_result_t whd_bus_m2m_set_backplane_window(whd_driver_t whd_driver, uint32_t addr, uint32_t *cur_addr)
610 {
611     return WHD_UNSUPPORTED;
612 }
613 
whd_ensure_wlan_is_up(whd_driver_t whd_driver)614 whd_bool_t whd_ensure_wlan_is_up(whd_driver_t whd_driver)
615 {
616     if ( (whd_driver != NULL) && (whd_driver->internal_info.whd_wlan_status.state == WLAN_UP) )
617         return WHD_TRUE;
618     else
619         return WHD_FALSE;
620 }
621 
622 #endif /* (CYBSP_WIFI_INTERFACE_TYPE == CYBSP_M2M_INTERFACE) */
623 
624