|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 ITE Corporation. |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#define DT_DRV_COMPAT ite_it51xxx_sha |
| 8 | + |
| 9 | +#include <errno.h> |
| 10 | +#include <it51xxx/chip_chipregs.h> |
| 11 | +#include <zephyr/crypto/crypto.h> |
| 12 | +#include <zephyr/kernel.h> |
| 13 | +#include <zephyr/sys/byteorder.h> |
| 14 | + |
| 15 | +#include <zephyr/logging/log.h> |
| 16 | +LOG_MODULE_REGISTER(crypto_it51xxx_sha, CONFIG_CRYPTO_LOG_LEVEL); |
| 17 | + |
| 18 | +#define IT51XXX_SHA_REGS_BASE DT_REG_ADDR(DT_NODELABEL(sha256)) |
| 19 | + |
| 20 | +/* 0x00: SHA Control Register (SHACR) */ |
| 21 | +#define IT51XXX_SHACR (IT51XXX_SHA_REGS_BASE + 0x00) |
| 22 | +#define IT51XXX_SHAWB BIT(2) |
| 23 | +#define IT51XXX_SHAINI BIT(1) |
| 24 | +#define IT51XXX_SHAEXE BIT(0) |
| 25 | +/* 0x01: SHA Status Register (SHASR)*/ |
| 26 | +#define IT51XXX_SHASR (IT51XXX_SHA_REGS_BASE + 0x01) |
| 27 | +#define IT51XXX_SHAIE BIT(3) |
| 28 | +#define IT51XXX_SHAIS BIT(2) |
| 29 | +#define IT51XXX_SHABUSY BIT(0) |
| 30 | +/* 0x02: SHA Execution Counter Register (SHAECR) */ |
| 31 | +#define IT51XXX_SHAECR (IT51XXX_SHA_REGS_BASE + 0x02) |
| 32 | +#define IT51XXX_SHAEXEC_64_BYTE 0x00 |
| 33 | +#define IT51XXX_SHAEXEC_1K_BYTE 0x0F |
| 34 | +/* 0x03: SHA DLM Base Address 0 Register (SHADBA0R) */ |
| 35 | +#define IT51XXX_SHADBA0R (IT51XXX_SHA_REGS_BASE + 0x03) |
| 36 | +/* 0x04: SHA DLM Base Address 1 Register (SHADBA1R) */ |
| 37 | +#define IT51XXX_SHADBA1R (IT51XXX_SHA_REGS_BASE + 0x04) |
| 38 | +/* 0x05: SHA Setting Register (SHASETR) */ |
| 39 | +#define IT51XXX_SHASETR (IT51XXX_SHA_REGS_BASE + 0x05) |
| 40 | +#define IT51XXX_SHA256 0x00 |
| 41 | +/* 0x06: SHA DLM Base Address 2 Register (SHADBA2R) */ |
| 42 | +#define IT51XXX_SHADBA2R (IT51XXX_SHA_REGS_BASE + 0x06) |
| 43 | + |
| 44 | +#define SHA_SHA256_HASH_LEN 32 |
| 45 | +#define SHA_SHA256_BLOCK_LEN 64 |
| 46 | +#define SHA_SHA256_HASH_LEN_WORDS (SHA_SHA256_HASH_LEN / sizeof(uint32_t)) |
| 47 | +#define SHA_SHA256_BLOCK_LEN_WORDS (SHA_SHA256_BLOCK_LEN / sizeof(uint32_t)) |
| 48 | + |
| 49 | +/* |
| 50 | + * If the input message is more than 1K bytes, taking 10K bytes for example, |
| 51 | + * it should run 10 times SHA hardwired loading and execution, and process 1K bytes each time. |
| 52 | + */ |
| 53 | +#define SHA_HW_MAX_INPUT_LEN 1024 |
| 54 | +#define SHA_HW_MAX_INPUT_LEN_WORDS (SHA_HW_MAX_INPUT_LEN / sizeof(uint32_t)) |
| 55 | + |
| 56 | +/* |
| 57 | + * This struct is used by the hardware and must be stored in RAM first 4k-byte |
| 58 | + * and aligned on a 256-byte boundary. |
| 59 | + */ |
| 60 | +struct chip_sha256_ctx { |
| 61 | + union { |
| 62 | + /* SHA data buffer */ |
| 63 | + uint32_t w_sha[SHA_HW_MAX_INPUT_LEN_WORDS]; |
| 64 | + uint8_t w_input[SHA_HW_MAX_INPUT_LEN]; |
| 65 | + }; |
| 66 | + /* H[0] ~ H[7] */ |
| 67 | + uint32_t h[SHA_SHA256_HASH_LEN_WORDS]; |
| 68 | + uint32_t sha_init; |
| 69 | + uint32_t w_input_index; |
| 70 | + uint32_t total_len; |
| 71 | +} __aligned(256); |
| 72 | + |
| 73 | +Z_GENERIC_SECTION(.__sha256_ram_block) struct chip_sha256_ctx chip_ctx; |
| 74 | + |
| 75 | +static void it51xxx_sha256_init(bool init_k) |
| 76 | +{ |
| 77 | + chip_ctx.sha_init = init_k; |
| 78 | + chip_ctx.total_len = 0; |
| 79 | + chip_ctx.w_input_index = 0; |
| 80 | + |
| 81 | + /* Set DLM address for input data */ |
| 82 | + sys_write8(((uint32_t)&chip_ctx) & 0xC0, IT51XXX_SHADBA0R); |
| 83 | + sys_write8(((uint32_t)&chip_ctx) >> 8, IT51XXX_SHADBA1R); |
| 84 | + sys_write8(((uint32_t)&chip_ctx) >> 16, IT51XXX_SHADBA2R); |
| 85 | +} |
| 86 | + |
| 87 | +static void it51xxx_sha256_module_calculation(void) |
| 88 | +{ |
| 89 | + uint32_t key; |
| 90 | + |
| 91 | + /* |
| 92 | + * Global interrupt is disabled because the CPU cannot access memory |
| 93 | + * via the DLM (Data Local Memory) bus while HW module is computing |
| 94 | + * hash. |
| 95 | + */ |
| 96 | + key = irq_lock(); |
| 97 | + |
| 98 | + if (chip_ctx.sha_init) { |
| 99 | + chip_ctx.sha_init = 0; |
| 100 | + sys_write8(IT51XXX_SHAINI | IT51XXX_SHAEXE, IT51XXX_SHACR); |
| 101 | + } else { |
| 102 | + sys_write8(IT51XXX_SHAEXE, IT51XXX_SHACR); |
| 103 | + } |
| 104 | + |
| 105 | + while (sys_read8(IT51XXX_SHASR) & IT51XXX_SHABUSY) { |
| 106 | + }; |
| 107 | + sys_write8(IT51XXX_SHAIS, IT51XXX_SHASR); |
| 108 | + |
| 109 | + irq_unlock(key); |
| 110 | + |
| 111 | + chip_ctx.w_input_index = 0; |
| 112 | +} |
| 113 | + |
| 114 | +static int it51xxx_hash_handler(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish) |
| 115 | +{ |
| 116 | + uint32_t i; |
| 117 | + uint32_t in_buf_idx = 0; |
| 118 | + uint32_t key; |
| 119 | + uint32_t rem_len = pkt->in_len; |
| 120 | + |
| 121 | + /* data length >= 1KiB */ |
| 122 | + while (rem_len >= SHA_HW_MAX_INPUT_LEN) { |
| 123 | + rem_len = rem_len - SHA_HW_MAX_INPUT_LEN; |
| 124 | + |
| 125 | + for (i = 0; i < SHA_HW_MAX_INPUT_LEN; i++) { |
| 126 | + chip_ctx.w_input[chip_ctx.w_input_index++] = pkt->in_buf[in_buf_idx++]; |
| 127 | + } |
| 128 | + |
| 129 | + /* HW automatically load 1KB data from DLM */ |
| 130 | + sys_write8(IT51XXX_SHAEXEC_1K_BYTE, IT51XXX_SHAECR); |
| 131 | + while (sys_read8(IT51XXX_SHASR) & IT51XXX_SHABUSY) { |
| 132 | + }; |
| 133 | + |
| 134 | + it51xxx_sha256_module_calculation(); |
| 135 | + } |
| 136 | + |
| 137 | + /* 0 <= data length < 1KiB */ |
| 138 | + while (rem_len) { |
| 139 | + rem_len--; |
| 140 | + chip_ctx.w_input[chip_ctx.w_input_index++] = pkt->in_buf[in_buf_idx++]; |
| 141 | + |
| 142 | + /* |
| 143 | + * If fill full 64byte then execute HW calculation. |
| 144 | + * If not, will execute in later finish block. |
| 145 | + */ |
| 146 | + if (chip_ctx.w_input_index >= SHA_SHA256_BLOCK_LEN) { |
| 147 | + /* HW automatically load 64 bytes data from DLM */ |
| 148 | + sys_write8(IT51XXX_SHAEXEC_64_BYTE, IT51XXX_SHAECR); |
| 149 | + while (sys_read8(IT51XXX_SHASR) & IT51XXX_SHABUSY) { |
| 150 | + }; |
| 151 | + |
| 152 | + it51xxx_sha256_module_calculation(); |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + chip_ctx.total_len += pkt->in_len; |
| 157 | + |
| 158 | + if (finish) { |
| 159 | + uint32_t *out_buf_ptr = (uint32_t *)pkt->out_buf; |
| 160 | + |
| 161 | + /* Pre-processing (Padding) */ |
| 162 | + chip_ctx.w_input[chip_ctx.w_input_index++] = 0x80; |
| 163 | + memset(&chip_ctx.w_input[chip_ctx.w_input_index], 0, |
| 164 | + SHA_SHA256_BLOCK_LEN - chip_ctx.w_input_index); |
| 165 | + |
| 166 | + /* |
| 167 | + * Handles the boundary case of rest data: |
| 168 | + * Because the last eight bytes are bit length field of SHA256 rule. |
| 169 | + * If the data index >= 56, it needs to trigger HW to calculate, |
| 170 | + * then fill 0 data and the last eight bytes bit length, and calculate |
| 171 | + * again. |
| 172 | + */ |
| 173 | + if (chip_ctx.w_input_index >= 56) { |
| 174 | + /* HW automatically load 64Bytes data from DLM */ |
| 175 | + sys_write8(IT51XXX_SHAEXEC_64_BYTE, IT51XXX_SHAECR); |
| 176 | + while (sys_read8(IT51XXX_SHASR) & IT51XXX_SHABUSY) { |
| 177 | + }; |
| 178 | + |
| 179 | + it51xxx_sha256_module_calculation(); |
| 180 | + |
| 181 | + memset(&chip_ctx.w_input[chip_ctx.w_input_index], 0, |
| 182 | + SHA_SHA256_BLOCK_LEN - chip_ctx.w_input_index); |
| 183 | + } |
| 184 | + |
| 185 | + /* |
| 186 | + * Since input data (big-endian) are copied 1byte by 1byte to |
| 187 | + * it51xxx memory (little-endian), so the bit length needs to |
| 188 | + * be transformed into big-endian format and then write to memory. |
| 189 | + */ |
| 190 | + chip_ctx.w_sha[15] = sys_cpu_to_be32(chip_ctx.total_len * 8); |
| 191 | + |
| 192 | + /* HW automatically load 64Bytes data from DLM */ |
| 193 | + sys_write8(IT51XXX_SHAEXEC_64_BYTE, IT51XXX_SHAECR); |
| 194 | + while (sys_read8(IT51XXX_SHASR) & IT51XXX_SHABUSY) { |
| 195 | + }; |
| 196 | + |
| 197 | + it51xxx_sha256_module_calculation(); |
| 198 | + |
| 199 | + /* HW write back the hash result to DLM */ |
| 200 | + /* Set DLM address for input data */ |
| 201 | + sys_write8(((uint32_t)&chip_ctx.h) & 0xC0, IT51XXX_SHADBA0R); |
| 202 | + sys_write8(((uint32_t)&chip_ctx.h) >> 8, IT51XXX_SHADBA1R); |
| 203 | + |
| 204 | + key = irq_lock(); |
| 205 | + |
| 206 | + sys_write8(IT51XXX_SHAWB, IT51XXX_SHACR); |
| 207 | + while (sys_read8(IT51XXX_SHASR) & IT51XXX_SHABUSY) { |
| 208 | + }; |
| 209 | + |
| 210 | + sys_write8(IT51XXX_SHAIS, IT51XXX_SHASR); |
| 211 | + |
| 212 | + irq_unlock(key); |
| 213 | + |
| 214 | + for (i = 0; i < SHA_SHA256_HASH_LEN_WORDS; i++) { |
| 215 | + out_buf_ptr[i] = chip_ctx.h[i]; |
| 216 | + } |
| 217 | + |
| 218 | + it51xxx_sha256_init(true); |
| 219 | + } |
| 220 | + |
| 221 | + return 0; |
| 222 | +} |
| 223 | + |
| 224 | +static int it51xxx_hash_session_free(const struct device *dev, struct hash_ctx *ctx) |
| 225 | +{ |
| 226 | + it51xxx_sha256_init(true); |
| 227 | + |
| 228 | + return 0; |
| 229 | +} |
| 230 | + |
| 231 | +static inline int it51xxx_query_hw_caps(const struct device *dev) |
| 232 | +{ |
| 233 | + return (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS); |
| 234 | +} |
| 235 | + |
| 236 | +static int it51xxx_hash_begin_session(const struct device *dev, struct hash_ctx *ctx, |
| 237 | + enum hash_algo algo) |
| 238 | +{ |
| 239 | + if (algo != CRYPTO_HASH_ALGO_SHA256) { |
| 240 | + LOG_ERR("Unsupported algorithm"); |
| 241 | + return -EINVAL; |
| 242 | + } |
| 243 | + |
| 244 | + if (ctx->flags & ~(it51xxx_query_hw_caps(dev))) { |
| 245 | + LOG_ERR("Unsupported flag"); |
| 246 | + return -EINVAL; |
| 247 | + } |
| 248 | + |
| 249 | + it51xxx_sha256_init(true); |
| 250 | + ctx->hash_hndlr = it51xxx_hash_handler; |
| 251 | + |
| 252 | + return 0; |
| 253 | +} |
| 254 | + |
| 255 | +static int it51xxx_sha_init(const struct device *dev) |
| 256 | +{ |
| 257 | + it51xxx_sha256_init(true); |
| 258 | + |
| 259 | + /* Select SHA-2 Family, SHA-256 */ |
| 260 | + sys_write8(IT51XXX_SHA256, IT51XXX_SHASETR); |
| 261 | + |
| 262 | + /* SHA interrupt disable */ |
| 263 | + sys_write8(sys_read8(IT51XXX_SHASR) & ~IT51XXX_SHAIE, IT51XXX_SHASR); |
| 264 | + |
| 265 | + return 0; |
| 266 | +} |
| 267 | + |
| 268 | +static DEVICE_API(crypto, it51xxx_crypto_api) = { |
| 269 | + .hash_begin_session = it51xxx_hash_begin_session, |
| 270 | + .hash_free_session = it51xxx_hash_session_free, |
| 271 | + .query_hw_caps = it51xxx_query_hw_caps, |
| 272 | +}; |
| 273 | + |
| 274 | +DEVICE_DT_INST_DEFINE(0, &it51xxx_sha_init, NULL, NULL, NULL, POST_KERNEL, |
| 275 | + CONFIG_CRYPTO_INIT_PRIORITY, &it51xxx_crypto_api); |
| 276 | +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "support only one sha compatible node"); |
0 commit comments