1*f29d1e0cSSheetal Tigadoli /* 2*f29d1e0cSSheetal Tigadoli * Copyright (c) 2017 - 2020, Broadcom 3*f29d1e0cSSheetal Tigadoli * 4*f29d1e0cSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause 5*f29d1e0cSSheetal Tigadoli */ 6*f29d1e0cSSheetal Tigadoli 7*f29d1e0cSSheetal Tigadoli #include <stdint.h> 8*f29d1e0cSSheetal Tigadoli 9*f29d1e0cSSheetal Tigadoli #include <common/debug.h> 10*f29d1e0cSSheetal Tigadoli #include <drivers/delay_timer.h> 11*f29d1e0cSSheetal Tigadoli #include <lib/mmio.h> 12*f29d1e0cSSheetal Tigadoli 13*f29d1e0cSSheetal Tigadoli #include <ocotp.h> 14*f29d1e0cSSheetal Tigadoli #include <platform_def.h> 15*f29d1e0cSSheetal Tigadoli 16*f29d1e0cSSheetal Tigadoli #define OTP_MAP 2 17*f29d1e0cSSheetal Tigadoli #define OTP_NUM_WORDS 2048 18*f29d1e0cSSheetal Tigadoli /* 19*f29d1e0cSSheetal Tigadoli * # of tries for OTP Status. The time to execute a command varies. The slowest 20*f29d1e0cSSheetal Tigadoli * commands are writes which also vary based on the # of bits turned on. Writing 21*f29d1e0cSSheetal Tigadoli * 0xffffffff takes ~3800 us. 22*f29d1e0cSSheetal Tigadoli */ 23*f29d1e0cSSheetal Tigadoli #define OTPC_RETRIES_US 5000 24*f29d1e0cSSheetal Tigadoli 25*f29d1e0cSSheetal Tigadoli /* Sequence to enable OTP program */ 26*f29d1e0cSSheetal Tigadoli #define OTPC_PROG_EN_SEQ { 0xf, 0x4, 0x8, 0xd } 27*f29d1e0cSSheetal Tigadoli 28*f29d1e0cSSheetal Tigadoli /* OTPC Commands */ 29*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_READ 0x0 30*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_OTP_PROG_ENABLE 0x2 31*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_OTP_PROG_DISABLE 0x3 32*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_PROGRAM 0x8 33*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_ECC 0x10 34*f29d1e0cSSheetal Tigadoli #define OTPC_ECC_ADDR 0x1A 35*f29d1e0cSSheetal Tigadoli #define OTPC_ECC_VAL 0x00EC0000 36*f29d1e0cSSheetal Tigadoli 37*f29d1e0cSSheetal Tigadoli /* OTPC Status Bits */ 38*f29d1e0cSSheetal Tigadoli #define OTPC_STAT_CMD_DONE BIT(1) 39*f29d1e0cSSheetal Tigadoli #define OTPC_STAT_PROG_OK BIT(2) 40*f29d1e0cSSheetal Tigadoli 41*f29d1e0cSSheetal Tigadoli /* OTPC register definition */ 42*f29d1e0cSSheetal Tigadoli #define OTPC_MODE_REG_OFFSET 0x0 43*f29d1e0cSSheetal Tigadoli #define OTPC_MODE_REG_OTPC_MODE 0 44*f29d1e0cSSheetal Tigadoli #define OTPC_COMMAND_OFFSET 0x4 45*f29d1e0cSSheetal Tigadoli #define OTPC_COMMAND_COMMAND_WIDTH 6 46*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_START_OFFSET 0x8 47*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_START_START 0 48*f29d1e0cSSheetal Tigadoli #define OTPC_CPU_STATUS_OFFSET 0xc 49*f29d1e0cSSheetal Tigadoli #define OTPC_CPUADDR_REG_OFFSET 0x28 50*f29d1e0cSSheetal Tigadoli #define OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH 16 51*f29d1e0cSSheetal Tigadoli #define OTPC_CPU_WRITE_REG_OFFSET 0x2c 52*f29d1e0cSSheetal Tigadoli 53*f29d1e0cSSheetal Tigadoli #define OTPC_CMD_MASK (BIT(OTPC_COMMAND_COMMAND_WIDTH) - 1) 54*f29d1e0cSSheetal Tigadoli #define OTPC_ADDR_MASK (BIT(OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH) - 1) 55*f29d1e0cSSheetal Tigadoli 56*f29d1e0cSSheetal Tigadoli #define OTPC_MODE_REG OCOTP_REGS_BASE 57*f29d1e0cSSheetal Tigadoli 58*f29d1e0cSSheetal Tigadoli struct chip_otp_cfg { 59*f29d1e0cSSheetal Tigadoli uint32_t base; 60*f29d1e0cSSheetal Tigadoli uint32_t num_words; 61*f29d1e0cSSheetal Tigadoli }; 62*f29d1e0cSSheetal Tigadoli 63*f29d1e0cSSheetal Tigadoli struct chip_otp_cfg ocotp_cfg = { 64*f29d1e0cSSheetal Tigadoli .base = OTPC_MODE_REG, 65*f29d1e0cSSheetal Tigadoli .num_words = 2048, 66*f29d1e0cSSheetal Tigadoli }; 67*f29d1e0cSSheetal Tigadoli 68*f29d1e0cSSheetal Tigadoli struct otpc_priv { 69*f29d1e0cSSheetal Tigadoli uint32_t base; 70*f29d1e0cSSheetal Tigadoli struct otpc_map *map; 71*f29d1e0cSSheetal Tigadoli int size; 72*f29d1e0cSSheetal Tigadoli int state; 73*f29d1e0cSSheetal Tigadoli }; 74*f29d1e0cSSheetal Tigadoli 75*f29d1e0cSSheetal Tigadoli struct otpc_priv otpc_info; 76*f29d1e0cSSheetal Tigadoli 77*f29d1e0cSSheetal Tigadoli static inline void set_command(uint32_t base, uint32_t command) 78*f29d1e0cSSheetal Tigadoli { 79*f29d1e0cSSheetal Tigadoli mmio_write_32(base + OTPC_COMMAND_OFFSET, command & OTPC_CMD_MASK); 80*f29d1e0cSSheetal Tigadoli } 81*f29d1e0cSSheetal Tigadoli 82*f29d1e0cSSheetal Tigadoli static inline void set_cpu_address(uint32_t base, uint32_t addr) 83*f29d1e0cSSheetal Tigadoli { 84*f29d1e0cSSheetal Tigadoli mmio_write_32(base + OTPC_CPUADDR_REG_OFFSET, addr & OTPC_ADDR_MASK); 85*f29d1e0cSSheetal Tigadoli } 86*f29d1e0cSSheetal Tigadoli 87*f29d1e0cSSheetal Tigadoli static inline void set_start_bit(uint32_t base) 88*f29d1e0cSSheetal Tigadoli { 89*f29d1e0cSSheetal Tigadoli mmio_write_32(base + OTPC_CMD_START_OFFSET, 1 << OTPC_CMD_START_START); 90*f29d1e0cSSheetal Tigadoli } 91*f29d1e0cSSheetal Tigadoli 92*f29d1e0cSSheetal Tigadoli static inline void reset_start_bit(uint32_t base) 93*f29d1e0cSSheetal Tigadoli { 94*f29d1e0cSSheetal Tigadoli mmio_write_32(base + OTPC_CMD_START_OFFSET, 0); 95*f29d1e0cSSheetal Tigadoli } 96*f29d1e0cSSheetal Tigadoli 97*f29d1e0cSSheetal Tigadoli static inline void write_cpu_data(uint32_t base, uint32_t value) 98*f29d1e0cSSheetal Tigadoli { 99*f29d1e0cSSheetal Tigadoli mmio_write_32(base + OTPC_CPU_WRITE_REG_OFFSET, value); 100*f29d1e0cSSheetal Tigadoli } 101*f29d1e0cSSheetal Tigadoli 102*f29d1e0cSSheetal Tigadoli static int poll_cpu_status(uint32_t base, uint32_t value) 103*f29d1e0cSSheetal Tigadoli { 104*f29d1e0cSSheetal Tigadoli uint32_t status; 105*f29d1e0cSSheetal Tigadoli uint32_t retries; 106*f29d1e0cSSheetal Tigadoli 107*f29d1e0cSSheetal Tigadoli for (retries = 0; retries < OTPC_RETRIES_US; retries++) { 108*f29d1e0cSSheetal Tigadoli status = mmio_read_32(base + OTPC_CPU_STATUS_OFFSET); 109*f29d1e0cSSheetal Tigadoli if (status & value) 110*f29d1e0cSSheetal Tigadoli break; 111*f29d1e0cSSheetal Tigadoli udelay(1); 112*f29d1e0cSSheetal Tigadoli } 113*f29d1e0cSSheetal Tigadoli if (retries == OTPC_RETRIES_US) 114*f29d1e0cSSheetal Tigadoli return -1; 115*f29d1e0cSSheetal Tigadoli 116*f29d1e0cSSheetal Tigadoli return 0; 117*f29d1e0cSSheetal Tigadoli } 118*f29d1e0cSSheetal Tigadoli 119*f29d1e0cSSheetal Tigadoli static int bcm_otpc_ecc(uint32_t enable) 120*f29d1e0cSSheetal Tigadoli { 121*f29d1e0cSSheetal Tigadoli struct otpc_priv *priv = &otpc_info; 122*f29d1e0cSSheetal Tigadoli int ret; 123*f29d1e0cSSheetal Tigadoli 124*f29d1e0cSSheetal Tigadoli set_command(priv->base, OTPC_CMD_ECC); 125*f29d1e0cSSheetal Tigadoli set_cpu_address(priv->base, OTPC_ECC_ADDR); 126*f29d1e0cSSheetal Tigadoli 127*f29d1e0cSSheetal Tigadoli if (!enable) 128*f29d1e0cSSheetal Tigadoli write_cpu_data(priv->base, OTPC_ECC_VAL); 129*f29d1e0cSSheetal Tigadoli else 130*f29d1e0cSSheetal Tigadoli write_cpu_data(priv->base, ~OTPC_ECC_VAL); 131*f29d1e0cSSheetal Tigadoli 132*f29d1e0cSSheetal Tigadoli set_start_bit(priv->base); 133*f29d1e0cSSheetal Tigadoli ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE); 134*f29d1e0cSSheetal Tigadoli if (ret) { 135*f29d1e0cSSheetal Tigadoli ERROR("otp ecc op error: 0x%x", ret); 136*f29d1e0cSSheetal Tigadoli return -1; 137*f29d1e0cSSheetal Tigadoli } 138*f29d1e0cSSheetal Tigadoli reset_start_bit(priv->base); 139*f29d1e0cSSheetal Tigadoli 140*f29d1e0cSSheetal Tigadoli return 0; 141*f29d1e0cSSheetal Tigadoli } 142*f29d1e0cSSheetal Tigadoli 143*f29d1e0cSSheetal Tigadoli /* 144*f29d1e0cSSheetal Tigadoli * bcm_otpc_read read otp data in the size of 8 byte rows. 145*f29d1e0cSSheetal Tigadoli * bytes has to be the multiple of 8. 146*f29d1e0cSSheetal Tigadoli * return -1 in error case, return read bytes in success. 147*f29d1e0cSSheetal Tigadoli */ 148*f29d1e0cSSheetal Tigadoli int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes, 149*f29d1e0cSSheetal Tigadoli uint32_t ecc_flag) 150*f29d1e0cSSheetal Tigadoli { 151*f29d1e0cSSheetal Tigadoli struct otpc_priv *priv = &otpc_info; 152*f29d1e0cSSheetal Tigadoli uint32_t *buf = val; 153*f29d1e0cSSheetal Tigadoli uint32_t bytes_read; 154*f29d1e0cSSheetal Tigadoli uint32_t address = offset / priv->map->word_size; 155*f29d1e0cSSheetal Tigadoli int i, ret; 156*f29d1e0cSSheetal Tigadoli 157*f29d1e0cSSheetal Tigadoli if (!priv->state) { 158*f29d1e0cSSheetal Tigadoli ERROR("OCOTP read failed\n"); 159*f29d1e0cSSheetal Tigadoli return -1; 160*f29d1e0cSSheetal Tigadoli } 161*f29d1e0cSSheetal Tigadoli 162*f29d1e0cSSheetal Tigadoli bcm_otpc_ecc(ecc_flag); 163*f29d1e0cSSheetal Tigadoli 164*f29d1e0cSSheetal Tigadoli for (bytes_read = 0; (bytes_read + priv->map->word_size) <= bytes;) { 165*f29d1e0cSSheetal Tigadoli set_command(priv->base, OTPC_CMD_READ); 166*f29d1e0cSSheetal Tigadoli set_cpu_address(priv->base, address++); 167*f29d1e0cSSheetal Tigadoli set_start_bit(priv->base); 168*f29d1e0cSSheetal Tigadoli ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE); 169*f29d1e0cSSheetal Tigadoli if (ret) { 170*f29d1e0cSSheetal Tigadoli ERROR("otp read error: 0x%x", ret); 171*f29d1e0cSSheetal Tigadoli return -1; 172*f29d1e0cSSheetal Tigadoli } 173*f29d1e0cSSheetal Tigadoli 174*f29d1e0cSSheetal Tigadoli for (i = 0; i < priv->map->otpc_row_size; i++) { 175*f29d1e0cSSheetal Tigadoli *buf++ = mmio_read_32(priv->base + 176*f29d1e0cSSheetal Tigadoli priv->map->data_r_offset[i]); 177*f29d1e0cSSheetal Tigadoli bytes_read += sizeof(*buf); 178*f29d1e0cSSheetal Tigadoli } 179*f29d1e0cSSheetal Tigadoli 180*f29d1e0cSSheetal Tigadoli reset_start_bit(priv->base); 181*f29d1e0cSSheetal Tigadoli } 182*f29d1e0cSSheetal Tigadoli 183*f29d1e0cSSheetal Tigadoli return bytes_read; 184*f29d1e0cSSheetal Tigadoli } 185*f29d1e0cSSheetal Tigadoli 186*f29d1e0cSSheetal Tigadoli int bcm_otpc_init(struct otpc_map *map) 187*f29d1e0cSSheetal Tigadoli { 188*f29d1e0cSSheetal Tigadoli struct otpc_priv *priv; 189*f29d1e0cSSheetal Tigadoli 190*f29d1e0cSSheetal Tigadoli priv = &otpc_info; 191*f29d1e0cSSheetal Tigadoli priv->base = ocotp_cfg.base; 192*f29d1e0cSSheetal Tigadoli priv->map = map; 193*f29d1e0cSSheetal Tigadoli 194*f29d1e0cSSheetal Tigadoli priv->size = 4 * ocotp_cfg.num_words; 195*f29d1e0cSSheetal Tigadoli 196*f29d1e0cSSheetal Tigadoli /* Enable CPU access to OTPC. */ 197*f29d1e0cSSheetal Tigadoli mmio_setbits_32(priv->base + OTPC_MODE_REG_OFFSET, 198*f29d1e0cSSheetal Tigadoli BIT(OTPC_MODE_REG_OTPC_MODE)); 199*f29d1e0cSSheetal Tigadoli reset_start_bit(priv->base); 200*f29d1e0cSSheetal Tigadoli priv->state = 1; 201*f29d1e0cSSheetal Tigadoli VERBOSE("OTPC Initialization done\n"); 202*f29d1e0cSSheetal Tigadoli 203*f29d1e0cSSheetal Tigadoli return 0; 204*f29d1e0cSSheetal Tigadoli } 205