1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Support SPI communication with NXP PN553/PN80T secure element.
17 */
18
19 #include "include/ese/hw/nxp/pn80t/common.h"
20
21 #ifndef INT_MAX
22 #define INT_MAX 2147483647
23 #endif
24
nxp_pn80t_preprocess(const struct Teq1ProtocolOptions * const opts,struct Teq1Frame * frame,int tx)25 int nxp_pn80t_preprocess(const struct Teq1ProtocolOptions *const opts,
26 struct Teq1Frame *frame, int tx) {
27 if (tx) {
28 /* Recompute the LRC with the NAD of 0x00 */
29 frame->header.NAD = 0x00;
30 frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
31 frame->header.NAD = opts->node_address;
32 ALOGV("interface is preprocessing outbound frame");
33 } else {
34 /* Replace the NAD with 0x00 so the LRC check passes. */
35 ALOGV("interface is preprocessing inbound frame (%x->%x)",
36 frame->header.NAD, 0x00);
37 if (frame->header.NAD != opts->host_address) {
38 ALOGV("Rewriting from unknown NAD: %x", frame->header.NAD);
39 }
40 frame->header.NAD = 0x00;
41 ALOGV("Frame length: %x", frame->header.LEN);
42 }
43 return 0;
44 }
45
46 static const struct Teq1ProtocolOptions kTeq1Options = {
47 .host_address = 0xA5,
48 .node_address = 0x5A,
49 .bwt = 1.624f, /* cwt by default would be ~8k * 1.05s */
50 .etu = 0.00105f, /* seconds */
51 .preprocess = &nxp_pn80t_preprocess,
52 };
53
nxp_pn80t_open(struct EseInterface * ese,void * board)54 int nxp_pn80t_open(struct EseInterface *ese, void *board) {
55 struct NxpState *ns;
56 const struct Pn80tPlatform *platform;
57 if (sizeof(ese->pad) < sizeof(struct NxpState *)) {
58 /* This is a compile-time correctable error only. */
59 ALOGE("Pad size too small to use NXP HW (%zu < %zu)", sizeof(ese->pad),
60 sizeof(struct NxpState));
61 return -1;
62 }
63 platform = ese->ops->opts;
64
65 /* Ensure all required functions exist */
66 if (!platform->initialize || !platform->release || !platform->toggle_reset ||
67 !platform->wait) {
68 ALOGE("Required functions not implemented in supplied platform");
69 return -1;
70 }
71
72 ns = NXP_PN80T_STATE(ese);
73 TEQ1_INIT_CARD_STATE((struct Teq1CardState *)(&ese->pad[0]));
74 ns->handle = platform->initialize(board);
75 if (!ns->handle) {
76 ALOGE("platform initialization failed");
77 ese_set_error(ese, kNxpPn80tErrorPlatformInit);
78 return -1;
79 }
80 /* Toggle all required power GPIOs.
81 * Each platform may prefer to handle the power
82 * muxing specific. E.g., if NFC is in use, it would
83 * be unwise to unset VEN. However, the implementation
84 * here will attempt it if supported.
85 */
86 if (platform->toggle_ven) {
87 platform->toggle_ven(ns->handle, 1);
88 }
89 if (platform->toggle_power_req) {
90 platform->toggle_power_req(ns->handle, 1);
91 }
92 /* Power on eSE */
93 platform->toggle_reset(ns->handle, 1);
94 /* Let the eSE boot. */
95 platform->wait(ns->handle, 5000);
96 return 0;
97 }
98
nxp_pn80t_reset(struct EseInterface * ese)99 int nxp_pn80t_reset(struct EseInterface *ese) {
100 const struct Pn80tPlatform *platform = ese->ops->opts;
101 struct NxpState *ns = NXP_PN80T_STATE(ese);
102 if (platform->toggle_reset(ns->handle, 0) < 0) {
103 ese_set_error(ese, kNxpPn80tErrorResetToggle);
104 return -1;
105 }
106 platform->wait(ns->handle, 1000);
107 if (platform->toggle_reset(ns->handle, 1) < 0) {
108 ese_set_error(ese, kNxpPn80tErrorResetToggle);
109 return -1;
110 }
111 return 0;
112 }
113
nxp_pn80t_poll(struct EseInterface * ese,uint8_t poll_for,float timeout,int complete)114 int nxp_pn80t_poll(struct EseInterface *ese, uint8_t poll_for, float timeout,
115 int complete) {
116 struct NxpState *ns = NXP_PN80T_STATE(ese);
117 const struct Pn80tPlatform *platform = ese->ops->opts;
118 /* Attempt to read a 8-bit character once per 8-bit character transmission
119 * window (in seconds). */
120 int intervals = (int)(0.5f + timeout / (7.0f * kTeq1Options.etu));
121 uint8_t byte = 0xff;
122 ALOGV("interface polling for start of frame/host node address: %x", poll_for);
123 /* If we had interrupts, we could just get notified by the driver. */
124 do {
125 /*
126 * In practice, if complete=true, then no transmission
127 * should attempt again until after 1000usec.
128 */
129 if (ese->ops->hw_receive(ese, &byte, 1, complete) != 1) {
130 ALOGE("failed to read one byte");
131 ese_set_error(ese, kNxpPn80tErrorPollRead);
132 return -1;
133 }
134 if (byte == poll_for) {
135 ALOGV("Polled for byte seen: %x with %d intervals remaining.", poll_for,
136 intervals);
137 ALOGV("RX[0]: %.2X", byte);
138 return 1;
139 } else {
140 ALOGV("No match (saw %x)", byte);
141 }
142 platform->wait(ns->handle,
143 7.0f * kTeq1Options.etu * 1000000.0f); /* s -> us */
144 ALOGV("poll interval %d: no match.", intervals);
145 } while (intervals-- > 0);
146 ALOGW("polling timed out.");
147 return -1;
148 }
149
nxp_pn80t_transceive(struct EseInterface * ese,const uint8_t * const tx_buf,uint32_t tx_len,uint8_t * rx_buf,uint32_t rx_len)150 uint32_t nxp_pn80t_transceive(struct EseInterface *ese,
151 const uint8_t *const tx_buf, uint32_t tx_len,
152 uint8_t *rx_buf, uint32_t rx_len) {
153 /* TODO(wad) Should we toggle power on each call? */
154 return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
155 }
156
nxp_pn80t_send_cooldown(struct EseInterface * ese)157 uint32_t nxp_pn80t_send_cooldown(struct EseInterface *ese) {
158 const struct Pn80tPlatform *platform = ese->ops->opts;
159 const uint8_t kCooldown[] = {0xa5, 0xc5, 0x00, 0xc5};
160 uint8_t rx_buf[8];
161 uint32_t *res = (uint32_t *)(&rx_buf[3]);
162 ese->ops->hw_transmit(ese, kCooldown, sizeof(kCooldown), 1);
163 nxp_pn80t_poll(ese, kTeq1Options.host_address, 5.0f, 0);
164 ese->ops->hw_receive(ese, rx_buf, sizeof(rx_buf), 1);
165 if (rx_buf[2] == 4) {
166 ALOGI("Cooldown value is %u", *res);
167 return *res;
168 } else {
169 ALOGI("Cooldown value unavailable");
170 }
171 return 0;
172 }
173
nxp_pn80t_close(struct EseInterface * ese)174 void nxp_pn80t_close(struct EseInterface *ese) {
175 struct NxpState *ns;
176 const struct Pn80tPlatform *platform = ese->ops->opts;
177 ALOGV("%s: called", __func__);
178 ns = NXP_PN80T_STATE(ese);
179 nxp_pn80t_send_cooldown(ese);
180 platform->toggle_reset(ns->handle, 0);
181 if (platform->toggle_power_req) {
182 platform->toggle_power_req(ns->handle, 0);
183 }
184 if (platform->toggle_ven) {
185 platform->toggle_ven(ns->handle, 0);
186 }
187 platform->release(ns->handle);
188 ns->handle = NULL;
189 }
190
191 const char *kNxpPn80tErrorMessages[] = {
192 /* The first three are required by teq1_transceive use. */
193 TEQ1_ERROR_MESSAGES,
194 /* The rest are pn80t impl specific. */
195 [kNxpPn80tErrorPlatformInit] = "unable to initialize platform",
196 [kNxpPn80tErrorPollRead] = "failed to read one byte",
197 [kNxpPn80tErrorReceive] = "failed to read",
198 [kNxpPn80tErrorReceiveSize] = "attempted to receive too much data",
199 [kNxpPn80tErrorTransmitSize] = "attempted to transfer too much data",
200 [kNxpPn80tErrorTransmit] = "failed to transmit",
201 [kNxpPn80tErrorResetToggle] = "failed to toggle reset",
202 };
203