xref: /aosp_15_r20/external/libese/libese-hw/nxp/pn80t/common.c (revision 5c4dab75aa57366379dce576b1a9e082a44e2b3a)
1*5c4dab75SAndroid Build Coastguard Worker /*
2*5c4dab75SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*5c4dab75SAndroid Build Coastguard Worker  *
4*5c4dab75SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*5c4dab75SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*5c4dab75SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*5c4dab75SAndroid Build Coastguard Worker  *
8*5c4dab75SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*5c4dab75SAndroid Build Coastguard Worker  *
10*5c4dab75SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*5c4dab75SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*5c4dab75SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5c4dab75SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*5c4dab75SAndroid Build Coastguard Worker  * limitations under the License.
15*5c4dab75SAndroid Build Coastguard Worker  *
16*5c4dab75SAndroid Build Coastguard Worker  * Support SPI communication with NXP PN553/PN80T secure element.
17*5c4dab75SAndroid Build Coastguard Worker  */
18*5c4dab75SAndroid Build Coastguard Worker 
19*5c4dab75SAndroid Build Coastguard Worker #include "include/ese/hw/nxp/pn80t/common.h"
20*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_preprocess(const struct Teq1ProtocolOptions * const opts,struct Teq1Frame * frame,int tx)21*5c4dab75SAndroid Build Coastguard Worker int nxp_pn80t_preprocess(const struct Teq1ProtocolOptions *const opts,
22*5c4dab75SAndroid Build Coastguard Worker                          struct Teq1Frame *frame, int tx) {
23*5c4dab75SAndroid Build Coastguard Worker   if (tx) {
24*5c4dab75SAndroid Build Coastguard Worker     /* Recompute the LRC with the NAD of 0x00 */
25*5c4dab75SAndroid Build Coastguard Worker     frame->header.NAD = 0x00;
26*5c4dab75SAndroid Build Coastguard Worker     frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
27*5c4dab75SAndroid Build Coastguard Worker     frame->header.NAD = opts->node_address;
28*5c4dab75SAndroid Build Coastguard Worker     ALOGV("interface is preprocessing outbound frame");
29*5c4dab75SAndroid Build Coastguard Worker   } else {
30*5c4dab75SAndroid Build Coastguard Worker     /* Replace the NAD with 0x00 so the LRC check passes. */
31*5c4dab75SAndroid Build Coastguard Worker     ALOGV("interface is preprocessing inbound frame (%x->%x)",
32*5c4dab75SAndroid Build Coastguard Worker           frame->header.NAD, 0x00);
33*5c4dab75SAndroid Build Coastguard Worker     if (frame->header.NAD != opts->host_address) {
34*5c4dab75SAndroid Build Coastguard Worker       ALOGV("Rewriting from unknown NAD: %x", frame->header.NAD);
35*5c4dab75SAndroid Build Coastguard Worker     }
36*5c4dab75SAndroid Build Coastguard Worker     frame->header.NAD = 0x00;
37*5c4dab75SAndroid Build Coastguard Worker     ALOGV("Frame length: %x", frame->header.LEN);
38*5c4dab75SAndroid Build Coastguard Worker   }
39*5c4dab75SAndroid Build Coastguard Worker   return 0;
40*5c4dab75SAndroid Build Coastguard Worker }
41*5c4dab75SAndroid Build Coastguard Worker 
42*5c4dab75SAndroid Build Coastguard Worker static const struct Teq1ProtocolOptions kTeq1Options = {
43*5c4dab75SAndroid Build Coastguard Worker     .host_address = 0xA5,
44*5c4dab75SAndroid Build Coastguard Worker     .node_address = 0x5A,
45*5c4dab75SAndroid Build Coastguard Worker     .bwt = 1.624f, /* cwt by default would be ~8k * 1.05s */
46*5c4dab75SAndroid Build Coastguard Worker     /* 1.05ms is the vendor defined ETU.  However, we use this
47*5c4dab75SAndroid Build Coastguard Worker      * for polling and 7 * etu (7ms) is a long time to wait
48*5c4dab75SAndroid Build Coastguard Worker      * between poll attempts so we divided by 7. */
49*5c4dab75SAndroid Build Coastguard Worker     .etu = 0.00015f, /* elementary time unit, in seconds */
50*5c4dab75SAndroid Build Coastguard Worker     .preprocess = &nxp_pn80t_preprocess,
51*5c4dab75SAndroid Build Coastguard Worker };
52*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_open(struct EseInterface * ese,void * board)53*5c4dab75SAndroid Build Coastguard Worker int nxp_pn80t_open(struct EseInterface *ese, void *board) {
54*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns;
55*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform;
56*5c4dab75SAndroid Build Coastguard Worker   _static_assert(sizeof(ese->pad) >= sizeof(struct NxpState *),
57*5c4dab75SAndroid Build Coastguard Worker                  "Pad size too small to use NXP HW");
58*5c4dab75SAndroid Build Coastguard Worker   platform = ese->ops->opts;
59*5c4dab75SAndroid Build Coastguard Worker 
60*5c4dab75SAndroid Build Coastguard Worker   /* Ensure all required functions exist */
61*5c4dab75SAndroid Build Coastguard Worker   if (!platform->initialize || !platform->release || !platform->toggle_reset ||
62*5c4dab75SAndroid Build Coastguard Worker       !platform->wait) {
63*5c4dab75SAndroid Build Coastguard Worker     ALOGE("Required functions not implemented in supplied platform");
64*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, kNxpPn80tErrorPlatformInit);
65*5c4dab75SAndroid Build Coastguard Worker     return -1;
66*5c4dab75SAndroid Build Coastguard Worker   }
67*5c4dab75SAndroid Build Coastguard Worker 
68*5c4dab75SAndroid Build Coastguard Worker   ns = NXP_PN80T_STATE(ese);
69*5c4dab75SAndroid Build Coastguard Worker   TEQ1_INIT_CARD_STATE((struct Teq1CardState *)(&ese->pad[0]));
70*5c4dab75SAndroid Build Coastguard Worker   ns->handle = platform->initialize(board);
71*5c4dab75SAndroid Build Coastguard Worker   if (!ns->handle) {
72*5c4dab75SAndroid Build Coastguard Worker     ALOGE("platform initialization failed");
73*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, kNxpPn80tErrorPlatformInit);
74*5c4dab75SAndroid Build Coastguard Worker     return -1;
75*5c4dab75SAndroid Build Coastguard Worker   }
76*5c4dab75SAndroid Build Coastguard Worker   /* Toggle all required power GPIOs.
77*5c4dab75SAndroid Build Coastguard Worker    * Each platform may prefer to handle the power
78*5c4dab75SAndroid Build Coastguard Worker    * muxing specific. E.g., if NFC is in use, it would
79*5c4dab75SAndroid Build Coastguard Worker    * be unwise to unset VEN.  However, the implementation
80*5c4dab75SAndroid Build Coastguard Worker    * here will attempt it if supported.
81*5c4dab75SAndroid Build Coastguard Worker    */
82*5c4dab75SAndroid Build Coastguard Worker   if (platform->toggle_ven) {
83*5c4dab75SAndroid Build Coastguard Worker     platform->toggle_ven(ns->handle, 1);
84*5c4dab75SAndroid Build Coastguard Worker   }
85*5c4dab75SAndroid Build Coastguard Worker   if (platform->toggle_power_req) {
86*5c4dab75SAndroid Build Coastguard Worker     platform->toggle_power_req(ns->handle, 1);
87*5c4dab75SAndroid Build Coastguard Worker   }
88*5c4dab75SAndroid Build Coastguard Worker   /* Power on eSE */
89*5c4dab75SAndroid Build Coastguard Worker   platform->toggle_reset(ns->handle, 1);
90*5c4dab75SAndroid Build Coastguard Worker   return 0;
91*5c4dab75SAndroid Build Coastguard Worker }
92*5c4dab75SAndroid Build Coastguard Worker 
93*5c4dab75SAndroid Build Coastguard Worker /* Used for soft-reset when possible. */
94*5c4dab75SAndroid Build Coastguard Worker uint32_t nxp_pn80t_send_cooldown(struct EseInterface *ese, bool end);
95*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_reset(struct EseInterface * ese)96*5c4dab75SAndroid Build Coastguard Worker int nxp_pn80t_reset(struct EseInterface *ese) {
97*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
98*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
99*5c4dab75SAndroid Build Coastguard Worker 
100*5c4dab75SAndroid Build Coastguard Worker   /* If there is no error, perform a soft reset.
101*5c4dab75SAndroid Build Coastguard Worker    * If there is no cooldown time associated, go ahead and do a real
102*5c4dab75SAndroid Build Coastguard Worker    * reset as there is no other interface to trigger a hard reset.
103*5c4dab75SAndroid Build Coastguard Worker    *
104*5c4dab75SAndroid Build Coastguard Worker    * This avoids pulling the power when a cooldown is in progress
105*5c4dab75SAndroid Build Coastguard Worker    * if it is at all possible to avoid.
106*5c4dab75SAndroid Build Coastguard Worker    */
107*5c4dab75SAndroid Build Coastguard Worker   if (!ese_error(ese)) {
108*5c4dab75SAndroid Build Coastguard Worker     const uint32_t cooldownSec = nxp_pn80t_send_cooldown(ese, false);
109*5c4dab75SAndroid Build Coastguard Worker     if (!ese_error(ese) && cooldownSec > 0) {
110*5c4dab75SAndroid Build Coastguard Worker       return 0;
111*5c4dab75SAndroid Build Coastguard Worker     }
112*5c4dab75SAndroid Build Coastguard Worker   }
113*5c4dab75SAndroid Build Coastguard Worker 
114*5c4dab75SAndroid Build Coastguard Worker   if (platform->toggle_reset(ns->handle, 0) < 0) {
115*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, kNxpPn80tErrorResetToggle);
116*5c4dab75SAndroid Build Coastguard Worker     return -1;
117*5c4dab75SAndroid Build Coastguard Worker   }
118*5c4dab75SAndroid Build Coastguard Worker   if (platform->toggle_reset(ns->handle, 1) < 0) {
119*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, kNxpPn80tErrorResetToggle);
120*5c4dab75SAndroid Build Coastguard Worker     return -1;
121*5c4dab75SAndroid Build Coastguard Worker   }
122*5c4dab75SAndroid Build Coastguard Worker 
123*5c4dab75SAndroid Build Coastguard Worker   /* Start fresh with the reset. */
124*5c4dab75SAndroid Build Coastguard Worker   ese->error.is_err = false;
125*5c4dab75SAndroid Build Coastguard Worker   return 0;
126*5c4dab75SAndroid Build Coastguard Worker }
127*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_poll(struct EseInterface * ese,uint8_t poll_for,float timeout,int complete)128*5c4dab75SAndroid Build Coastguard Worker int nxp_pn80t_poll(struct EseInterface *ese, uint8_t poll_for, float timeout,
129*5c4dab75SAndroid Build Coastguard Worker                    int complete) {
130*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
131*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
132*5c4dab75SAndroid Build Coastguard Worker   /* Attempt to read a 8-bit character once per 8-bit character transmission
133*5c4dab75SAndroid Build Coastguard Worker    * window (in seconds).
134*5c4dab75SAndroid Build Coastguard Worker    */
135*5c4dab75SAndroid Build Coastguard Worker   int intervals = (int)(0.5f + timeout / (7.0f * kTeq1Options.etu));
136*5c4dab75SAndroid Build Coastguard Worker   uint8_t byte = 0xff;
137*5c4dab75SAndroid Build Coastguard Worker   ALOGV("interface polling for start of frame/host node address: %x", poll_for);
138*5c4dab75SAndroid Build Coastguard Worker   /* If we had interrupts, we could just get notified by the driver. */
139*5c4dab75SAndroid Build Coastguard Worker   do {
140*5c4dab75SAndroid Build Coastguard Worker     /*
141*5c4dab75SAndroid Build Coastguard Worker      * In practice, if complete=true, then no transmission
142*5c4dab75SAndroid Build Coastguard Worker      * should attempt again until after 1000usec.
143*5c4dab75SAndroid Build Coastguard Worker      */
144*5c4dab75SAndroid Build Coastguard Worker     if (ese->ops->hw_receive(ese, &byte, 1, complete) != 1) {
145*5c4dab75SAndroid Build Coastguard Worker       ALOGE("failed to read one byte");
146*5c4dab75SAndroid Build Coastguard Worker       ese_set_error(ese, kNxpPn80tErrorPollRead);
147*5c4dab75SAndroid Build Coastguard Worker       return -1;
148*5c4dab75SAndroid Build Coastguard Worker     }
149*5c4dab75SAndroid Build Coastguard Worker     if (byte == poll_for) {
150*5c4dab75SAndroid Build Coastguard Worker       ALOGV("Polled for byte seen: %x with %d intervals remaining.", poll_for,
151*5c4dab75SAndroid Build Coastguard Worker             intervals);
152*5c4dab75SAndroid Build Coastguard Worker       ALOGV("RX[0]: %.2X", byte);
153*5c4dab75SAndroid Build Coastguard Worker       return 1;
154*5c4dab75SAndroid Build Coastguard Worker     } else {
155*5c4dab75SAndroid Build Coastguard Worker       ALOGV("No match (saw %x)", byte);
156*5c4dab75SAndroid Build Coastguard Worker     }
157*5c4dab75SAndroid Build Coastguard Worker     platform->wait(ns->handle,
158*5c4dab75SAndroid Build Coastguard Worker                    7.0f * kTeq1Options.etu * 1000000.0f); /* s -> us */
159*5c4dab75SAndroid Build Coastguard Worker     ALOGV("poll interval %d: no match.", intervals);
160*5c4dab75SAndroid Build Coastguard Worker   } while (intervals-- > 0);
161*5c4dab75SAndroid Build Coastguard Worker   ALOGW("polling timed out.");
162*5c4dab75SAndroid Build Coastguard Worker   return -1;
163*5c4dab75SAndroid Build Coastguard Worker }
164*5c4dab75SAndroid Build Coastguard Worker 
165*5c4dab75SAndroid Build Coastguard Worker /* Returns the seconds the chip has requested to stay powered for internal
166*5c4dab75SAndroid Build Coastguard Worker  * maintenance. This is not expected during normal operation, but it is still
167*5c4dab75SAndroid Build Coastguard Worker  * a possible operating response.
168*5c4dab75SAndroid Build Coastguard Worker  *
169*5c4dab75SAndroid Build Coastguard Worker  * There are three timers reserved for internal state usage which are
170*5c4dab75SAndroid Build Coastguard Worker  * not reliable API. As such, this function returns the maximum time
171*5c4dab75SAndroid Build Coastguard Worker  * in seconds that the chip would like to stay powered-on.
172*5c4dab75SAndroid Build Coastguard Worker  */
173*5c4dab75SAndroid Build Coastguard Worker #define SECURE_TIMER 0xF1
174*5c4dab75SAndroid Build Coastguard Worker #define ATTACK_COUNTER 0xF2
175*5c4dab75SAndroid Build Coastguard Worker #define RESTRICTED_MODE_PENALTY 0xF3
nxp_pn80t_send_cooldown(struct EseInterface * ese,bool end)176*5c4dab75SAndroid Build Coastguard Worker uint32_t nxp_pn80t_send_cooldown(struct EseInterface *ese, bool end) {
177*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
178*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
179*5c4dab75SAndroid Build Coastguard Worker   const static uint8_t kEndofApduSession[] = {0x5a, 0xc5, 0x00, 0xc5};
180*5c4dab75SAndroid Build Coastguard Worker   const static uint8_t kResetSession[] = {0x5a, 0xc4, 0x00, 0xc4};
181*5c4dab75SAndroid Build Coastguard Worker   const uint8_t *const message = end ? kEndofApduSession : kResetSession;
182*5c4dab75SAndroid Build Coastguard Worker   const uint32_t message_len =
183*5c4dab75SAndroid Build Coastguard Worker       end ? sizeof(kEndofApduSession) : sizeof(kResetSession);
184*5c4dab75SAndroid Build Coastguard Worker 
185*5c4dab75SAndroid Build Coastguard Worker   if (ese_error(ese)) {
186*5c4dab75SAndroid Build Coastguard Worker     return 0;
187*5c4dab75SAndroid Build Coastguard Worker   }
188*5c4dab75SAndroid Build Coastguard Worker 
189*5c4dab75SAndroid Build Coastguard Worker   ese->ops->hw_transmit(ese, message, message_len, 1);
190*5c4dab75SAndroid Build Coastguard Worker   if (ese_error(ese)) {
191*5c4dab75SAndroid Build Coastguard Worker     ALOGE("failed to transmit cooldown check");
192*5c4dab75SAndroid Build Coastguard Worker     return 0;
193*5c4dab75SAndroid Build Coastguard Worker   }
194*5c4dab75SAndroid Build Coastguard Worker 
195*5c4dab75SAndroid Build Coastguard Worker   nxp_pn80t_poll(ese, kTeq1Options.host_address, 5.0f, 0);
196*5c4dab75SAndroid Build Coastguard Worker   if (ese_error(ese)) {
197*5c4dab75SAndroid Build Coastguard Worker     ALOGE("failed to poll during cooldown");
198*5c4dab75SAndroid Build Coastguard Worker     return 0;
199*5c4dab75SAndroid Build Coastguard Worker   }
200*5c4dab75SAndroid Build Coastguard Worker   uint8_t rx_buf[32];
201*5c4dab75SAndroid Build Coastguard Worker   const uint32_t bytes_read =
202*5c4dab75SAndroid Build Coastguard Worker       ese->ops->hw_receive(ese, rx_buf, sizeof(rx_buf), 1);
203*5c4dab75SAndroid Build Coastguard Worker   if (ese_error(ese)) {
204*5c4dab75SAndroid Build Coastguard Worker     ALOGE("failed to receive cooldown response");
205*5c4dab75SAndroid Build Coastguard Worker     return 0;
206*5c4dab75SAndroid Build Coastguard Worker   }
207*5c4dab75SAndroid Build Coastguard Worker 
208*5c4dab75SAndroid Build Coastguard Worker   ALOGI("Requested power-down delay times (sec):");
209*5c4dab75SAndroid Build Coastguard Worker   /* For each tag type, walk the response to extract the value. */
210*5c4dab75SAndroid Build Coastguard Worker   uint32_t max_wait = 0;
211*5c4dab75SAndroid Build Coastguard Worker   if (bytes_read >= 0x8 && rx_buf[0] == 0xe5 && rx_buf[1] == 0x12) {
212*5c4dab75SAndroid Build Coastguard Worker     uint8_t *tag_ptr = &rx_buf[2];
213*5c4dab75SAndroid Build Coastguard Worker     while (tag_ptr < (rx_buf + bytes_read)) {
214*5c4dab75SAndroid Build Coastguard Worker       const uint8_t tag = *tag_ptr;
215*5c4dab75SAndroid Build Coastguard Worker       const uint8_t length = *(tag_ptr + 1);
216*5c4dab75SAndroid Build Coastguard Worker 
217*5c4dab75SAndroid Build Coastguard Worker       /* The cooldown timers are 32-bit values. */
218*5c4dab75SAndroid Build Coastguard Worker       if (length == sizeof(uint32_t)) {
219*5c4dab75SAndroid Build Coastguard Worker         const uint32_t *const value_ptr = (uint32_t *)(tag_ptr + 2);
220*5c4dab75SAndroid Build Coastguard Worker         uint32_t cooldown = ese_be32toh(*value_ptr);
221*5c4dab75SAndroid Build Coastguard Worker         switch (tag) {
222*5c4dab75SAndroid Build Coastguard Worker         case RESTRICTED_MODE_PENALTY:
223*5c4dab75SAndroid Build Coastguard Worker           /* This timer is in minutes, so convert it to seconds. */
224*5c4dab75SAndroid Build Coastguard Worker           cooldown *= 60;
225*5c4dab75SAndroid Build Coastguard Worker         /* Fallthrough */
226*5c4dab75SAndroid Build Coastguard Worker         case SECURE_TIMER:
227*5c4dab75SAndroid Build Coastguard Worker         case ATTACK_COUNTER:
228*5c4dab75SAndroid Build Coastguard Worker           ALOGI("- Timer 0x%.2X: %d", tag, cooldown);
229*5c4dab75SAndroid Build Coastguard Worker           if (cooldown > max_wait) {
230*5c4dab75SAndroid Build Coastguard Worker             max_wait = cooldown;
231*5c4dab75SAndroid Build Coastguard Worker             /* Wait 25ms Guard time to make sure eSE is in DPD mode */
232*5c4dab75SAndroid Build Coastguard Worker             platform->wait(ns->handle, 25000);
233*5c4dab75SAndroid Build Coastguard Worker           }
234*5c4dab75SAndroid Build Coastguard Worker           break;
235*5c4dab75SAndroid Build Coastguard Worker         default:
236*5c4dab75SAndroid Build Coastguard Worker           /* Ignore -- not a known tag. */
237*5c4dab75SAndroid Build Coastguard Worker           break;
238*5c4dab75SAndroid Build Coastguard Worker         }
239*5c4dab75SAndroid Build Coastguard Worker       }
240*5c4dab75SAndroid Build Coastguard Worker       tag_ptr += 2 + length;
241*5c4dab75SAndroid Build Coastguard Worker     }
242*5c4dab75SAndroid Build Coastguard Worker   }
243*5c4dab75SAndroid Build Coastguard Worker   return max_wait;
244*5c4dab75SAndroid Build Coastguard Worker }
245*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_handle_interface_call(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)246*5c4dab75SAndroid Build Coastguard Worker uint32_t nxp_pn80t_handle_interface_call(struct EseInterface *ese,
247*5c4dab75SAndroid Build Coastguard Worker                                          const struct EseSgBuffer *tx_buf,
248*5c4dab75SAndroid Build Coastguard Worker                                          uint32_t tx_len,
249*5c4dab75SAndroid Build Coastguard Worker                                          struct EseSgBuffer *rx_buf,
250*5c4dab75SAndroid Build Coastguard Worker                                          uint32_t rx_len) {
251*5c4dab75SAndroid Build Coastguard Worker   /* Catch proprietary, host-targeted calls FF XX 00 00 */
252*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
253*5c4dab75SAndroid Build Coastguard Worker   static const uint32_t kCommandLength = 4;
254*5c4dab75SAndroid Build Coastguard Worker   static const uint8_t kResetCommand = 0x01;
255*5c4dab75SAndroid Build Coastguard Worker   static const uint8_t kGpioToggleCommand = 0xe0;
256*5c4dab75SAndroid Build Coastguard Worker   static const uint8_t kCooldownCommand = 0xe1;
257*5c4dab75SAndroid Build Coastguard Worker   uint8_t buf[kCommandLength + 1];
258*5c4dab75SAndroid Build Coastguard Worker   uint8_t ok[2] = {0x90, 0x00};
259*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
260*5c4dab75SAndroid Build Coastguard Worker   /* Over-copy by one to make sure the command length matches. */
261*5c4dab75SAndroid Build Coastguard Worker   if (ese_sg_to_buf(tx_buf, tx_len, 0, sizeof(buf), buf) != kCommandLength) {
262*5c4dab75SAndroid Build Coastguard Worker     return 0;
263*5c4dab75SAndroid Build Coastguard Worker   }
264*5c4dab75SAndroid Build Coastguard Worker   /* Let 3 change as an argument. */
265*5c4dab75SAndroid Build Coastguard Worker   if (buf[0] != 0xff || buf[2] != 0x00) {
266*5c4dab75SAndroid Build Coastguard Worker     return 0;
267*5c4dab75SAndroid Build Coastguard Worker   }
268*5c4dab75SAndroid Build Coastguard Worker   switch (buf[1]) {
269*5c4dab75SAndroid Build Coastguard Worker   case kResetCommand:
270*5c4dab75SAndroid Build Coastguard Worker     ALOGI("interface command received: reset");
271*5c4dab75SAndroid Build Coastguard Worker     /* Force a hard reset by setting an error on the hw. */
272*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, 0);
273*5c4dab75SAndroid Build Coastguard Worker     if (nxp_pn80t_reset(ese) < 0) {
274*5c4dab75SAndroid Build Coastguard Worker       /* Warning, state unchanged error. */
275*5c4dab75SAndroid Build Coastguard Worker       ok[0] = 0x62;
276*5c4dab75SAndroid Build Coastguard Worker     }
277*5c4dab75SAndroid Build Coastguard Worker     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
278*5c4dab75SAndroid Build Coastguard Worker   case kGpioToggleCommand:
279*5c4dab75SAndroid Build Coastguard Worker     ALOGI("interface command received: gpio toggle");
280*5c4dab75SAndroid Build Coastguard Worker     if (platform->toggle_bootloader) {
281*5c4dab75SAndroid Build Coastguard Worker       int ret = platform->toggle_bootloader(ns->handle, buf[3]);
282*5c4dab75SAndroid Build Coastguard Worker       if (ret) {
283*5c4dab75SAndroid Build Coastguard Worker         /* Grab the bottom two bytes. */
284*5c4dab75SAndroid Build Coastguard Worker         ok[0] = (ret >> 8) & 0xff;
285*5c4dab75SAndroid Build Coastguard Worker         ok[1] = ret & 0xff;
286*5c4dab75SAndroid Build Coastguard Worker       }
287*5c4dab75SAndroid Build Coastguard Worker     } else {
288*5c4dab75SAndroid Build Coastguard Worker       /* Not found. */
289*5c4dab75SAndroid Build Coastguard Worker       ok[0] = 0x6a;
290*5c4dab75SAndroid Build Coastguard Worker       ok[1] = 0x82;
291*5c4dab75SAndroid Build Coastguard Worker     }
292*5c4dab75SAndroid Build Coastguard Worker     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
293*5c4dab75SAndroid Build Coastguard Worker   case kCooldownCommand:
294*5c4dab75SAndroid Build Coastguard Worker     ALOGI("interface command received: cooldown");
295*5c4dab75SAndroid Build Coastguard Worker     uint8_t reply[6] = {0, 0, 0, 0, 0x90, 0x00};
296*5c4dab75SAndroid Build Coastguard Worker     const uint32_t cooldownSec = nxp_pn80t_send_cooldown(ese, false);
297*5c4dab75SAndroid Build Coastguard Worker     *(uint32_t *)(&reply[0]) = ese_htole32(cooldownSec);
298*5c4dab75SAndroid Build Coastguard Worker     if (ese_error(ese)) {
299*5c4dab75SAndroid Build Coastguard Worker       /* Return SW_UKNOWN on an ese failure. */
300*5c4dab75SAndroid Build Coastguard Worker       reply[sizeof(reply) - 2] = 0x6f;
301*5c4dab75SAndroid Build Coastguard Worker     }
302*5c4dab75SAndroid Build Coastguard Worker     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(reply), reply);
303*5c4dab75SAndroid Build Coastguard Worker   }
304*5c4dab75SAndroid Build Coastguard Worker   return 0;
305*5c4dab75SAndroid Build Coastguard Worker }
306*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_transceive(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)307*5c4dab75SAndroid Build Coastguard Worker uint32_t nxp_pn80t_transceive(struct EseInterface *ese,
308*5c4dab75SAndroid Build Coastguard Worker                               const struct EseSgBuffer *tx_buf, uint32_t tx_len,
309*5c4dab75SAndroid Build Coastguard Worker                               struct EseSgBuffer *rx_buf, uint32_t rx_len) {
310*5c4dab75SAndroid Build Coastguard Worker 
311*5c4dab75SAndroid Build Coastguard Worker   const uint32_t recvd =
312*5c4dab75SAndroid Build Coastguard Worker       nxp_pn80t_handle_interface_call(ese, tx_buf, tx_len, rx_buf, rx_len);
313*5c4dab75SAndroid Build Coastguard Worker   if (recvd > 0) {
314*5c4dab75SAndroid Build Coastguard Worker     return recvd;
315*5c4dab75SAndroid Build Coastguard Worker   }
316*5c4dab75SAndroid Build Coastguard Worker   return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
317*5c4dab75SAndroid Build Coastguard Worker }
318*5c4dab75SAndroid Build Coastguard Worker 
nxp_pn80t_close(struct EseInterface * ese)319*5c4dab75SAndroid Build Coastguard Worker void nxp_pn80t_close(struct EseInterface *ese) {
320*5c4dab75SAndroid Build Coastguard Worker   ALOGV("%s: called", __func__);
321*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
322*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
323*5c4dab75SAndroid Build Coastguard Worker   const uint32_t wait_sec = nxp_pn80t_send_cooldown(ese, true);
324*5c4dab75SAndroid Build Coastguard Worker 
325*5c4dab75SAndroid Build Coastguard Worker   /* After the cooldown, the device should go to sleep.
326*5c4dab75SAndroid Build Coastguard Worker    * If not post-use time is required, power down to ensure
327*5c4dab75SAndroid Build Coastguard Worker    * that the device is powered down when the OS is not on.
328*5c4dab75SAndroid Build Coastguard Worker    */
329*5c4dab75SAndroid Build Coastguard Worker   if (ese_error(ese) || wait_sec == 0) {
330*5c4dab75SAndroid Build Coastguard Worker     platform->toggle_reset(ns->handle, 0);
331*5c4dab75SAndroid Build Coastguard Worker     if (platform->toggle_power_req) {
332*5c4dab75SAndroid Build Coastguard Worker       platform->toggle_power_req(ns->handle, 0);
333*5c4dab75SAndroid Build Coastguard Worker     }
334*5c4dab75SAndroid Build Coastguard Worker     if (platform->toggle_ven) {
335*5c4dab75SAndroid Build Coastguard Worker       platform->toggle_ven(ns->handle, 0);
336*5c4dab75SAndroid Build Coastguard Worker     }
337*5c4dab75SAndroid Build Coastguard Worker   }
338*5c4dab75SAndroid Build Coastguard Worker 
339*5c4dab75SAndroid Build Coastguard Worker   platform->release(ns->handle);
340*5c4dab75SAndroid Build Coastguard Worker   ns->handle = NULL;
341*5c4dab75SAndroid Build Coastguard Worker }
342*5c4dab75SAndroid Build Coastguard Worker 
343*5c4dab75SAndroid Build Coastguard Worker const char *kNxpPn80tErrorMessages[] = {
344*5c4dab75SAndroid Build Coastguard Worker     /* The first three are required by teq1_transceive use. */
345*5c4dab75SAndroid Build Coastguard Worker     TEQ1_ERROR_MESSAGES,
346*5c4dab75SAndroid Build Coastguard Worker     /* The rest are pn80t impl specific. */
347*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorPlatformInit] = "unable to initialize platform",
348*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorPollRead] = "failed to read one byte",
349*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorReceive] = "failed to read",
350*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorReceiveSize] = "attempted to receive too much data",
351*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorTransmitSize] = "attempted to transfer too much data",
352*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorTransmit] = "failed to transmit",
353*5c4dab75SAndroid Build Coastguard Worker     [kNxpPn80tErrorResetToggle] = "failed to toggle reset",
354*5c4dab75SAndroid Build Coastguard Worker };
355