123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /*
- * Copyright (c) 2017 - 2020, Broadcom
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <stdint.h>
- #include <common/debug.h>
- #include <drivers/delay_timer.h>
- #include <lib/mmio.h>
- #include <ocotp.h>
- #include <platform_def.h>
- #define OTP_MAP 2
- #define OTP_NUM_WORDS 2048
- /*
- * # of tries for OTP Status. The time to execute a command varies. The slowest
- * commands are writes which also vary based on the # of bits turned on. Writing
- * 0xffffffff takes ~3800 us.
- */
- #define OTPC_RETRIES_US 5000
- /* Sequence to enable OTP program */
- #define OTPC_PROG_EN_SEQ { 0xf, 0x4, 0x8, 0xd }
- /* OTPC Commands */
- #define OTPC_CMD_READ 0x0
- #define OTPC_CMD_OTP_PROG_ENABLE 0x2
- #define OTPC_CMD_OTP_PROG_DISABLE 0x3
- #define OTPC_CMD_PROGRAM 0x8
- #define OTPC_CMD_ECC 0x10
- #define OTPC_ECC_ADDR 0x1A
- #define OTPC_ECC_VAL 0x00EC0000
- /* OTPC Status Bits */
- #define OTPC_STAT_CMD_DONE BIT(1)
- #define OTPC_STAT_PROG_OK BIT(2)
- /* OTPC register definition */
- #define OTPC_MODE_REG_OFFSET 0x0
- #define OTPC_MODE_REG_OTPC_MODE 0
- #define OTPC_COMMAND_OFFSET 0x4
- #define OTPC_COMMAND_COMMAND_WIDTH 6
- #define OTPC_CMD_START_OFFSET 0x8
- #define OTPC_CMD_START_START 0
- #define OTPC_CPU_STATUS_OFFSET 0xc
- #define OTPC_CPUADDR_REG_OFFSET 0x28
- #define OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH 16
- #define OTPC_CPU_WRITE_REG_OFFSET 0x2c
- #define OTPC_CMD_MASK (BIT(OTPC_COMMAND_COMMAND_WIDTH) - 1)
- #define OTPC_ADDR_MASK (BIT(OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH) - 1)
- #define OTPC_MODE_REG OCOTP_REGS_BASE
- struct chip_otp_cfg {
- uint32_t base;
- uint32_t num_words;
- };
- struct chip_otp_cfg ocotp_cfg = {
- .base = OTPC_MODE_REG,
- .num_words = 2048,
- };
- struct otpc_priv {
- uint32_t base;
- struct otpc_map *map;
- int size;
- int state;
- };
- struct otpc_priv otpc_info;
- static inline void set_command(uint32_t base, uint32_t command)
- {
- mmio_write_32(base + OTPC_COMMAND_OFFSET, command & OTPC_CMD_MASK);
- }
- static inline void set_cpu_address(uint32_t base, uint32_t addr)
- {
- mmio_write_32(base + OTPC_CPUADDR_REG_OFFSET, addr & OTPC_ADDR_MASK);
- }
- static inline void set_start_bit(uint32_t base)
- {
- mmio_write_32(base + OTPC_CMD_START_OFFSET, 1 << OTPC_CMD_START_START);
- }
- static inline void reset_start_bit(uint32_t base)
- {
- mmio_write_32(base + OTPC_CMD_START_OFFSET, 0);
- }
- static inline void write_cpu_data(uint32_t base, uint32_t value)
- {
- mmio_write_32(base + OTPC_CPU_WRITE_REG_OFFSET, value);
- }
- static int poll_cpu_status(uint32_t base, uint32_t value)
- {
- uint32_t status;
- uint32_t retries;
- for (retries = 0; retries < OTPC_RETRIES_US; retries++) {
- status = mmio_read_32(base + OTPC_CPU_STATUS_OFFSET);
- if (status & value)
- break;
- udelay(1);
- }
- if (retries == OTPC_RETRIES_US)
- return -1;
- return 0;
- }
- static int bcm_otpc_ecc(uint32_t enable)
- {
- struct otpc_priv *priv = &otpc_info;
- int ret;
- set_command(priv->base, OTPC_CMD_ECC);
- set_cpu_address(priv->base, OTPC_ECC_ADDR);
- if (!enable)
- write_cpu_data(priv->base, OTPC_ECC_VAL);
- else
- write_cpu_data(priv->base, ~OTPC_ECC_VAL);
- set_start_bit(priv->base);
- ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
- if (ret) {
- ERROR("otp ecc op error: 0x%x", ret);
- return -1;
- }
- reset_start_bit(priv->base);
- return 0;
- }
- /*
- * bcm_otpc_read read otp data in the size of 8 byte rows.
- * bytes has to be the multiple of 8.
- * return -1 in error case, return read bytes in success.
- */
- int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes,
- uint32_t ecc_flag)
- {
- struct otpc_priv *priv = &otpc_info;
- uint32_t *buf = val;
- uint32_t bytes_read;
- uint32_t address = offset / priv->map->word_size;
- int i, ret;
- if (!priv->state) {
- ERROR("OCOTP read failed\n");
- return -1;
- }
- bcm_otpc_ecc(ecc_flag);
- for (bytes_read = 0; (bytes_read + priv->map->word_size) <= bytes;) {
- set_command(priv->base, OTPC_CMD_READ);
- set_cpu_address(priv->base, address++);
- set_start_bit(priv->base);
- ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
- if (ret) {
- ERROR("otp read error: 0x%x", ret);
- return -1;
- }
- for (i = 0; i < priv->map->otpc_row_size; i++) {
- *buf++ = mmio_read_32(priv->base +
- priv->map->data_r_offset[i]);
- bytes_read += sizeof(*buf);
- }
- reset_start_bit(priv->base);
- }
- return bytes_read;
- }
- int bcm_otpc_init(struct otpc_map *map)
- {
- struct otpc_priv *priv;
- priv = &otpc_info;
- priv->base = ocotp_cfg.base;
- priv->map = map;
- priv->size = 4 * ocotp_cfg.num_words;
- /* Enable CPU access to OTPC. */
- mmio_setbits_32(priv->base + OTPC_MODE_REG_OFFSET,
- BIT(OTPC_MODE_REG_OTPC_MODE));
- reset_start_bit(priv->base);
- priv->state = 1;
- VERBOSE("OTPC Initialization done\n");
- return 0;
- }
|