| /* |
| * Copyright (c) 2016-2020, Broadcom |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include <string.h> |
| |
| #include <common/debug.h> |
| #include <lib/mmio.h> |
| #include <sotp.h> |
| |
| #include <platform_def.h> |
| #include <platform_sotp.h> |
| |
| #ifdef USE_SOFT_SOTP |
| extern uint64_t soft_sotp[]; |
| #endif |
| |
| #define SOTP_PROG_CONTROL (SOTP_REGS_OTP_BASE + 0x0000) |
| #define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN 15 |
| #define SOTP_PROG_CONTROL__OTP_DISABLE_ECC 9 |
| #define SOTP_PROG_CONTROL__OTP_ECC_WREN 8 |
| |
| #define SOTP_WRDATA_0 (SOTP_REGS_OTP_BASE + 0x0004) |
| #define SOTP_WRDATA_1 (SOTP_REGS_OTP_BASE + 0x0008) |
| |
| #define SOTP_ADDR (SOTP_REGS_OTP_BASE + 0x000c) |
| #define SOTP_ADDR__OTP_ROW_ADDR_R 6 |
| #define SOTP_ADDR_MASK 0x3FF |
| |
| #define SOTP_CTRL_0 (SOTP_REGS_OTP_BASE + 0x0010) |
| #define SOTP_CTRL_0__START 0 |
| #define SOTP_CTRL_0__OTP_CMD 1 |
| |
| #define SOTP_STATUS_0 (SOTP_REGS_OTP_BASE + 0x0018) |
| #define SOTP_STATUS__FDONE 3 |
| |
| #define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c) |
| #define SOTP_STATUS_1__CMD_DONE 1 |
| #define SOTP_STATUS_1__ECC_DET 17 |
| |
| #define SOTP_RDDATA_0 (SOTP_REGS_OTP_BASE + 0x0020) |
| #define SOTP_RDDATA_1 (SOTP_REGS_OTP_BASE + 0x0024) |
| |
| #define SOTP_READ 0 |
| |
| #define SOTP_PROG_WORD 10 |
| #define SOTP_STATUS__PROGOK 2 |
| #define SOTP_PROG_ENABLE 2 |
| |
| #define SOTP_ROW_DATA_MASK 0xffffffff |
| #define SOTP_ECC_ERR_BITS_MASK 0x1ff00000000 |
| |
| #define SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES 4 |
| #define SOTP_CHIP_CTRL_SW_MANU_PROG 5 |
| #define SOTP_CHIP_CTRL_SW_CID_PROG 6 |
| #define SOTP_CHIP_CTRL_SW_AB_DEVICE 8 |
| #define SOTP_CHIP_CTRL_SW_AB_DEV_MODE 9 |
| #define CHIP_STATE_UNPROGRAMMED 0x1 |
| #define CHIP_STATE_UNASSIGNED 0x2 |
| |
| uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc) |
| { |
| #ifdef USE_SOFT_SOTP |
| (void)sotp_add_ecc; |
| |
| return soft_sotp[offset]; |
| #else |
| uint64_t read_data = 0; |
| uint64_t read_data1 = 0; |
| uint64_t read_data2 = 0; |
| |
| /* Check for FDONE status */ |
| while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) != |
| BIT(SOTP_STATUS__FDONE)) |
| ; |
| |
| /* Enable OTP access by CPU */ |
| mmio_setbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| |
| if (sotp_add_ecc == 1) { |
| mmio_clrbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC)); |
| } |
| |
| if (sotp_add_ecc == 0) { |
| mmio_setbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC)); |
| } |
| |
| mmio_write_32(SOTP_ADDR, |
| ((offset & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R)); |
| mmio_write_32(SOTP_CTRL_0, (SOTP_READ << SOTP_CTRL_0__OTP_CMD)); |
| |
| /* Start bit to tell SOTP to send command to the OTP controller */ |
| mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| |
| /* Wait for SOTP command done to be set */ |
| while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) != |
| BIT(SOTP_STATUS_1__CMD_DONE)) |
| ; |
| |
| /* Clr Start bit after command done */ |
| mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| |
| if ((offset > SOTP_DEVICE_SECURE_CFG3_ROW) && |
| (mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__ECC_DET))) { |
| ERROR("SOTP ECC ERROR Detected row offset %d\n", offset); |
| read_data = SOTP_ECC_ERR_DETECT; |
| } else { |
| read_data1 = (uint64_t)mmio_read_32(SOTP_RDDATA_0); |
| read_data1 = read_data1 & 0xFFFFFFFF; |
| read_data2 = (uint64_t)mmio_read_32(SOTP_RDDATA_1); |
| read_data2 = (read_data2 & 0x1ff) << 32; |
| read_data = read_data1 | read_data2; |
| } |
| |
| /* Command done is cleared */ |
| mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE)); |
| |
| /* disable OTP access by CPU */ |
| mmio_clrbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| |
| return read_data; |
| #endif |
| } |
| |
| void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata) |
| { |
| #ifdef USE_SOFT_SOTP |
| (void)sotp_add_ecc; |
| |
| soft_sotp[addr] = wdata; |
| #else |
| uint32_t loop; |
| uint8_t prog_array[4] = { 0x0F, 0x04, 0x08, 0x0D }; |
| |
| uint32_t chip_state_default = |
| (CHIP_STATE_UNASSIGNED|CHIP_STATE_UNPROGRAMMED); |
| uint32_t chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES); |
| uint32_t chip_ctrl_default = 0; |
| |
| /* |
| * The override settings is required to allow the customer to program |
| * the application specific keys into SOTP, before the conversion to |
| * one of the AB modes. |
| * At the end of write operation, the chip ctrl settings will restored |
| * to the state prior to write call |
| */ |
| if (chip_state & chip_state_default) { |
| uint32_t chip_ctrl; |
| |
| chip_ctrl_default = mmio_read_32(SOTP_CHIP_CTRL); |
| INFO("SOTP: enable special prog mode\n"); |
| |
| chip_ctrl = BIT(SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES) | |
| BIT(SOTP_CHIP_CTRL_SW_MANU_PROG) | |
| BIT(SOTP_CHIP_CTRL_SW_CID_PROG) | |
| BIT(SOTP_CHIP_CTRL_SW_AB_DEVICE); |
| mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl); |
| } |
| |
| /* Check for FDONE status */ |
| while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) != |
| BIT(SOTP_STATUS__FDONE)) |
| ; |
| |
| /* Enable OTP acces by CPU */ |
| mmio_setbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| |
| if (addr > SOTP_DEVICE_SECURE_CFG3_ROW) { |
| if (sotp_add_ecc == 0) { |
| mmio_clrbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN)); |
| } |
| if (sotp_add_ecc == 1) { |
| mmio_setbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN)); |
| } |
| } else { |
| mmio_clrbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN)); |
| } |
| |
| mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_ENABLE << 1)); |
| |
| /* |
| * In order to avoid unintentional writes / programming of the OTP |
| * array, the OTP Controller must be put into programming mode before |
| * it will accept program commands. This is done by writing 0xF, 0x4, |
| * 0x8, 0xD with program commands prior to starting the actual |
| * programming sequence |
| */ |
| for (loop = 0; loop < 4; loop++) { |
| mmio_write_32(SOTP_WRDATA_0, prog_array[loop]); |
| |
| /* |
| * Start bit to tell SOTP to send command to the OTP controller |
| */ |
| mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| |
| /* Wait for SOTP command done to <-- be set */ |
| while ((mmio_read_32(SOTP_STATUS_1) & |
| BIT(SOTP_STATUS_1__CMD_DONE)) != |
| BIT(SOTP_STATUS_1__CMD_DONE)) |
| ; |
| |
| /* Command done is cleared w1c */ |
| mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE)); |
| |
| /* Clr Start bit after command done */ |
| mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| } |
| |
| /* Check for PROGOK */ |
| while ((mmio_read_32(SOTP_STATUS_0) & 0x4) != BIT(SOTP_STATUS__PROGOK)) |
| ; |
| |
| /* Set 10 bit row address */ |
| mmio_write_32(SOTP_ADDR, |
| ((addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R)); |
| |
| /* Set SOTP Row data */ |
| mmio_write_32(SOTP_WRDATA_0, (wdata & SOTP_ROW_DATA_MASK)); |
| |
| /* Set SOTP ECC and error bits */ |
| mmio_write_32(SOTP_WRDATA_1, ((wdata & SOTP_ECC_ERR_BITS_MASK) >> 32)); |
| |
| /* Set prog_word command */ |
| mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_WORD << 1)); |
| |
| /* Start bit to tell SOTP to send command to the OTP controller */ |
| mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| |
| /* Wait for SOTP command done to be set */ |
| while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) != |
| BIT(SOTP_STATUS_1__CMD_DONE)) |
| ; |
| |
| /* Command done is cleared w1c */ |
| mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE)); |
| |
| /* disable OTP acces by CPU */ |
| mmio_clrbits_32(SOTP_PROG_CONTROL, |
| BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN)); |
| |
| /* Clr Start bit after command done */ |
| mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START)); |
| |
| if (chip_state & chip_state_default) |
| mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl_default); |
| |
| #endif |
| } |
| |
| int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row) |
| { |
| int row; |
| uint32_t status = 0; |
| uint32_t status2 = 0xFFFFFFFF; |
| uint64_t row_data; |
| uint32_t data; |
| uint32_t *temp_key = (uint32_t *)key; |
| |
| row = start_row; |
| while ((keysize > 0) && (row <= end_row)) { |
| row_data = sotp_mem_read(row, SOTP_ROW_ECC); |
| if (!(row_data & (SOTP_ECC_ERR_DETECT | SOTP_FAIL_BITS))) { |
| memcpy(temp_key++, &row_data, sizeof(uint32_t)); |
| keysize -= sizeof(uint32_t); |
| data = (uint32_t)(row_data & SOTP_ROW_DATA_MASK); |
| status |= data; |
| status2 &= data; |
| } |
| row++; |
| } |
| |
| if ((status2 == 0xFFFFFFFF) || (status == 0) || (row > end_row)) |
| return -1; |
| |
| return 0; |
| } |
| |
| int sotp_key_erased(void) |
| { |
| uint64_t row_data; |
| int status = 0; |
| |
| row_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0); |
| if (row_data & SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK) |
| status = 1; |
| |
| else if (mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES) & |
| SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK) |
| status = 1; |
| |
| return status; |
| } |
| |
| /* |
| * This function optimise the SOTP redundancy |
| * by considering the 00- zero and 01,10,11 - one |
| */ |
| uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data) |
| { |
| uint32_t opt_data; |
| uint32_t opt_loop; |
| uint32_t temp_data; |
| |
| opt_data = 0; |
| |
| for (opt_loop = 0; opt_loop < 16; opt_loop = opt_loop + 1) { |
| temp_data = ((sotp_row_data >> (opt_loop * 2)) & 0x3); |
| |
| if (temp_data != 0x0) |
| opt_data = (opt_data | (1 << opt_loop)); |
| } |
| return opt_data; |
| } |