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 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 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 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 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 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 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 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