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