1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
/*
* 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;
}
|