Sheetal Tigadoli | ad0943e | 2019-12-18 19:44:43 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016-2020, Broadcom |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <string.h> |
| 8 | |
| 9 | #include <common/debug.h> |
| 10 | #include <lib/mmio.h> |
| 11 | #include <sotp.h> |
| 12 | |
| 13 | #include <platform_def.h> |
| 14 | #include <platform_sotp.h> |
| 15 | |
| 16 | #ifdef USE_SOFT_SOTP |
| 17 | extern uint64_t soft_sotp[]; |
| 18 | #endif |
| 19 | |
| 20 | #define SOTP_PROG_CONTROL (SOTP_REGS_OTP_BASE + 0x0000) |
| 21 | #define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN 15 |
| 22 | #define SOTP_PROG_CONTROL__OTP_DISABLE_ECC 9 |
| 23 | #define SOTP_PROG_CONTROL__OTP_ECC_WREN 8 |
| 24 | |
| 25 | #define SOTP_WRDATA_0 (SOTP_REGS_OTP_BASE + 0x0004) |
| 26 | #define SOTP_WRDATA_1 (SOTP_REGS_OTP_BASE + 0x0008) |
| 27 | |
| 28 | #define SOTP_ADDR (SOTP_REGS_OTP_BASE + 0x000c) |
| 29 | #define SOTP_ADDR__OTP_ROW_ADDR_R 6 |
| 30 | #define SOTP_ADDR_MASK 0x3FF |
| 31 | |
| 32 | #define SOTP_CTRL_0 (SOTP_REGS_OTP_BASE + 0x0010) |
| 33 | #define SOTP_CTRL_0__START 0 |
| 34 | #define SOTP_CTRL_0__OTP_CMD 1 |
| 35 | |
| 36 | #define SOTP_STATUS_0 (SOTP_REGS_OTP_BASE + 0x0018) |
| 37 | #define SOTP_STATUS__FDONE 3 |
| 38 | |
| 39 | #define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c) |
| 40 | #define SOTP_STATUS_1__CMD_DONE 1 |
| 41 | #define SOTP_STATUS_1__ECC_DET 17 |
| 42 | |
| 43 | #define SOTP_RDDATA_0 (SOTP_REGS_OTP_BASE + 0x0020) |
| 44 | #define SOTP_RDDATA_1 (SOTP_REGS_OTP_BASE + 0x0024) |
| 45 | |
| 46 | #define SOTP_READ 0 |
| 47 | |
| 48 | #define SOTP_PROG_WORD 10 |
| 49 | #define SOTP_STATUS__PROGOK 2 |
| 50 | #define SOTP_PROG_ENABLE 2 |
| 51 | |
| 52 | #define SOTP_ROW_DATA_MASK 0xffffffff |
| 53 | #define SOTP_ECC_ERR_BITS_MASK 0x1ff00000000 |
| 54 | |
| 55 | #define SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES 4 |
| 56 | #define SOTP_CHIP_CTRL_SW_MANU_PROG 5 |
| 57 | #define SOTP_CHIP_CTRL_SW_CID_PROG 6 |
| 58 | #define SOTP_CHIP_CTRL_SW_AB_DEVICE 8 |
| 59 | #define SOTP_CHIP_CTRL_SW_AB_DEV_MODE 9 |
| 60 | #define CHIP_STATE_UNPROGRAMMED 0x1 |
| 61 | #define CHIP_STATE_UNASSIGNED 0x2 |
| 62 | |
| 63 | uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc) |
| 64 | { |
| 65 | #ifdef USE_SOFT_SOTP |
| 66 | (void)sotp_add_ecc; |
| 67 | |
| 68 | return soft_sotp[offset]; |
| 69 | #else |
| 70 | uint64_t read_data = 0; |
| 71 | uint64_t read_data1 = 0; |
| 72 | uint64_t read_data2 = 0; |
| 73 | |
| 74 | /* Check for FDONE status */ |
| 75 | while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) != |
| 76 | BIT(SOTP_STATUS__FDONE)) |
| 77 | ; |
| 78 | |
| 79 | /* Enable OTP access by CPU */ |
| 80 | mmio_setbits_32(SOTP_PROG_CONTROL, |
| 81 | BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| 82 | |
| 83 | if (sotp_add_ecc == 1) { |
| 84 | mmio_clrbits_32(SOTP_PROG_CONTROL, |
| 85 | BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC)); |
| 86 | } |
| 87 | |
| 88 | if (sotp_add_ecc == 0) { |
| 89 | mmio_setbits_32(SOTP_PROG_CONTROL, |
| 90 | BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC)); |
| 91 | } |
| 92 | |
| 93 | mmio_write_32(SOTP_ADDR, |
| 94 | ((offset & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R)); |
| 95 | mmio_write_32(SOTP_CTRL_0, (SOTP_READ << SOTP_CTRL_0__OTP_CMD)); |
| 96 | |
| 97 | /* Start bit to tell SOTP to send command to the OTP controller */ |
| 98 | mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| 99 | |
| 100 | /* Wait for SOTP command done to be set */ |
| 101 | while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) != |
| 102 | BIT(SOTP_STATUS_1__CMD_DONE)) |
| 103 | ; |
| 104 | |
| 105 | /* Clr Start bit after command done */ |
| 106 | mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| 107 | |
| 108 | if ((offset > SOTP_DEVICE_SECURE_CFG3_ROW) && |
| 109 | (mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__ECC_DET))) { |
| 110 | ERROR("SOTP ECC ERROR Detected row offset %d\n", offset); |
| 111 | read_data = SOTP_ECC_ERR_DETECT; |
| 112 | } else { |
| 113 | read_data1 = (uint64_t)mmio_read_32(SOTP_RDDATA_0); |
| 114 | read_data1 = read_data1 & 0xFFFFFFFF; |
| 115 | read_data2 = (uint64_t)mmio_read_32(SOTP_RDDATA_1); |
| 116 | read_data2 = (read_data2 & 0x1ff) << 32; |
| 117 | read_data = read_data1 | read_data2; |
| 118 | } |
| 119 | |
| 120 | /* Command done is cleared */ |
| 121 | mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE)); |
| 122 | |
| 123 | /* disable OTP access by CPU */ |
| 124 | mmio_clrbits_32(SOTP_PROG_CONTROL, |
| 125 | BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| 126 | |
| 127 | return read_data; |
| 128 | #endif |
| 129 | } |
| 130 | |
| 131 | void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata) |
| 132 | { |
| 133 | #ifdef USE_SOFT_SOTP |
| 134 | (void)sotp_add_ecc; |
| 135 | |
| 136 | soft_sotp[addr] = wdata; |
| 137 | #else |
| 138 | uint32_t loop; |
| 139 | uint8_t prog_array[4] = { 0x0F, 0x04, 0x08, 0x0D }; |
| 140 | |
| 141 | uint32_t chip_state_default = |
| 142 | (CHIP_STATE_UNASSIGNED|CHIP_STATE_UNPROGRAMMED); |
| 143 | uint32_t chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES); |
| 144 | uint32_t chip_ctrl_default = 0; |
| 145 | |
| 146 | /* |
| 147 | * The override settings is required to allow the customer to program |
| 148 | * the application specific keys into SOTP, before the conversion to |
| 149 | * one of the AB modes. |
| 150 | * At the end of write operation, the chip ctrl settings will restored |
| 151 | * to the state prior to write call |
| 152 | */ |
| 153 | if (chip_state & chip_state_default) { |
| 154 | uint32_t chip_ctrl; |
| 155 | |
| 156 | chip_ctrl_default = mmio_read_32(SOTP_CHIP_CTRL); |
| 157 | INFO("SOTP: enable special prog mode\n"); |
| 158 | |
| 159 | chip_ctrl = BIT(SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES) | |
| 160 | BIT(SOTP_CHIP_CTRL_SW_MANU_PROG) | |
| 161 | BIT(SOTP_CHIP_CTRL_SW_CID_PROG) | |
| 162 | BIT(SOTP_CHIP_CTRL_SW_AB_DEVICE); |
| 163 | mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl); |
| 164 | } |
| 165 | |
| 166 | /* Check for FDONE status */ |
| 167 | while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) != |
| 168 | BIT(SOTP_STATUS__FDONE)) |
| 169 | ; |
| 170 | |
Elyes Haouas | 2be03c0 | 2023-02-13 09:14:48 +0100 | [diff] [blame] | 171 | /* Enable OTP access by CPU */ |
Sheetal Tigadoli | ad0943e | 2019-12-18 19:44:43 +0530 | [diff] [blame] | 172 | mmio_setbits_32(SOTP_PROG_CONTROL, |
| 173 | BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| 174 | |
| 175 | if (addr > SOTP_DEVICE_SECURE_CFG3_ROW) { |
| 176 | if (sotp_add_ecc == 0) { |
| 177 | mmio_clrbits_32(SOTP_PROG_CONTROL, |
| 178 | BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN)); |
| 179 | } |
| 180 | if (sotp_add_ecc == 1) { |
| 181 | mmio_setbits_32(SOTP_PROG_CONTROL, |
| 182 | BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN)); |
| 183 | } |
| 184 | } else { |
| 185 | mmio_clrbits_32(SOTP_PROG_CONTROL, |
| 186 | BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN)); |
| 187 | } |
| 188 | |
| 189 | mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_ENABLE << 1)); |
| 190 | |
| 191 | /* |
| 192 | * In order to avoid unintentional writes / programming of the OTP |
| 193 | * array, the OTP Controller must be put into programming mode before |
| 194 | * it will accept program commands. This is done by writing 0xF, 0x4, |
| 195 | * 0x8, 0xD with program commands prior to starting the actual |
| 196 | * programming sequence |
| 197 | */ |
| 198 | for (loop = 0; loop < 4; loop++) { |
| 199 | mmio_write_32(SOTP_WRDATA_0, prog_array[loop]); |
| 200 | |
| 201 | /* |
| 202 | * Start bit to tell SOTP to send command to the OTP controller |
| 203 | */ |
| 204 | mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| 205 | |
| 206 | /* Wait for SOTP command done to <-- be set */ |
| 207 | while ((mmio_read_32(SOTP_STATUS_1) & |
| 208 | BIT(SOTP_STATUS_1__CMD_DONE)) != |
| 209 | BIT(SOTP_STATUS_1__CMD_DONE)) |
| 210 | ; |
| 211 | |
| 212 | /* Command done is cleared w1c */ |
| 213 | mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE)); |
| 214 | |
| 215 | /* Clr Start bit after command done */ |
| 216 | mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| 217 | } |
| 218 | |
| 219 | /* Check for PROGOK */ |
| 220 | while ((mmio_read_32(SOTP_STATUS_0) & 0x4) != BIT(SOTP_STATUS__PROGOK)) |
| 221 | ; |
| 222 | |
| 223 | /* Set 10 bit row address */ |
| 224 | mmio_write_32(SOTP_ADDR, |
| 225 | ((addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R)); |
| 226 | |
| 227 | /* Set SOTP Row data */ |
| 228 | mmio_write_32(SOTP_WRDATA_0, (wdata & SOTP_ROW_DATA_MASK)); |
| 229 | |
| 230 | /* Set SOTP ECC and error bits */ |
| 231 | mmio_write_32(SOTP_WRDATA_1, ((wdata & SOTP_ECC_ERR_BITS_MASK) >> 32)); |
| 232 | |
| 233 | /* Set prog_word command */ |
| 234 | mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_WORD << 1)); |
| 235 | |
| 236 | /* Start bit to tell SOTP to send command to the OTP controller */ |
| 237 | mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| 238 | |
| 239 | /* Wait for SOTP command done to be set */ |
| 240 | while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) != |
| 241 | BIT(SOTP_STATUS_1__CMD_DONE)) |
| 242 | ; |
| 243 | |
| 244 | /* Command done is cleared w1c */ |
| 245 | mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE)); |
| 246 | |
Elyes Haouas | 2be03c0 | 2023-02-13 09:14:48 +0100 | [diff] [blame] | 247 | /* disable OTP access by CPU */ |
Sheetal Tigadoli | ad0943e | 2019-12-18 19:44:43 +0530 | [diff] [blame] | 248 | mmio_clrbits_32(SOTP_PROG_CONTROL, |
| 249 | BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| 250 | |
| 251 | /* Clr Start bit after command done */ |
| 252 | mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| 253 | |
| 254 | if (chip_state & chip_state_default) |
| 255 | mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl_default); |
| 256 | |
| 257 | #endif |
| 258 | } |
| 259 | |
| 260 | int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row) |
| 261 | { |
| 262 | int row; |
| 263 | uint32_t status = 0; |
| 264 | uint32_t status2 = 0xFFFFFFFF; |
| 265 | uint64_t row_data; |
| 266 | uint32_t data; |
| 267 | uint32_t *temp_key = (uint32_t *)key; |
| 268 | |
| 269 | row = start_row; |
| 270 | while ((keysize > 0) && (row <= end_row)) { |
| 271 | row_data = sotp_mem_read(row, SOTP_ROW_ECC); |
| 272 | if (!(row_data & (SOTP_ECC_ERR_DETECT | SOTP_FAIL_BITS))) { |
| 273 | memcpy(temp_key++, &row_data, sizeof(uint32_t)); |
| 274 | keysize -= sizeof(uint32_t); |
| 275 | data = (uint32_t)(row_data & SOTP_ROW_DATA_MASK); |
| 276 | status |= data; |
| 277 | status2 &= data; |
| 278 | } |
| 279 | row++; |
| 280 | } |
| 281 | |
| 282 | if ((status2 == 0xFFFFFFFF) || (status == 0) || (row > end_row)) |
| 283 | return -1; |
| 284 | |
| 285 | return 0; |
| 286 | } |
| 287 | |
| 288 | int sotp_key_erased(void) |
| 289 | { |
| 290 | uint64_t row_data; |
| 291 | int status = 0; |
| 292 | |
| 293 | row_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0); |
| 294 | if (row_data & SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK) |
| 295 | status = 1; |
| 296 | |
| 297 | else if (mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES) & |
| 298 | SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK) |
| 299 | status = 1; |
| 300 | |
| 301 | return status; |
| 302 | } |
| 303 | |
| 304 | /* |
| 305 | * This function optimise the SOTP redundancy |
| 306 | * by considering the 00- zero and 01,10,11 - one |
| 307 | */ |
| 308 | uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data) |
| 309 | { |
| 310 | uint32_t opt_data; |
| 311 | uint32_t opt_loop; |
| 312 | uint32_t temp_data; |
| 313 | |
| 314 | opt_data = 0; |
| 315 | |
| 316 | for (opt_loop = 0; opt_loop < 16; opt_loop = opt_loop + 1) { |
| 317 | temp_data = ((sotp_row_data >> (opt_loop * 2)) & 0x3); |
| 318 | |
| 319 | if (temp_data != 0x0) |
| 320 | opt_data = (opt_data | (1 << opt_loop)); |
| 321 | } |
| 322 | return opt_data; |
| 323 | } |