From a8f7a59d60996e1efdc36a50e960bf122cefa855 Mon Sep 17 00:00:00 2001 From: Justin Sobota Date: Fri, 15 Jun 2012 16:41:39 -0400 Subject: [PATCH 1/1] Initial version of OTP Writer --- otp_writer/.ccsproject | 12 ++ otp_writer/.cproject | 144 ++++++++++++++ otp_writer/.project | 83 +++++++++ otp_writer/include/otp_pvt.h | 159 ++++++++++++++++ otp_writer/link.cmd | 37 ++++ otp_writer/main.c | 235 +++++++++++++++++++++++ otp_writer/otp.c | 350 +++++++++++++++++++++++++++++++++++ otp_writer/otp.h | 138 ++++++++++++++ 8 files changed, 1158 insertions(+) create mode 100644 otp_writer/.ccsproject create mode 100644 otp_writer/.cproject create mode 100644 otp_writer/.project create mode 100644 otp_writer/include/otp_pvt.h create mode 100644 otp_writer/link.cmd create mode 100644 otp_writer/main.c create mode 100644 otp_writer/otp.c create mode 100644 otp_writer/otp.h diff --git a/otp_writer/.ccsproject b/otp_writer/.ccsproject new file mode 100644 index 0000000..beca121 --- /dev/null +++ b/otp_writer/.ccsproject @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/otp_writer/.cproject b/otp_writer/.cproject new file mode 100644 index 0000000..0fa48c2 --- /dev/null +++ b/otp_writer/.cproject @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/otp_writer/.project b/otp_writer/.project new file mode 100644 index 0000000..e7c12de --- /dev/null +++ b/otp_writer/.project @@ -0,0 +1,83 @@ + + + OTP_Writer + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + -k + + + org.eclipse.cdt.make.core.buildCommand + ${CCS_UTILS_DIR}/bin/gmake + + + org.eclipse.cdt.make.core.buildLocation + ${BuildDirectory} + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + true + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + false + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + com.ti.ccstudio.core.ccsNature + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/otp_writer/include/otp_pvt.h b/otp_writer/include/otp_pvt.h new file mode 100644 index 0000000..6307272 --- /dev/null +++ b/otp_writer/include/otp_pvt.h @@ -0,0 +1,159 @@ +/* + * file otp_pvt.h + * + * Private API and data structures for OTP driver. + * + * ============================================================================ + * (C) Copyright 2012, Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \par +*/ + +#ifndef OTP_PVT_H_ +#define OTP_PVT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "otp.h" + +/* EFUSE defines */ +#define EFUSE_JTAG_BLOCK ((Uint16) 0) +#define EFUSE_JTAG_ROW ((Uint16) 0xA) +#define EFUSE_JTAG_SIZE_32BIT_WORDS ((Uint16) 1) +#define EFUSE_PUBLIC_PRIVATE_ENABLE_BLOCK ((Uint16) 0) +#define EFUSE_PUBLIC_PRIVATE_ENABLE_ROW ((Uint16) 0x9) +#define EFUSE_PUBLIC_PRIVATE_ENABLE_SIZE_32BIT_WORDS ((Uint16) 1) +#define EFUSE_SMEK_BLOCK ((Uint16) 0) +#define EFUSE_SMEK_ROW ((Uint16) 0x15) +#define EFUSE_SMPK_BLOCK ((Uint16) 0) +#define EFUSE_SMPK_ROW ((Uint16) 0x1F) +/* FuseROM 0 contains the first 17.5 OTP keys: Key Mgr 0, Key 0 - Key Mgr 1, Key 0 + * Half of Key Mgr 1, Key 1 is contained in FuseROM 0 and the other half in FurseROM 1 + * FuseROM 1 contains the last 14.5 keys: Key Mgr 1, Key 2 - Key Mgr 1, Key 15 */ +#define EFUSE_OTP_1_BLOCK ((Uint16) 0) +#define EFUSE_OTP_1_BASE_ROW ((Uint16) 0x65) /* Key Mgr 0, Key 0 - half of + * Key Mgr 1, Key 1 */ +#define EFUSE_OTP_2_BLOCK ((Uint16) 1) +#define EFUSE_OTP_2_BASE_ROW ((Uint16) 0x3E) /* half of Key Mgr 1, Key 1 - + * Key Mgr 1, Key 15 */ +#define EFUSE_OTP_SIZE_32BIT_WORDS ((Uint16) 4) /* 4 key words */ + +/* EFUSE JTAG defines */ +#define EFUSE_JTAG_OPEN ((Uint32) 0x00000000) +#define EFUSE_JTAG_PROTECTED ((Uint32) 0x00000001) +#define EFUSE_JTAG_DISABLED ((Uint32) 0x00000003) + +/* eFuse controller instructions */ +#define EFUSE_INSTRUCTION_NOOP ((Uint32) 0x00000000) +#define EFUSE_INSTRUCTION_READ ((Uint32) 0x04000000) +#define EFUSE_INSTRUCTION_PROGRAM ((Uint32) 0x07000000) + +/* eFuse Address register block defines */ +#define EFUSE_ADDRESS_FUSEROM_BLOCK_0 ((Uint32) 0x00000000) +#define EFUSE_ADDRESS_FUSEROM_BLOCK_1 ((Uint32) 0x00000800) + +/* eFuse key code */ +#define EFUSE_KEY_CODE ((Uint32) 0x96969696) + +/* eFuse data register upper defines */ +#define EFUSE_DATA_UPPER_NO_REP_NO_PROT ((Uint32) 0x00000000) +#define EFUSE_DATA_UPPER_NO_REP_WR_PROT ((Uint32) 0x00000001) +#define EFUSE_DATA_UPPER_NO_REP_WR_RD_PROT ((Uint32) 0x00000002) +#define EFUSE_DATA_UPPER_ROW_REP ((Uint32) 0x00000003) + +/* eFuse read register defines */ +#define EFUSE_READ_READ_DATA_BIT ((Uint32) 0x00000004) +#define EFUSE_CLOCK_READ_PULSE_WIDTH ((Uint32) 0x000000E0) /* Currently set to 14*sys_clk_period */ + +/* eFuse program register defines */ +/* Current program write configuration sets: + * Bits 10:0 - 113 (0x71) for the strobe pulse width + * Bits 14:11 - write iterations is cleared, will be OR'd in from write API parameter + * Bit 15 - program signal + * Bits 31:17 - 64 clock pulse stall width */ +#define EFUSE_PROGRAM_WRITE_CONFIG ((Uint32) 0x00808071) +/* Current program read configuration sets: + * Bits 10:0 - 14 (0x0E) for the strobe pulse width + * Bits 14:11 - write iterations is cleared, will be OR'd in from write API parameter + * Bit 15 - program signal + * Bits 31:17 - 64 clock pulse stall width */ +#define EFUSE_PROGRAM_READ_CONFIG ((Uint32) 0x0080800E) +#define EFUSE_PROGRAM_WR_ATTEMPT_SHIFT ((Uint16) 11) + +/* eFuse error status register defines */ +#define EFUSE_ERROR_STATUS_NUM_FUSE_CHAINS ((Uint16) 4) +#define EFUSE_ERROR_STATUS_MASK ((Uint32) 0x1F) /* all errors are 5 bits */ +/* Macro for extracting each fuse chain's status on a write operation. + * There are 8 bits between fuse chain error status fields */ +#define EFUSE_ERROR_STATUS_WRITE(errorStatus, fuseChain) ( \ + (errorStatus >> (fuseChain * 8)) & EFUSE_ERROR_STATUS_MASK) +/* Macro for extracting each fuse chain's status on a read operation. + * There are 6 bits between fuse chain error status fields */ +#define EFUSE_ERROR_STATUS_READ(errorStatus, fuseChain) ( \ + (errorStatus >> (fuseChain * 6)) & EFUSE_ERROR_STATUS_MASK) + +/* OTP Key Boundaries */ +#define EFUSE_MAX_KEY_MGRS 2 +#define EFUSE_MAX_KEYS_PER_MGR 16 + +#define EFUSE_OTP_KEY_CHECK(mgr, key) ((mgr >= EFUSE_MAX_KEY_MGRS) || \ + (key >= EFUSE_MAX_KEYS_PER_MGR)) + +/* OTP control register overlay structure */ +typedef struct { + Uint32 otpSysStatus_Instruction; + Uint32 otpInstructionDumpword; + Uint32 otpAddress; + Uint32 otpDataLower; + Uint32 otpSysConfig; + Uint32 otpDataUpper; + Uint32 otpAccumulator; + Uint32 otpBoundary; + Uint32 otpKeyFlag; + Uint32 otpKey; + Uint32 otpRelease; + Uint32 otpPins; + Uint32 otpCra; + Uint32 otpRead; + Uint32 otpProgram; + Uint32 otpErrorStatus; +} Otp_ControlOverlay; + +Otp_Status Otp_write (Uint32 *data, Uint16 size, Uint16 fuseRomBlock, + Uint16 fuseRomRow, Otp_writeCfg *otpWrCfg); + +#ifdef __cplusplus +} +#endif + +#endif /* OTP_PVT_H_ */ diff --git a/otp_writer/link.cmd b/otp_writer/link.cmd new file mode 100644 index 0000000..dae336b --- /dev/null +++ b/otp_writer/link.cmd @@ -0,0 +1,37 @@ + +--args 0x0 +-heap 0x0 +-stack 0x1000 + +MEMORY +{ + L2SRAM (RWX) : org = 0x800000, len = 0x100000 + MSMCSRAM (RWX) : org = 0xc000000, len = 0x200000 + DDR3 : org = 0xa0000000, len = 0x20000000 +} + +SECTIONS +{ + .text: load >> L2SRAM + .ti.decompress: load > L2SRAM + .stack: load > L2SRAM + GROUP: load > L2SRAM + { + .bss: + .neardata: + .rodata: + } + .cinit: load > L2SRAM + .pinit: load >> L2SRAM + .init_array: load > L2SRAM + .const: load >> L2SRAM + .data: load >> L2SRAM + .fardata: load >> L2SRAM + .switch: load >> L2SRAM + .sysmem: load > L2SRAM + .far: load >> L2SRAM + .args: load > L2SRAM align = 0x4, fill = 0 {_argsize = 0x0; } + .cio: load >> L2SRAM + .ti.handler_table: load > L2SRAM + .testtoc: load >> MSMCSRAM +} diff --git a/otp_writer/main.c b/otp_writer/main.c new file mode 100644 index 0000000..9abae77 --- /dev/null +++ b/otp_writer/main.c @@ -0,0 +1,235 @@ +/** + * @file main.c + * + * @brief + * OTP Writer main. Used to unlock JTAG and write customer SMEK and SMPK keys + * to the EFUSE. + * + * \par + * ============================================================================ + * @n (C) Copyright 2012, Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \par +*/ + +/* Standard includes */ +#include +#include + +/* CSL types */ +#include + +/* OTP includes */ +#include "otp.h" + +extern Uint32 dataArr_smpk[]; +extern Uint32 dataArr_smek[]; + +/* TOC Header Defines */ +#define TOC_HEADER_ADDRESS ((Uint32) 0x0C000000) +#define TOC_HEADER_IMAGE_SIZE_FIELD ((Uint32) 4) +#define TOC_HEADER_RESERVED_FIELD ((Uint32) 8) +#define TOC_HEADER_LOAD_ADDR_FIELD ((Uint32) 16) +#define TOC_HEADER_STRING_FIELD ((Uint32) 20) + +/* Key File Defines */ +#define KEY_FILE_ID_JTAG ((Uint32) 0x00000001) +#define KEY_FILE_ID_SMEK ((Uint32) 0x00000002) +#define KEY_FILE_ID_SMPK ((Uint32) 0x00000003) + +#define KEY_FILE_OPEN_JTAG ((Uint32) 0x00000001) + +/* JTAG unlock address */ +#define SEC_TAP_EN *((volatile unsigned int *)0x02500028) + +void main (void) +{ + Uint32 *tocHdrPtr = &testTocHeader[0]; /* (Uint32 *) TOC_HEADER_ADDRESS; */ + Char *tocHdrStrPtr; + Char *tocHdrName = "2ND"; + Uint32 *tocHdrResFields = tocHdrPtr + (TOC_HEADER_RESERVED_FIELD/4); + Uint32 *keyFilePtr; + Uint32 keyFileSizeBytes; + Uint32 keyFileEndAddr; + Otp_writeCfg otpWrCfg; + Otp_Status otpStatus; + + /* Image data load address (4th 32-bit word) */ + if (*(tocHdrPtr + (TOC_HEADER_LOAD_ADDR_FIELD/4))) + { + /* Return if the load address field of the image data is populated. When the + * load address field is populated an image is to be run. Keys are not supposed + * to be written */ + return; + } + + /* Assign the TOC header string pointer to the first string section in the + * TOC header (5th 32-bit word) */ + tocHdrStrPtr = (Char *) (TOC_HEADER_ADDRESS + TOC_HEADER_STRING_FIELD); + + /* Return if "2ND" string is not in the TOC header */ + if (strncmp(tocHdrStrPtr, tocHdrName, 3)) + { + return; + } + + /* Key file offset is first entry in TOC header (1st 32-bit word) */ + /* Initialize to start of TOC header prior to adding offset and + * add offset from TOC header */ + keyFilePtr = (Uint32 *) (TOC_HEADER_ADDRESS + *tocHdrPtr); + + /* Key file size is second entry in TOC header (2nd 32-bit word) */ + tocHdrPtr++; + keyFileSizeBytes = *tocHdrPtr; + + if ((keyFileSizeBytes % 4) != 0) + { + /* Key file should be multiple of four bytes */ + return; + } + + /* Get end of Key File for parsing */ + keyFileEndAddr = (Uint32) keyFilePtr + keyFileSizeBytes; + + /* Parse key file and program keys */ + while (((Uint32) keyFilePtr) != keyFileEndAddr) + { + /* Clear the OTP status */ + otpStatus = Otp_status_INSTRUCTION_SUCCESSFUL; + + if (*keyFilePtr == KEY_FILE_ID_JTAG) + { + /* Check length */ + keyFilePtr++; + if ((*keyFilePtr) != 0x1) + { + /* Should only be 1 byte for JTAG command */ + return; + } + + /* Get JTAG command */ + keyFilePtr++; + if ((*keyFilePtr) == KEY_FILE_OPEN_JTAG) + { + /* Allow emulation access */ + SEC_TAP_EN = 0xffffffff; + + /* Also allow ARM debug access */ + *((unsigned int *)0x2620630) = 0x1fff; + } + + /* Go to next Key File entry */ + keyFilePtr++; + } + else if ((*keyFilePtr) == KEY_FILE_ID_SMEK) + { + /* Check length */ + keyFilePtr++; + if ((*keyFilePtr) != (OTP_SMEK_SIZE_32BIT_WORDS * 4)) + { + /* WIPE IF ERROR?! */ + + /* SMEK should be 20 bytes total - 4 bytes ECC + 16 data bytes */ + return; + } + + /* Send the data to the OTP driver */ + keyFilePtr++; + /* FOR TESTING DO NOT WRITE OR READ PROTECT */ +#if 0 + otpWrCfg.maxWrAttempts = 7; + otpWrCfg.writeProtect = 0; + otpWrCfg.readProtect = 0; + otpStatus = Otp_smekWrite (&keyFilePtr[0], &otpWrCfg); +#endif + /* Use first of reserved fields to return SMEK status to Host */ + *tocHdrResFields = (Uint32) otpStatus; + + /* Wipe SMEK out of memory */ + memset((void *)&keyFilePtr[0], 0, (OTP_SMEK_SIZE_32BIT_WORDS * 4)); + + /* Go to next Key File entry */ + keyFilePtr += OTP_SMEK_SIZE_32BIT_WORDS; + } + else if ((*keyFilePtr) == KEY_FILE_ID_SMPK) + { + /* Check length */ + keyFilePtr++; + if ((*keyFilePtr) != (OTP_SMPK_SIZE_32BIT_WORDS * 4)) + { + /* WIPE IF ERROR?! */ + + /* SMPK should be 40 bytes total - 8 bytes ECC + 32 data bytes */ + return; + } + + /* Send the data to the OTP driver */ + keyFilePtr++; + /* FOR TESTING DO NOT WRITE OR READ PROTECT */ +#if 0 + otpWrCfg.maxWrAttempts = 7; + otpWrCfg.writeProtect = 0; + otpWrCfg.readProtect = 0; + otpStatus = Otp_smpkWrite (&keyFilePtr[0], &otpWrCfg); +#endif + /* Use second of reserved fields to return SMEK status to Host */ + tocHdrResFields++; + *tocHdrResFields = (Uint32) otpStatus; + + /* Wipe SMPK out of memory */ + memset((void *)&keyFilePtr[0], 0, (OTP_SMPK_SIZE_32BIT_WORDS * 4)); + + /* Go to next Key File entry */ + keyFilePtr += OTP_SMPK_SIZE_32BIT_WORDS; + } + else + { + /* Skip any other types */ + Uint32 keyFileEntrySizeWords; + + /* Get entry size and round up to nearest 32-bit word */ + keyFilePtr++; + keyFileEntrySizeWords = (*keyFilePtr) / 4; + if (((*keyFilePtr) % 4) != 0) + { + keyFileEntrySizeWords++; + } + + /* Jump to next Key File entry */ + keyFilePtr++; + keyFilePtr += keyFileEntrySizeWords; + } + } + + + for (;;){} + +} diff --git a/otp_writer/otp.c b/otp_writer/otp.c new file mode 100644 index 0000000..974ae57 --- /dev/null +++ b/otp_writer/otp.c @@ -0,0 +1,350 @@ +/** + * @file otp.c + * + * @brief + * This is the OTP driver file. + * + * \par + * ============================================================================ + * @n (C) Copyright 2012, Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \par +*/ + +/* Standard includes */ +#include +#include + +/* OTP includes */ +#include "otp.h" +#include "include/otp_pvt.h" + +/********************************************************************** + ************************** Globals *********************************** + **********************************************************************/ + +/* OTP (EFUSE) control registers according to SPRS671B - TMS320TCI6614 Data Manual */ +volatile Otp_ControlOverlay *otpControlRegs = (Otp_ControlOverlay *) 0x02522000; + +/* Mapping of Key Mgr Keys to their respective rows in the fuseROMs. There are two key + * Mgrs and 16 keys per Key Mgr */ +const Uint16 otp_KeyMgrKeyToFuseRowMap[EFUSE_MAX_KEY_MGRS][EFUSE_MAX_KEYS_PER_MGR] = {{0x23, 0x27, 0x2B, 0x2F, + 0x33, 0x37, 0x3B, 0x3F, + 0x43, 0x47, 0x4B, 0x4F, + 0x53, 0x57, 0x5B, 0x5F}, + {0x63, 0x06, 0x0A, 0x0E, + 0x12, 0x16, 0x1A, 0x1E, + 0x22, 0x26, 0x2A, 0x2E, + 0x32, 0x36, 0x3A, 0x3E}}; + +/********************************************************************** + ********************** Internal Functions ********************************* + **********************************************************************/ +void Otp_delay (void) +{ + Uint32 i; + + for(i = 0; i < 100000; i++) + { + asm(" NOP 9 "); + } +} + +Otp_Status Otp_checkForWriteError (Uint32 errorStatus) +{ + Uint16 i; + Uint32 extractedErrorStatus = Otp_status_INSTRUCTION_SUCCESSFUL; + + /* Return the first fuse chain error */ + for (i = 0; i < EFUSE_ERROR_STATUS_NUM_FUSE_CHAINS; i++) + { + if (extractedErrorStatus = EFUSE_ERROR_STATUS_WRITE(errorStatus, i)) + { + return ((Otp_Status) extractedErrorStatus); + } + } + + /* If no error found return the extracedErrorStatus anyway, which will be instruction successful */ + return ((Otp_Status) extractedErrorStatus); +} + +Otp_Status Otp_checkForReadError (Uint32 errorStatus) +{ + Uint16 i; + Uint32 extractedErrorStatus = Otp_status_INSTRUCTION_SUCCESSFUL; + + /* Return the first fuse chain error */ + for (i = 0; i < EFUSE_ERROR_STATUS_NUM_FUSE_CHAINS; i++) + { + if (extractedErrorStatus = EFUSE_ERROR_STATUS_READ(errorStatus, i)) + { + return ((Otp_Status) extractedErrorStatus); + } + } + + /* If no error found return the extracedErrorStatus anyway, which will be instruction successful */ + return ((Otp_Status) extractedErrorStatus); +} + +Otp_Status Otp_write (Uint32 *data, Uint16 size, Uint16 fuseRomBlock, + Uint16 fuseRomRow, Otp_writeCfg *otpWrCfg) +{ + Uint32 i; + Uint32 status; + Uint32 bitReversedData; + Uint32 rowAddress; + Uint32 readData; + + /* Make sure if read protection is requested to be set that write protection is set as well */ + if (otpWrCfg->readProtect && !otpWrCfg->writeProtect) + { + return (Otp_status_READ_PROTECT_WITHOUT_WRITE_PROTECT); + } + + /* Configure the OTP registers for write/read */ + + /* Set key code which protects fuseROM during power-up */ + otpControlRegs->otpKey= EFUSE_KEY_CODE; + /* Set the read data bit and the read pulse width */ + otpControlRegs->otpRead = (EFUSE_CLOCK_READ_PULSE_WIDTH|EFUSE_READ_READ_DATA_BIT); + + /* Perform the number of writes specified in the size parameter */ + for(i = 0; i < size; i++) + { + /* Configure the eFuse control registers for write */ + + /* Clear the error status register before each write and read */ + otpControlRegs->otpErrorStatus = 0x00000000; + + /* Start with the specified eFuse row address and work backwards */ + rowAddress = fuseRomRow-i; + + /* Choose the fuseROM block based on the input parameter and set + * the address register */ + if (fuseRomBlock == EFUSE_OTP_2_BLOCK) + { + rowAddress |= EFUSE_ADDRESS_FUSEROM_BLOCK_1; + } + otpControlRegs->otpAddress = rowAddress; + +#if 1 + /* TEST READ */ + + /* Clear the data lower register since the read data will be placed there */ + otpControlRegs->otpDataLower = 0x00000000; + + /* Set the program register for read adding in the write attempts */ + otpControlRegs->otpProgram = (EFUSE_PROGRAM_READ_CONFIG | + (otpWrCfg->maxWrAttempts << EFUSE_PROGRAM_WR_ATTEMPT_SHIFT)); + /* Peform the read from the row address that was just written to */ + otpControlRegs->otpInstructionDumpword = (EFUSE_INSTRUCTION_READ|rowAddress); + + /* Allow time for the read to occur */ + Otp_delay(); + + /* Check for an error during read. Return if error occurred */ + if (status = Otp_checkForReadError(otpControlRegs->otpErrorStatus)) + { + return ((Otp_Status) status); + } + + /* Compare the read data with what was originally written */ + readData = _bitr(otpControlRegs->otpDataLower); + printf("read data %x\n", readData); + + /* Clear the error status register before each write and read */ + otpControlRegs->otpErrorStatus = 0x00000000; +#endif + + /* Set the program register for write adding in the write attempts */ + otpControlRegs->otpProgram = (EFUSE_PROGRAM_WRITE_CONFIG | + (otpWrCfg->maxWrAttempts << EFUSE_PROGRAM_WR_ATTEMPT_SHIFT)); + + + /* Configure the data upper and lower registers with the data and protection + * settings. Reverse the bit order of the data word to be written. All eFuse chain bits + * are reversed */ + bitReversedData = _bitr(data[i]); + otpControlRegs->otpDataLower = bitReversedData; + if (otpWrCfg->writeProtect && otpWrCfg->readProtect) + { + otpControlRegs->otpDataUpper = EFUSE_DATA_UPPER_NO_REP_WR_RD_PROT; + } + else if (otpWrCfg->writeProtect) + { + otpControlRegs->otpDataUpper = EFUSE_DATA_UPPER_NO_REP_WR_PROT; + } + else + { + otpControlRegs->otpDataUpper = 0x00000000; + } + + /* Perform the write by writing the "write" command to the instruction register */ + otpControlRegs->otpInstructionDumpword = EFUSE_INSTRUCTION_PROGRAM; + + /* Allow time for the write to occur */ + Otp_delay(); + + /* Check for an error during write. Return if error occurred */ + if (status = Otp_checkForWriteError(otpControlRegs->otpErrorStatus)) + { + return ((Otp_Status) status); + } + + /* Read back from the location to make sure the data was written */ + + /* Clear the error status register before each write and read */ + otpControlRegs->otpErrorStatus = 0x00000000; + + /* Clear the data lower register since the read data will be placed there */ + otpControlRegs->otpDataLower = 0x00000000; + + /* Set the program register for read adding in the write attempts */ + otpControlRegs->otpProgram = (EFUSE_PROGRAM_READ_CONFIG | + (otpWrCfg->maxWrAttempts << EFUSE_PROGRAM_WR_ATTEMPT_SHIFT)); + /* Peform the read from the row address that was just written to */ + otpControlRegs->otpInstructionDumpword = (EFUSE_INSTRUCTION_READ|rowAddress); + + /* Allow time for the read to occur */ + Otp_delay(); + + /* Check for an error during read. Return if error occurred */ + if (status = Otp_checkForReadError(otpControlRegs->otpErrorStatus)) + { + return ((Otp_Status) status); + } + + /* Compare the read data with what was originally written */ + readData = _bitr(otpControlRegs->otpDataLower); + if (readData != data[i]) + { + return(Otp_status_READ_DATA_NOT_SAME_AS_WRITTEN); + } + } + + /* Clear the program register when all writes and reads are complete */ + otpControlRegs->otpProgram = 0x00000000; + + return (Otp_status_INSTRUCTION_SUCCESSFUL); +} + +/********************************************************************** + *********************** Application visible APIs *************************** + **********************************************************************/ +Otp_Status Otp_smekWrite (Uint32 *smekDataPtr, Otp_writeCfg *otpWrCfg) +{ + return (Otp_write(smekDataPtr, OTP_SMEK_SIZE_32BIT_WORDS, EFUSE_SMEK_BLOCK, + EFUSE_SMEK_ROW, otpWrCfg)); +} + +Otp_Status Otp_smpkWrite (Uint32 *smpkDataPtr, Otp_writeCfg *otpWrCfg) +{ + return (Otp_write(smpkDataPtr, OTP_SMPK_SIZE_32BIT_WORDS, EFUSE_SMPK_BLOCK, + EFUSE_SMPK_ROW, otpWrCfg)); +} + +Otp_Status Otp_otpWrite (Uint32 *otpDataPtr, Uint16 otpKeyMgr, Uint16 otpKey, + Otp_writeCfg *otpWrCfg) +{ + Uint16 otpKeyBlock; + Uint16 otpKeyRow = otp_KeyMgrKeyToFuseRowMap[otpKeyMgr][otpKey]; + Otp_Status retVal; + + if (EFUSE_OTP_KEY_CHECK(otpKeyMgr, otpKey)) + { + return (Otp_status_KEY_MGR_OR_KEY_OUT_OF_RANGE); + } + + /* All Key Mgr 0 keys are in fuseROM block 0, as well as Key Mgr 1, Key 0 */ + if ((otpKeyMgr == 0) || ((otpKeyMgr == 1) && (otpKey == 0))) + { + /* Find the row for the key to be programmed */ + otpKeyBlock = EFUSE_OTP_1_BLOCK; + return (Otp_write(otpDataPtr, EFUSE_OTP_SIZE_32BIT_WORDS, otpKeyBlock, + otpKeyRow, otpWrCfg)); + + } + else if ((otpKeyMgr == 1) && (otpKey == 1)) + { + /* Key Mgr 1, Key 1 is split between two fuseROM blocks. Need to write half of the key to + * each block */ + + /* Write the second fuseROM block first */ + otpKeyBlock = EFUSE_OTP_2_BLOCK; + if (retVal = Otp_write(&otpDataPtr[2], (EFUSE_OTP_SIZE_32BIT_WORDS/2), otpKeyBlock, + otpKeyRow, otpWrCfg)) + { + /* Error during first write */ + return (retVal); + } + + /* Complete the second half of the write. Row should be last row in fuseROM 0 */ + otpKeyBlock = EFUSE_OTP_1_BLOCK; + otpKeyRow = EFUSE_OTP_1_BASE_ROW; + return (Otp_write(otpDataPtr, (EFUSE_OTP_SIZE_32BIT_WORDS/2), otpKeyBlock, + otpKeyRow, otpWrCfg)); + } + else + { + /* Handle remaining Keys in Key Mgr 1 */ + otpKeyBlock = EFUSE_OTP_2_BLOCK; + return (Otp_write(otpDataPtr, EFUSE_OTP_SIZE_32BIT_WORDS, otpKeyBlock, + otpKeyRow, otpWrCfg)); + } +} + + +Otp_Status Otp_otpSetPrivate (Uint16 otpKeyMgr, Uint16 otpKey, Otp_writeCfg *otpWrCfg) +{ + Uint32 setPrivateVal = 0x00000000; + + if (EFUSE_OTP_KEY_CHECK(otpKeyMgr, otpKey)) + { + return (Otp_status_KEY_MGR_OR_KEY_OUT_OF_RANGE); + } + + /* Form the value to write into the eFuse to set the private bit for the + * OTP key specified. Any bits that are 0 will not be reflected in the eFuse + * when the write occurs + * + * Bit 31 sets Key Mgr 1 - Key 15 to private + * Bit 30 sets Key Mgr 1 - Key 14 to private + * ... + * Bit 1 sets Key Mgr 0 - Key 1 to private + * Bit 0 sets Key Mgr 0 - Key 0 to private */ + setPrivateVal = 0x1 << (otpKey << otpKeyMgr); + + return (Otp_write(&setPrivateVal, EFUSE_PUBLIC_PRIVATE_ENABLE_SIZE_32BIT_WORDS, + EFUSE_PUBLIC_PRIVATE_ENABLE_BLOCK, EFUSE_PUBLIC_PRIVATE_ENABLE_ROW, + otpWrCfg)); + +} + diff --git a/otp_writer/otp.h b/otp_writer/otp.h new file mode 100644 index 0000000..185b88e --- /dev/null +++ b/otp_writer/otp.h @@ -0,0 +1,138 @@ +/* + * file otp.h + * + * API and data structures for OTP driver. + * + * ============================================================================ + * (C) Copyright 2012, Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \par +*/ + +#ifndef OTP_H_ +#define OTP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* SMEK, SMPK Defines */ +#define OTP_SMEK_SIZE_32BIT_WORDS ((Uint16) 5) /* 4 key words + 1 ECC word */ +#define OTP_SMPK_SIZE_32BIT_WORDS ((Uint16) 10) /* 8 hash words + 2 ECC words */ + +/* eFuse Programming defines */ +#define OTP_MAX_WRITE_ATTEMPTS ((Uint16) 0xF) + +/* OTP status */ +typedef enum { + /* EFUSE return codes */ + + /** No error - Instruction completed successfully */ + Otp_status_INSTRUCTION_SUCCESSFUL = 0, + /** Error: Time-out */ + Otp_status_TIMEOUT = 1, + /** Error: Autoload - Not enough data to fill scan chain */ + Otp_status_AUTOLOAD_NOT_ENOUGH_DATA = 2, + /** Error: Autoload - Wrong signature */ + Otp_status_AUTOLOAD_WRONG_SIGNATURE = 3, + /** Error: Autoload or program operation interrupted */ + Otp_status_PROGRAM_INTERRUPTION = 4, + + /** Value of 5 not used */ + + /** Error: Write protection bit is set */ + Otp_status_WRITE_PROTECT_SET = 6, + /** Error: Exceeded max write attempts allowed */ + Otp_status_EXCEEDED_MAX_WR_ATTEMPTS = 7, + /** Error: Exceeded max control bit write attempts allowed */ + Otp_status_EXCEEDED_MAX_CNTRL_BIT_WR_ATTEMPTS = 8, + /** Error: Some found to be set by test unprogrammed instruction */ + Otp_status_TEST_RAW_SOME_BIT_SET = 9, + + /** Value of 10 not used */ + + /** Error: Exceeded max CRA write attempts allowed */ + Otp_status_EXCEEDED_MAX_CRA_WR_ATTEMTPS = 11, + /** Error: Address previously programmed with same data */ + Otp_status_ADDRESS_PROGRAMMED_WITH_SAME_DATA = 12, + /** Inform: Program_compare_disable set when programming. */ + Otp_status_PROGRAM_COMP_DISABLE_SET_DURING_WR = 13, + /** Error: Program aborted due to no row repair but repair bit set */ + Otp_status_ABORT_PROGRAM_INVALID_ROW_REPAIR = 14, + /** Error: Program instruction executed with improper key value */ + Otp_status_IMPROPER_KEY_VALUE = 15, + + /** Values of 16 and 17 not used */ + + /** Error: Autoload operation incomplete */ + Otp_status_INCOMPLETE_AUTOLOAD = 18, + /** Error: Autoload last row stuck */ + Otp_status_AUTOLOAD_LAST_ROW_STUCK = 19, + + /* OTP Driver error codes */ + + /** Error: The Key Mgr or Key specified is out of the hardware's range */ + Otp_status_KEY_MGR_OR_KEY_OUT_OF_RANGE = 20, + /** Error: A read protect on a row was attempted without write protect being + * set as well */ + Otp_status_READ_PROTECT_WITHOUT_WRITE_PROTECT = 21, + /** Error: Data read from eFuse just after write was not the same. Write error */ + Otp_status_READ_DATA_NOT_SAME_AS_WRITTEN = 22 +} Otp_Status; + +typedef struct +{ + Uint16 maxWrAttempts; + /* Once writeProtect is set no further private bit settings can occur. + * readProtect cannot be set without writeProtect. An error will be returned if this is attempted */ + Bool writeProtect; + Bool readProtect; +} Otp_writeCfg; + +/* SMEK APIs */ +extern Otp_Status Otp_smekWrite (Uint32 *smekDataPtr, Otp_writeCfg *otpWrCfg); + +/* SMPK APIs */ +extern Otp_Status Otp_smpkWrite (Uint32 *smpkDataPtr, Otp_writeCfg *otpWrCfg); + +/* OTP APIs */ +extern Otp_Status Otp_otpWrite (Uint32 *otpDataPtr, Uint16 otpKeyMgr, Uint16 otpKey, + Otp_writeCfg *otpWrCfg); +extern Otp_Status Otp_otpSetPrivate (Uint16 otpKeyMgr, Uint16 otpKey, Otp_writeCfg *otpWrCfg); + +#ifdef __cplusplus +} +#endif + +#endif /* OTP_H_ */ + -- 2.39.2