]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/mcsdk-tools.git/blob - otp_writer/otp.c
Initial version of OTP Writer
[keystone-rtos/mcsdk-tools.git] / otp_writer / otp.c
1 /**
2  *   @file  otp.c
3  *
4  *   @brief   
5  *      This is the OTP driver file.
6  *
7  *  \par
8  *  ============================================================================
9  *  @n   (C) Copyright 2012, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
42 /* Standard includes */
43 #include <stdio.h>
44 #include <stdint.h>
46 /* OTP includes */
47 #include "otp.h"
48 #include "include/otp_pvt.h"
50 /**********************************************************************
51  ************************** Globals ***********************************
52  **********************************************************************/
54 /* OTP (EFUSE) control registers according to SPRS671B - TMS320TCI6614 Data Manual */
55 volatile Otp_ControlOverlay *otpControlRegs = (Otp_ControlOverlay *) 0x02522000;
57 /* Mapping of Key Mgr Keys to their respective rows in the fuseROMs.  There are two key
58   * Mgrs and 16 keys per Key Mgr */
59 const Uint16 otp_KeyMgrKeyToFuseRowMap[EFUSE_MAX_KEY_MGRS][EFUSE_MAX_KEYS_PER_MGR] = {{0x23, 0x27, 0x2B, 0x2F, 
60                                                                                       0x33, 0x37, 0x3B, 0x3F, 
61                                                                                       0x43, 0x47, 0x4B, 0x4F, 
62                                                                                       0x53, 0x57, 0x5B, 0x5F},
63                                                                                      {0x63, 0x06, 0x0A, 0x0E, 
64                                                                                       0x12, 0x16, 0x1A, 0x1E, 
65                                                                                       0x22, 0x26, 0x2A, 0x2E, 
66                                                                                       0x32, 0x36, 0x3A, 0x3E}};
68 /**********************************************************************
69  ********************** Internal Functions *********************************
70  **********************************************************************/
71 void Otp_delay (void)
72 {
73     Uint32 i;
75     for(i = 0; i < 100000; i++)
76     {
77         asm(" NOP 9 ");
78     }
79 }
81 Otp_Status Otp_checkForWriteError (Uint32 errorStatus)
82 {
83     Uint16 i;
84     Uint32 extractedErrorStatus = Otp_status_INSTRUCTION_SUCCESSFUL;
86     /* Return the first fuse chain error */
87     for (i = 0; i < EFUSE_ERROR_STATUS_NUM_FUSE_CHAINS; i++)
88     {
89         if (extractedErrorStatus = EFUSE_ERROR_STATUS_WRITE(errorStatus, i))
90         {
91             return ((Otp_Status) extractedErrorStatus);
92         }
93     }
95     /* If no error found return the extracedErrorStatus anyway, which will be instruction successful */
96     return ((Otp_Status) extractedErrorStatus);
97 }
99 Otp_Status Otp_checkForReadError (Uint32 errorStatus)
101     Uint16 i;
102     Uint32 extractedErrorStatus = Otp_status_INSTRUCTION_SUCCESSFUL;
104     /* Return the first fuse chain error */
105     for (i = 0; i < EFUSE_ERROR_STATUS_NUM_FUSE_CHAINS; i++)
106     {
107         if (extractedErrorStatus = EFUSE_ERROR_STATUS_READ(errorStatus, i))
108         {
109             return ((Otp_Status) extractedErrorStatus);
110         }
111     }
113     /* If no error found return the extracedErrorStatus anyway, which will be instruction successful */
114     return ((Otp_Status) extractedErrorStatus);
117 Otp_Status Otp_write (Uint32 *data, Uint16 size, Uint16 fuseRomBlock, 
118                                      Uint16 fuseRomRow, Otp_writeCfg *otpWrCfg)
120     Uint32 i;
121     Uint32 status;
122     Uint32 bitReversedData;
123     Uint32 rowAddress;
124     Uint32 readData;
126     /* Make sure if read protection is requested to be set that write protection is set as well */
127     if (otpWrCfg->readProtect && !otpWrCfg->writeProtect)
128     {
129         return (Otp_status_READ_PROTECT_WITHOUT_WRITE_PROTECT);
130     }
132     /* Configure the OTP registers for write/read */
134     /* Set key code which protects fuseROM during power-up */
135     otpControlRegs->otpKey= EFUSE_KEY_CODE;
136     /* Set the read data bit and the read pulse width */
137     otpControlRegs->otpRead = (EFUSE_CLOCK_READ_PULSE_WIDTH|EFUSE_READ_READ_DATA_BIT);
139     /* Perform the number of writes specified in the size parameter */
140     for(i = 0; i < size; i++)
141     {
142         /* Configure the eFuse control registers for write */
144         /* Clear the error status register before each write and read */
145         otpControlRegs->otpErrorStatus = 0x00000000;
147         /* Start with the specified eFuse row address and work backwards */
148         rowAddress = fuseRomRow-i;
150         /* Choose the fuseROM block based on the input parameter and set
151          * the address register */
152         if (fuseRomBlock == EFUSE_OTP_2_BLOCK)
153         {
154             rowAddress |= EFUSE_ADDRESS_FUSEROM_BLOCK_1;
155         }
156         otpControlRegs->otpAddress = rowAddress;
158 #if 1
159         /* TEST READ */
161         /* Clear the data lower register since the read data will be placed there */
162         otpControlRegs->otpDataLower = 0x00000000;
164         /* Set the program register for read adding in the write attempts */
165         otpControlRegs->otpProgram = (EFUSE_PROGRAM_READ_CONFIG |
166                                                        (otpWrCfg->maxWrAttempts << EFUSE_PROGRAM_WR_ATTEMPT_SHIFT));
167         /* Peform the read from the row address that was just written to */
168         otpControlRegs->otpInstructionDumpword = (EFUSE_INSTRUCTION_READ|rowAddress);
170         /* Allow time for the read to occur */
171         Otp_delay();
173         /* Check for an error during read.  Return if error occurred */
174         if (status = Otp_checkForReadError(otpControlRegs->otpErrorStatus))
175         {
176            return ((Otp_Status) status);
177         }
179         /* Compare the read data with what was originally written */
180         readData = _bitr(otpControlRegs->otpDataLower);
181         printf("read data %x\n", readData);
183         /* Clear the error status register before each write and read */
184         otpControlRegs->otpErrorStatus = 0x00000000;
185 #endif
187         /* Set the program register for write adding in the write attempts */
188         otpControlRegs->otpProgram = (EFUSE_PROGRAM_WRITE_CONFIG |
189                                                        (otpWrCfg->maxWrAttempts << EFUSE_PROGRAM_WR_ATTEMPT_SHIFT));
192         /* Configure the data upper and lower registers with the data and protection 
193          * settings.  Reverse the bit order of the data word to be written.  All eFuse chain bits
194          * are reversed */
195         bitReversedData = _bitr(data[i]);
196         otpControlRegs->otpDataLower = bitReversedData;
197         if (otpWrCfg->writeProtect && otpWrCfg->readProtect)
198         {
199             otpControlRegs->otpDataUpper = EFUSE_DATA_UPPER_NO_REP_WR_RD_PROT;
200         }
201         else if (otpWrCfg->writeProtect)
202         {
203             otpControlRegs->otpDataUpper = EFUSE_DATA_UPPER_NO_REP_WR_PROT;
204         }
205         else
206         {
207             otpControlRegs->otpDataUpper = 0x00000000;
208         }
210         /* Perform the write by writing the "write" command to the instruction register */
211         otpControlRegs->otpInstructionDumpword = EFUSE_INSTRUCTION_PROGRAM;
213         /* Allow time for the write to occur */
214         Otp_delay();
216         /* Check for an error during write.  Return if error occurred */
217         if (status = Otp_checkForWriteError(otpControlRegs->otpErrorStatus))
218         {
219             return ((Otp_Status) status);
220         }
222         /* Read back from the location to make sure the data was written */
224         /* Clear the error status register before each write and read */
225         otpControlRegs->otpErrorStatus = 0x00000000;
227         /* Clear the data lower register since the read data will be placed there */
228         otpControlRegs->otpDataLower = 0x00000000;
230         /* Set the program register for read adding in the write attempts */
231         otpControlRegs->otpProgram = (EFUSE_PROGRAM_READ_CONFIG |
232                                                        (otpWrCfg->maxWrAttempts << EFUSE_PROGRAM_WR_ATTEMPT_SHIFT));
233         /* Peform the read from the row address that was just written to */
234         otpControlRegs->otpInstructionDumpword = (EFUSE_INSTRUCTION_READ|rowAddress);
236         /* Allow time for the read to occur */
237         Otp_delay();
239         /* Check for an error during read.  Return if error occurred */
240         if (status = Otp_checkForReadError(otpControlRegs->otpErrorStatus))
241         {
242             return ((Otp_Status) status);
243         }
245         /* Compare the read data with what was originally written */
246         readData = _bitr(otpControlRegs->otpDataLower);
247         if (readData != data[i])
248         {
249             return(Otp_status_READ_DATA_NOT_SAME_AS_WRITTEN);
250         }
251     }
253     /* Clear the program register when all writes and reads are complete */
254     otpControlRegs->otpProgram = 0x00000000;
256     return (Otp_status_INSTRUCTION_SUCCESSFUL);
259 /**********************************************************************
260  *********************** Application visible APIs ***************************
261  **********************************************************************/
262 Otp_Status Otp_smekWrite (Uint32 *smekDataPtr, Otp_writeCfg *otpWrCfg)
264     return (Otp_write(smekDataPtr, OTP_SMEK_SIZE_32BIT_WORDS, EFUSE_SMEK_BLOCK,
265                                  EFUSE_SMEK_ROW, otpWrCfg));
268 Otp_Status Otp_smpkWrite (Uint32 *smpkDataPtr, Otp_writeCfg *otpWrCfg)
270     return (Otp_write(smpkDataPtr, OTP_SMPK_SIZE_32BIT_WORDS, EFUSE_SMPK_BLOCK,
271                                  EFUSE_SMPK_ROW, otpWrCfg));
274 Otp_Status Otp_otpWrite (Uint32 *otpDataPtr, Uint16 otpKeyMgr, Uint16 otpKey, 
275                                             Otp_writeCfg *otpWrCfg)
277     Uint16 otpKeyBlock;
278     Uint16 otpKeyRow = otp_KeyMgrKeyToFuseRowMap[otpKeyMgr][otpKey];
279     Otp_Status retVal;
281     if (EFUSE_OTP_KEY_CHECK(otpKeyMgr, otpKey))
282     {
283         return (Otp_status_KEY_MGR_OR_KEY_OUT_OF_RANGE);
284     }
286     /* All Key Mgr 0 keys are in fuseROM block 0, as well as Key Mgr 1, Key 0 */
287     if ((otpKeyMgr == 0) || ((otpKeyMgr == 1) && (otpKey == 0)))
288     {
289         /* Find the row for the key to be programmed */
290         otpKeyBlock = EFUSE_OTP_1_BLOCK;
291         return (Otp_write(otpDataPtr, EFUSE_OTP_SIZE_32BIT_WORDS, otpKeyBlock,
292                                      otpKeyRow, otpWrCfg));
293         
294     }
295     else if ((otpKeyMgr == 1) && (otpKey == 1))
296     {
297         /* Key Mgr 1, Key 1 is split between two fuseROM blocks.  Need to write half of the key to
298           * each block */
300         /* Write the second fuseROM block first */
301         otpKeyBlock = EFUSE_OTP_2_BLOCK;
302         if (retVal = Otp_write(&otpDataPtr[2], (EFUSE_OTP_SIZE_32BIT_WORDS/2), otpKeyBlock,
303                                otpKeyRow, otpWrCfg))
304         {
305           /* Error during first write */
306           return (retVal);
307         }
309         /* Complete the second half of the write.  Row should be last row in fuseROM 0 */
310         otpKeyBlock = EFUSE_OTP_1_BLOCK;
311         otpKeyRow = EFUSE_OTP_1_BASE_ROW;
312         return (Otp_write(otpDataPtr, (EFUSE_OTP_SIZE_32BIT_WORDS/2), otpKeyBlock,
313                                      otpKeyRow, otpWrCfg));
314     }
315     else
316     {
317         /* Handle remaining Keys in Key Mgr 1 */
318         otpKeyBlock = EFUSE_OTP_2_BLOCK;
319         return (Otp_write(otpDataPtr, EFUSE_OTP_SIZE_32BIT_WORDS, otpKeyBlock,
320                                      otpKeyRow, otpWrCfg));
321     }
325 Otp_Status Otp_otpSetPrivate (Uint16 otpKeyMgr, Uint16 otpKey, Otp_writeCfg *otpWrCfg)
327     Uint32 setPrivateVal = 0x00000000;
329     if (EFUSE_OTP_KEY_CHECK(otpKeyMgr, otpKey))
330     {
331         return (Otp_status_KEY_MGR_OR_KEY_OUT_OF_RANGE);
332     }
334     /* Form the value to write into the eFuse to set the private bit for the 
335       * OTP key specified.  Any bits that are 0 will not be reflected in the eFuse
336       * when the write occurs
337       *
338       * Bit 31 sets Key Mgr 1 - Key 15 to private
339       * Bit 30 sets Key Mgr 1 - Key 14 to private
340       * ...
341       * Bit 1 sets Key Mgr 0 - Key 1 to private
342       * Bit 0 sets Key Mgr 0 - Key 0 to private */
343     setPrivateVal = 0x1 << (otpKey << otpKeyMgr);
345     return (Otp_write(&setPrivateVal, EFUSE_PUBLIC_PRIVATE_ENABLE_SIZE_32BIT_WORDS,
346                                   EFUSE_PUBLIC_PRIVATE_ENABLE_BLOCK, EFUSE_PUBLIC_PRIVATE_ENABLE_ROW,
347                                   otpWrCfg));
348