• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "NxpUwbChip.h"
2 #include "phNxpConfig.h"
3 #include "phNxpUciHal.h"
4 #include "phNxpUciHal_ext.h"
5 #include "phNxpUciHal_utils.h"
6 #include "phUwbStatus.h"
7 #include "phUwbTypes.h"
8 #include "phNxpUwbCalib.h"
9 #include "uci_defs.h"
10 
11 #define UCI_MSG_UWB_ESE_BINDING_LEN                   11
12 #define UCI_MSG_UWB_ESE_BINDING_OFFSET_COUNT          5
13 #define UCI_MSG_UWB_ESE_BINDING_OFFSET_BINDING_STATE  6
14 
15 extern phNxpUciHal_Control_t nxpucihal_ctrl;
16 
report_binding_status(uint8_t binding_status)17 static void report_binding_status(uint8_t binding_status)
18 {
19   // BINDING_STATUS_NTF
20   uint8_t data_len = 5;
21   uint8_t buffer[5];
22   buffer[0] = 0x6E;
23   buffer[1] = 0x06;
24   buffer[2] = 0x00;
25   buffer[3] = 0x01;
26   buffer[4] = binding_status;
27   nxpucihal_ctrl.rx_data_len = 5;
28   if (nxpucihal_ctrl.p_uwb_stack_data_cback != NULL) {
29     (*nxpucihal_ctrl.p_uwb_stack_data_cback)(data_len, buffer);
30   }
31 }
32 
33 /******************************************************************************
34  * Function         otp_read_data
35  *
36  * Description      Read OTP calibration data
37  *
38  * Returns          true on success
39  *
40  ******************************************************************************/
otp_read_data(const uint8_t channel,const uint8_t param_id,uint8_t * buffer,size_t len)41 static bool otp_read_data(const uint8_t channel, const uint8_t param_id, uint8_t *buffer, size_t len)
42 {
43   phNxpUciHal_Sem_t calib_data_ntf_wait;
44   phNxpUciHal_init_cb_data(&calib_data_ntf_wait, NULL);
45 
46   // NXP_READ_CALIB_DATA_NTF
47   bool received = false;
48   auto read_calib_ntf_cb =
49   [&] (size_t packet_len, const uint8_t *packet) mutable
50   {
51     // READ_CALIB_DATA_NTF: status(1), length-of-payload(1), payload(N)
52     const uint8_t plen = packet[3]; // payload-length
53     const uint8_t *p = &packet[4];  // payload
54 
55     if (plen < 2) {
56       NXPLOG_UCIHAL_E("Otp read: bad payload length %u", plen);
57     } else if (p[0] != UCI_STATUS_OK) {
58       NXPLOG_UCIHAL_E("Otp read: bad status=0x%x", nxpucihal_ctrl.p_rx_data[4]);
59     } else if (p[1] != len) {
60       NXPLOG_UCIHAL_E("Otp read: size mismatch %u (expected %zu for param 0x%x)",
61         p[1], len, param_id);
62     } else {
63       memcpy(buffer, &p[2], len);
64       received = true;
65       SEM_POST(&calib_data_ntf_wait);
66     }
67   };
68   auto handler = phNxpUciHal_rx_handler_add(
69       UCI_MT_NTF, UCI_GID_PROPRIETARY_0X0A, UCI_MSG_READ_CALIB_DATA,
70       true, true, read_calib_ntf_cb);
71 
72 
73   // READ_CALIB_DATA_CMD
74   std::vector<uint8_t> packet{(UCI_MT_CMD << UCI_MT_SHIFT) | UCI_GID_PROPRIETARY_0X0A, UCI_MSG_READ_CALIB_DATA, 0x00, 0x03};
75   packet.push_back(channel);
76   packet.push_back(0x01);      // OTP read option
77   packet.push_back(param_id);
78 
79   tHAL_UWB_STATUS status = phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
80   if (status != UWBSTATUS_SUCCESS) {
81     goto fail_otp_read_data;
82   }
83 
84   phNxpUciHal_sem_timed_wait_sec(&calib_data_ntf_wait, 3);
85   if (!received) {
86     goto fail_otp_read_data;
87   }
88 
89   phNxpUciHal_cleanup_cb_data(&calib_data_ntf_wait);
90   return true;
91 
92 fail_otp_read_data:
93   phNxpUciHal_cleanup_cb_data(&calib_data_ntf_wait);
94   NXPLOG_UCIHAL_E("Failed to read OTP data id=%u", param_id);
95   return false;
96 }
97 
sr1xx_read_otp(extcal_param_id_t id,uint8_t * data,size_t data_len,size_t * retlen)98 static tHAL_UWB_STATUS sr1xx_read_otp(extcal_param_id_t id, uint8_t *data, size_t data_len, size_t *retlen)
99 {
100   switch(id) {
101   case EXTCAL_PARAM_CLK_ACCURACY:
102     {
103       const size_t param_len = 6;
104       uint8_t otp_xtal_data[3];
105 
106       if (data_len < param_len) {
107         NXPLOG_UCIHAL_E("Requested RF_CLK_ACCURACY_CALIB with %zu bytes (expected >= %zu)", data_len, param_len);
108         return UWBSTATUS_FAILED;
109       }
110       if (!otp_read_data(0x09, OTP_ID_XTAL_CAP_GM_CTRL, otp_xtal_data, sizeof(otp_xtal_data))) {
111         NXPLOG_UCIHAL_E("Failed to read OTP XTAL_CAP_GM_CTRL");
112         return UWBSTATUS_FAILED;
113       }
114       memset(data, 0, param_len);
115       // convert OTP_ID_XTAL_CAP_GM_CTRL to EXTCAL_PARAM_RX_ANT_DELAY
116       data[0] = otp_xtal_data[0]; // cap1
117       data[2] = otp_xtal_data[1]; // cap2
118       data[4] = otp_xtal_data[2]; // gm_current_control (default: 0x30)
119       *retlen = param_len;
120       return UWBSTATUS_SUCCESS;
121     }
122     break;
123   default:
124     NXPLOG_UCIHAL_E("Unsupported otp parameter %d", id);
125     return UWBSTATUS_FAILED;
126   }
127 }
128 
129 //
130 // SR1XX Error handlers (Thermal Runaway, LOW VBATT)
131 //
132 
sr1xx_handle_device_error()133 static void sr1xx_handle_device_error()
134 {
135  /* Send FW crash NTF to upper layer for triggering MW recovery */
136   phNxpUciHal_send_dev_error_status_ntf();
137 }
138 
sr1xx_clear_device_error()139 static void sr1xx_clear_device_error()
140 {
141 }
142 
143 //
144 // SE binding
145 //
146 
147 // Temporarily disable DPD for binding, vendor config should re-enable it
sr1xx_disable_dpd()148 static tHAL_UWB_STATUS sr1xx_disable_dpd()
149 {
150   uint8_t buffer[] = {0x20, 0x04, 0x00, 0x04, 0x01, 0x01, 0x01, 0x00};
151   return phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
152 }
153 
154 /******************************************************************************
155  * Function         sr1xx_do_bind
156  *
157  * Description      Sends UWB_ESE_BINDING_CMD and returns
158  *                  updated binding status and remaining UWBS binding count
159  *
160  * Returns          status
161  *
162  ******************************************************************************/
sr1xx_do_bind(uint8_t * binding_status,uint8_t * remain_count)163 static tHAL_UWB_STATUS sr1xx_do_bind(uint8_t *binding_status, uint8_t *remain_count)
164 {
165   tHAL_UWB_STATUS status;
166 
167   // register rx handler for UWB_ESE_BINDING_NTF
168   phNxpUciHal_Sem_t binding_ntf_wait;
169   phNxpUciHal_init_cb_data(&binding_ntf_wait, NULL);
170 
171   auto binding_ntf_cb =
172     [&](size_t packet_len, const uint8_t *packet) mutable
173   {
174       if (packet_len == UCI_MSG_UWB_ESE_BINDING_LEN) {
175         uint8_t status = packet[UCI_RESPONSE_STATUS_OFFSET];
176         if (status != UWBSTATUS_SUCCESS) {
177           NXPLOG_UCIHAL_E("UWB_ESE_BINDING_NTF: Binding failed, status=0x%x", status);
178         }
179         *binding_status = packet[UCI_MSG_UWB_ESE_BINDING_OFFSET_BINDING_STATE];
180         *remain_count = packet[UCI_MSG_UWB_ESE_BINDING_OFFSET_COUNT];
181         NXPLOG_UCIHAL_D("Received UWB_ESE_BINDING_NTF, status=0x%x, binding_state=0x%x, count=%u",
182           status, *binding_status, *remain_count);
183         SEM_POST(&binding_ntf_wait);
184       } else {
185         NXPLOG_UCIHAL_E("UWB_ESE_BINDING_NTF: packet length mismatched %zu", packet_len);
186       }
187   };
188   auto handler = phNxpUciHal_rx_handler_add(
189       UCI_MT_NTF, UCI_GID_PROPRIETARY_0X0F, UCI_MSG_UWB_ESE_BINDING,
190       true, true, binding_ntf_cb);
191 
192   // UWB_ESE_BINDING_CMD
193   uint8_t buffer[] = {0x2F, 0x31, 0x00, 0x00};
194   status = phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
195   if (status != UWBSTATUS_SUCCESS) {
196     NXPLOG_UCIHAL_E("Failed to send UWB_ESE_BINDING_CMD");
197     goto exit_do_bind;
198   }
199 
200   if (phNxpUciHal_sem_timed_wait(&binding_ntf_wait) ||
201       binding_ntf_wait.status != UWBSTATUS_SUCCESS) {
202     NXPLOG_UCIHAL_E("Failed to retrieve UWB_ESE_BINDING_NTF");
203     goto exit_do_bind;
204   }
205 
206   status = UWBSTATUS_SUCCESS;
207 
208 exit_do_bind:
209   phNxpUciHal_rx_handler_del(handler);
210   phNxpUciHal_cleanup_cb_data(&binding_ntf_wait);
211   return status;
212 }
213 
214 /******************************************************************************
215  * Function         sr1xx_check_binding_status
216  *
217  * Description      Send UWB_ESE_BINDING_CHECK_CMD and returns updated binding status
218  *
219  * Returns          status
220  *
221  ******************************************************************************/
sr1xx_check_binding_status(uint8_t * binding_status)222 static tHAL_UWB_STATUS sr1xx_check_binding_status(uint8_t *binding_status)
223 {
224   tHAL_UWB_STATUS status;
225   *binding_status = UWB_DEVICE_UNKNOWN;
226 
227   // register rx handler for UWB_ESE_BINDING_CHECK_NTF
228   uint8_t binding_status_got = UWB_DEVICE_UNKNOWN;
229   phNxpUciHal_Sem_t binding_check_ntf_wait;
230   phNxpUciHal_init_cb_data(&binding_check_ntf_wait, NULL);
231   auto binding_check_ntf_cb = [&](size_t packet_len, const uint8_t *packet) mutable {
232     if (packet_len >= UCI_RESPONSE_STATUS_OFFSET) {
233       binding_status_got = packet[UCI_RESPONSE_STATUS_OFFSET];
234       NXPLOG_UCIHAL_D("Received UWB_ESE_BINDING_CHECK_NTF, binding_status=0x%x", binding_status_got);
235       SEM_POST(&binding_check_ntf_wait);
236     }
237   };
238   auto handler = phNxpUciHal_rx_handler_add(
239       UCI_MT_NTF, UCI_GID_PROPRIETARY_0X0F, UCI_MSG_UWB_ESE_BINDING_CHECK,
240       true, true, binding_check_ntf_cb);
241 
242   // UWB_ESE_BINDING_CHECK_CMD
243   uint8_t lock_cmd[] = {0x2F, 0x32, 0x00, 0x00};
244   status = phNxpUciHal_send_ext_cmd(sizeof(lock_cmd), lock_cmd);
245   if (status != UWBSTATUS_SUCCESS) {
246     goto exit_check_binding_status;
247   }
248 
249   if (phNxpUciHal_sem_timed_wait(&binding_check_ntf_wait) ||
250       binding_check_ntf_wait.status != UWBSTATUS_SUCCESS) {
251     NXPLOG_UCIHAL_E("Failed to retrieve UWB_ESE_BINDING_CHECK_NTF");
252     goto exit_check_binding_status;
253   }
254 
255   *binding_status = binding_status_got;
256   status = UWBSTATUS_SUCCESS;
257 
258 exit_check_binding_status:
259   phNxpUciHal_rx_handler_del(handler);
260   phNxpUciHal_cleanup_cb_data(&binding_check_ntf_wait);
261   return status;
262 }
263 
264 class NxpUwbChipSr1xx final : public NxpUwbChip {
265 public:
266   NxpUwbChipSr1xx();
267   virtual ~NxpUwbChipSr1xx();
268 
269   tHAL_UWB_STATUS chip_init();
270   tHAL_UWB_STATUS core_init();
271   device_type_t get_device_type(const uint8_t *param, size_t param_len);
272   tHAL_UWB_STATUS read_otp(extcal_param_id_t id, uint8_t *data, size_t data_len, size_t *retlen);
273   tHAL_UWB_STATUS apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len);
274   int16_t extra_group_delay(void);
275 
276 private:
277   tHAL_UWB_STATUS check_binding();
278   void onDeviceStatusNtf(size_t packet_len, const uint8_t* packet);
279   void onGenericErrorNtf(size_t packet_len, const uint8_t* packet);
280   void onBindingStatusNtf(size_t packet_len, const uint8_t* packet);
281 
282 private:
283   UciHalRxHandler deviceStatusNtfHandler_;
284   UciHalRxHandler genericErrorNtfHandler_;
285   UciHalRxHandler bindingStatusNtfHandler_;
286   UciHalSemaphore bindingStatusNtfWait_;
287   uint8_t bindingStatus_;
288 };
289 
NxpUwbChipSr1xx()290 NxpUwbChipSr1xx::NxpUwbChipSr1xx() :
291   bindingStatus_(UWB_DEVICE_UNKNOWN)
292 {
293 }
294 
~NxpUwbChipSr1xx()295 NxpUwbChipSr1xx::~NxpUwbChipSr1xx()
296 {
297 }
298 
onDeviceStatusNtf(size_t packet_len,const uint8_t * packet)299 void NxpUwbChipSr1xx::onDeviceStatusNtf(size_t packet_len, const uint8_t* packet)
300 {
301   if(packet_len > UCI_RESPONSE_STATUS_OFFSET) {
302     uint8_t status = packet[UCI_RESPONSE_STATUS_OFFSET];
303     if (status == UCI_STATUS_HW_RESET) {
304       sr1xx_clear_device_error();
305     }
306   }
307 }
308 
onGenericErrorNtf(size_t packet_len,const uint8_t * packet)309 void NxpUwbChipSr1xx::onGenericErrorNtf(size_t packet_len, const uint8_t* packet)
310 {
311   if(packet_len > UCI_RESPONSE_STATUS_OFFSET) {
312     uint8_t status = packet[UCI_RESPONSE_STATUS_OFFSET];
313     if ( status == UCI_STATUS_THERMAL_RUNAWAY || status == UCI_STATUS_LOW_VBAT) {
314       nxpucihal_ctrl.isSkipPacket = 1;
315       sr1xx_handle_device_error();
316     }
317   }
318 }
319 
onBindingStatusNtf(size_t packet_len,const uint8_t * packet)320 void NxpUwbChipSr1xx::onBindingStatusNtf(size_t packet_len, const uint8_t* packet)
321 {
322   if (packet_len > UCI_RESPONSE_STATUS_OFFSET) {
323     bindingStatus_ = packet[UCI_RESPONSE_STATUS_OFFSET];
324     NXPLOG_UCIHAL_D("BINDING_STATUS_NTF: 0x%x", bindingStatus_);
325     bindingStatusNtfWait_.post(UWBSTATUS_SUCCESS);
326   }
327 }
328 
check_binding()329 tHAL_UWB_STATUS NxpUwbChipSr1xx::check_binding()
330 {
331   // Wait for Binding status notification
332   if (bindingStatusNtfWait_.getStatus() != UWBSTATUS_SUCCESS) {
333     bindingStatusNtfWait_.wait_timeout_msec(3000);
334   }
335   if (bindingStatusNtfWait_.getStatus() != UWBSTATUS_SUCCESS) {
336     NXPLOG_UCIHAL_E("Binding status notification timeout");
337 
338     // Stop HAL init when it didn't receive the binding notification.
339     // or if it's not user mode fw, just continue
340     if (nxpucihal_ctrl.fw_boot_mode == USER_FW_BOOT_MODE)
341       return UWBSTATUS_FAILED;
342     else
343       return UWBSTATUS_SUCCESS;
344   }
345 
346   uint32_t val = 0;
347   NxpConfig_GetNum(NAME_UWB_BINDING_LOCKING_ALLOWED, &val, sizeof(val));
348   bool isBindingLockingAllowed = !!val;
349   if (!isBindingLockingAllowed) {
350     return UWBSTATUS_SUCCESS;
351   }
352 
353   NXPLOG_UCIHAL_E("Current binding status: 0x%x", bindingStatus_);
354 
355   switch (bindingStatus_) {
356     case UWB_DEVICE_UNKNOWN:
357       // Treat 'UNKNOWN' state as 'NOT_BOUND'
358       NXPLOG_UCIHAL_E("Unknown binding status, proceed binding.");
359       [[fallthrough]];
360     case UWB_DEVICE_NOT_BOUND:
361     {
362       sr1xx_disable_dpd();
363 
364       // perform bind
365       uint8_t remaining_count = 0;
366       tHAL_UWB_STATUS status = sr1xx_do_bind(&bindingStatus_, &remaining_count);
367       if (status != UWBSTATUS_SUCCESS) {
368         return status;
369       }
370 
371       // perform lock
372       if (bindingStatus_ == UWB_DEVICE_BOUND_UNLOCKED && remaining_count < 3) {
373         status = sr1xx_check_binding_status(&bindingStatus_);
374         if (status != UWBSTATUS_SUCCESS) {
375           return status;
376         }
377       }
378     }
379     break;
380   case UWB_DEVICE_BOUND_UNLOCKED:
381     {
382       sr1xx_disable_dpd();
383 
384       // perform lock
385       tHAL_UWB_STATUS status = sr1xx_check_binding_status(&bindingStatus_);
386       if (status != UWBSTATUS_SUCCESS) {
387         // Sending originial binding status notification to upper layer
388         // XXX: Why?
389         report_binding_status(bindingStatus_);
390       }
391     }
392     break;
393 
394   case UWB_DEVICE_BOUND_LOCKED:
395     // do nothing
396     break;
397 
398   default:
399     NXPLOG_UCIHAL_E("Unknown binding status: 0x%x", bindingStatus_);
400     return UWBSTATUS_FAILED;
401   }
402 
403   return UWBSTATUS_SUCCESS;
404 }
405 
406 extern int phNxpUciHal_fw_download();
407 
chip_init()408 tHAL_UWB_STATUS NxpUwbChipSr1xx::chip_init()
409 {
410   tHAL_UWB_STATUS status;
411 
412   // system in FW download mode
413   // This will be cleared on first Device Status NTF
414   nxpucihal_ctrl.fw_dwnld_mode = true;
415 
416   NXPLOG_UCIHAL_D("Start SR1XX FW download");
417 
418   for (int i = 0; i < 5; i++) {
419     phTmlUwb_Chip_Reset();
420 
421     status = phNxpUciHal_fw_download();
422 
423     if (status == UWBSTATUS_SUCCESS) {
424       NXPLOG_UCIHAL_D("Complete SR1XX FW download");
425       break;
426     } else if(status == UWBSTATUS_FILE_NOT_FOUND) {
427       NXPLOG_UCIHAL_E("FW file Not found.");
428       break;
429     } else {
430       NXPLOG_UCIHAL_E("FW download failed, status= 0x%x, retry.", status);
431     }
432   }
433 
434   // register device status ntf handler
435   deviceStatusNtfHandler_ = UciHalRxHandler(
436       UCI_MT_NTF, UCI_GID_CORE, UCI_MSG_CORE_DEVICE_STATUS_NTF, false,
437       std::bind(&NxpUwbChipSr1xx::onDeviceStatusNtf, this, std::placeholders::_1, std::placeholders::_2)
438   );
439 
440   // register device error ntf handler
441   genericErrorNtfHandler_ = UciHalRxHandler(
442     UCI_MT_NTF, UCI_GID_CORE, UCI_MSG_CORE_GENERIC_ERROR_NTF, false,
443     std::bind(&NxpUwbChipSr1xx::onGenericErrorNtf, this, std::placeholders::_1, std::placeholders::_2)
444   );
445 
446   // register binding status ntf handler
447   bindingStatusNtfHandler_ = UciHalRxHandler(
448       UCI_MT_NTF, UCI_GID_PROPRIETARY, UCI_MSG_BINDING_STATUS_NTF, true,
449       std::bind(&NxpUwbChipSr1xx::onBindingStatusNtf, this, std::placeholders::_1, std::placeholders::_2)
450   );
451 
452   return status;
453 }
454 
core_init()455 tHAL_UWB_STATUS NxpUwbChipSr1xx::core_init()
456 {
457   return check_binding();
458 }
459 
get_device_type(const uint8_t * param,size_t param_len)460 device_type_t NxpUwbChipSr1xx::get_device_type(const uint8_t *param, size_t param_len)
461 {
462   // 'SR100S' or 'SR1..T'
463   if (param_len >= 6) {
464     const uint8_t marker = param[5];
465     if (marker == 'S')
466       return DEVICE_TYPE_SR1xxS;
467     else if (marker == 'T')
468       return DEVICE_TYPE_SR1xxT;
469   }
470   return DEVICE_TYPE_UNKNOWN;
471 }
472 
read_otp(extcal_param_id_t id,uint8_t * data,size_t data_len,size_t * retlen)473 tHAL_UWB_STATUS NxpUwbChipSr1xx::read_otp(extcal_param_id_t id, uint8_t *data, size_t data_len, size_t *retlen)
474 {
475   return sr1xx_read_otp(id, data, data_len, retlen);
476 }
477 
apply_calibration(extcal_param_id_t id,const uint8_t ch,const uint8_t * data,size_t data_len)478 tHAL_UWB_STATUS NxpUwbChipSr1xx::apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len)
479 {
480   return phNxpUwbCalib_apply_calibration(id, ch, data, data_len);
481 }
482 
extra_group_delay(void)483 int16_t NxpUwbChipSr1xx::extra_group_delay(void) {
484   bool need_7cm_offset = FALSE;
485   // + Compensation for D48/D49 calibration
486   // If calibration was done with D48 / D49
487   char calibrated_with_fw[15] = {0};
488 
489   int has_calibrated_with_fw_config = NxpConfig_GetStr(
490     "cal.fw_version", calibrated_with_fw, sizeof(calibrated_with_fw) - 1);
491 
492   if ( has_calibrated_with_fw_config ) {
493     // Conf file has entry of `cal.fw_version`
494     if (
495       ( 0 == memcmp("48.", calibrated_with_fw, 3)) ||
496       ( 0 == memcmp("49.", calibrated_with_fw, 3))) {
497       // Calibrated with D48 / D49.
498       if (nxpucihal_ctrl.fw_version.major_version == 0xFF) {
499         // Current FW seems to be Test FW
500         NXPLOG_UCIHAL_W("For Test FW, D49 -> D50+ 7cm Compensation is applied");
501         need_7cm_offset = TRUE;
502       }
503       else if (nxpucihal_ctrl.fw_version.major_version >= 0x50) {
504         // D50 and later fix is needed.
505         need_7cm_offset = TRUE;
506       }
507     }
508     else
509     {
510       // Not calibrated with D48/D49
511     }
512   }
513   else
514   {
515     // Missing Entry cal.fw_version
516     NXPLOG_UCIHAL_W("Could not get cal.fw_version. Assuming D48 used for calibration.");
517     need_7cm_offset = TRUE;
518   }
519   if (need_7cm_offset) {
520     /* Its Q14.2 format, hence << 2 */
521     return (7 << 2);
522   }
523   else
524   {
525     return 0;
526   }
527 }
528 
GetUwbChip()529 std::unique_ptr<NxpUwbChip> GetUwbChip()
530 {
531   return std::make_unique<NxpUwbChipSr1xx>();
532 }
533