From 525c44ee7f3b0f10ca4f3b7f0bb5b899e2bccbc6 Mon Sep 17 00:00:00 2001 From: Sandeep Tripathy Date: Fri, 12 Apr 2019 21:34:12 +0530 Subject: drivers: bcm_sotp: add SOTP driver low level driver for Broadcom SOTP controller. Acked-by: Jens Wiklander Reviewed-by: Etienne Carriere Signed-off-by: Rahul Gupta Signed-off-by: Sandeep Tripathy --- core/drivers/bcm_sotp.c | 131 ++++++++++++++++++++++++++++++++++++++++ core/drivers/sub.mk | 1 + core/include/drivers/bcm_sotp.h | 15 +++++ 3 files changed, 147 insertions(+) create mode 100644 core/drivers/bcm_sotp.c create mode 100644 core/include/drivers/bcm_sotp.h (limited to 'core') diff --git a/core/drivers/bcm_sotp.c b/core/drivers/bcm_sotp.c new file mode 100644 index 00000000..03d18a42 --- /dev/null +++ b/core/drivers/bcm_sotp.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright 2019 Broadcom. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOTP_PROG_CONTROL 0x0 +#define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN BIT(15) +#define SOTP_PROG_CONTROL__OTP_DISABLE_ECC BIT(9) +#define SOTP_ADDR__OTP_ROW_ADDR_R 6 + +#define SOTP_ADDR 0xc + +#define SOTP_CTRL_0 0x10 +#define SOTP_CTRL_0__START 1 +#define SOTP_READ 0 + +#define SOTP_STAT_0 0x18 +#define SOTP_STATUS_0__FDONE BIT(3) + +#define SOTP_STATUS_1 0x1c +#define SOTP_STATUS_1__CMD_DONE BIT(1) +#define SOTP_STATUS_1__ECC_DET BIT(17) + +#define SOTP_RDDATA_0 0x20 +#define SOTP_RDDATA_1 0x24 +#define SOTP_ADDR_MASK 0x3ff + +#define SOTP_ECC_ERR_DETECT BIT64(63) + +#define SOTP_TIMEOUT_US 300 + +static vaddr_t bcm_sotp_base; + +static TEE_Result otp_status_done_wait(vaddr_t addr, uint32_t bit) +{ + uint64_t timeout = timeout_init_us(SOTP_TIMEOUT_US); + + while (!(io_read32(addr) & bit)) + if (timeout_elapsed(timeout)) + return TEE_ERROR_BUSY; + return TEE_SUCCESS; +} + +TEE_Result bcm_iproc_sotp_mem_read(uint32_t row_addr, uint32_t sotp_add_ecc, + uint64_t *rdata) +{ + uint64_t read_data = 0; + uint32_t reg_val = 0; + TEE_Result ret = TEE_SUCCESS; + + assert(bcm_sotp_base); + /* Check for FDONE status */ + ret = otp_status_done_wait((bcm_sotp_base + SOTP_STAT_0), + SOTP_STATUS_0__FDONE); + if (ret) { + EMSG("FDONE status done wait failed"); + return ret; + } + + /* Enable OTP access by CPU */ + io_setbits32((bcm_sotp_base + SOTP_PROG_CONTROL), + SOTP_PROG_CONTROL__OTP_CPU_MODE_EN); + + if (sotp_add_ecc == 1) { + io_clrbits32((bcm_sotp_base + SOTP_PROG_CONTROL), + SOTP_PROG_CONTROL__OTP_DISABLE_ECC); + } else { + io_setbits32((bcm_sotp_base + SOTP_PROG_CONTROL), + SOTP_PROG_CONTROL__OTP_DISABLE_ECC); + } + + /* 10 bit row address */ + reg_val = (row_addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R; + io_write32((bcm_sotp_base + SOTP_ADDR), reg_val); + reg_val = SOTP_READ; + io_write32((bcm_sotp_base + SOTP_CTRL_0), reg_val); + + /* Start bit to tell SOTP to send command to the OTP controller */ + io_setbits32((bcm_sotp_base + SOTP_CTRL_0), SOTP_CTRL_0__START); + + /* Wait for SOTP command done to be set */ + ret = otp_status_done_wait((bcm_sotp_base + SOTP_STAT_0), + SOTP_STATUS_1__CMD_DONE); + if (ret) { + EMSG("FDONE cmd done wait failed\n"); + return ret; + } + + DMSG("CMD Done\n"); + + /* Clr Start bit after command done */ + io_clrbits32((bcm_sotp_base + SOTP_CTRL_0), SOTP_CTRL_0__START); + read_data = io_read32(bcm_sotp_base + SOTP_RDDATA_1); + read_data = ((read_data & 0x1ff) << 32); + read_data |= io_read32(bcm_sotp_base + SOTP_RDDATA_0); + + reg_val = io_read32(bcm_sotp_base + SOTP_STATUS_1); + /* no ECC check till row 15 */ + if ((row_addr > 15) && (reg_val & SOTP_STATUS_1__ECC_DET)) { + EMSG("SOTP ECC ERROR Detected ROW %d\n", row_addr); + read_data = SOTP_ECC_ERR_DETECT; + } + + /* Command done is cleared */ + io_setbits32((bcm_sotp_base + SOTP_STATUS_1), SOTP_STATUS_1__CMD_DONE); + io_clrbits32((bcm_sotp_base + SOTP_PROG_CONTROL), + SOTP_PROG_CONTROL__OTP_CPU_MODE_EN); + DMSG("read done\n"); + + *rdata = read_data; + return ret; +} + +static TEE_Result bcm_sotp_init(void) +{ + bcm_sotp_base = (vaddr_t)phys_to_virt(SOTP_BASE, MEM_AREA_IO_SEC); + + DMSG("bcm_sotp init done\n"); + return TEE_SUCCESS; +} + +driver_init(bcm_sotp_init); diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk index e0cf05ae..bbe5cef0 100644 --- a/core/drivers/sub.mk +++ b/core/drivers/sub.mk @@ -26,3 +26,4 @@ srcs-$(CFG_STM32_RNG) += stm32_rng.c srcs-$(CFG_STM32_UART) += stm32_uart.c srcs-$(CFG_STM32_I2C) += stm32_i2c.c srcs-$(CFG_BCM_HWRNG) += bcm_hwrng.c +srcs-$(CFG_BCM_SOTP) += bcm_sotp.c diff --git a/core/include/drivers/bcm_sotp.h b/core/include/drivers/bcm_sotp.h new file mode 100644 index 00000000..1b66115d --- /dev/null +++ b/core/include/drivers/bcm_sotp.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2019 Broadcom. + */ + +#ifndef BCM_SOTP_H +#define BCM_SOTP_H + +#include +#include + +TEE_Result bcm_iproc_sotp_mem_read(uint32_t row_addr, uint32_t sotp_add_ecc, + uint64_t *rdata); + +#endif -- cgit v1.2.3