github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/ocotp/ocotp.go (about) 1 // NXP i.MX6 On-Chip OTP Controller (OCOTP_CTRL) driver 2 // https://github.com/usbarmory/tamago 3 // 4 // Copyright (c) WithSecure Corporation 5 // https://foundry.withsecure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 // Package ocotp implements a driver for the NXP On-Chip OTP Controller 11 // (OCOTP_CTRL), which provides an interface to on-chip fuses for read/write 12 // operation, adopting the following reference specifications: 13 // - IMX6ULLRM - i.MX 6ULL Applications Processor Reference Manual - Rev 1 2017/11 14 // 15 // WARNING: Fusing SoC OTPs is an **irreversible** action that permanently 16 // fuses values on the device. This means that any errors in the process, or 17 // lost fused data such as cryptographic key material, might result in a 18 // **bricked** device. 19 // 20 // The use of this package is therefore **at your own risk**. 21 // 22 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 23 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 24 // https://github.com/usbarmory/tamago. 25 package ocotp 26 27 import ( 28 "errors" 29 "sync" 30 "time" 31 32 "github.com/usbarmory/tamago/internal/reg" 33 ) 34 35 // OCOTP registers 36 // (p2388, 37.5 OCOTP Memory Map/Register Definition, IMX6ULLRM). 37 const ( 38 OCOTP_CTRL = 0x0000 39 CTRL_WRUNLOCK = 16 40 CTRL_RELOAD_SHADOWS = 10 41 CTRL_ERROR = 9 42 CTRL_BUSY = 8 43 CTRL_ADDR = 0 44 45 OCOTP_CTRL_CLR = 0x0008 46 OCOTP_DATA = 0x0020 47 ) 48 49 // Configuration constants 50 const ( 51 // WordSize represents the number of bytes per OTP word. 52 WordSize = 4 53 // BankSize represents the number of words per OTP bank. 54 BankSize = 8 55 // Timeout is the default timeout for OCOTP operations. 56 Timeout = 10 * time.Millisecond 57 ) 58 59 type OCOTP struct { 60 sync.Mutex 61 62 // Base register 63 Base uint32 64 // Bank base register (bank 0, word 0) 65 BankBase uint32 66 // Banks size 67 Banks int 68 // Clock gate register 69 CCGR uint32 70 // Clock gate 71 CG int 72 // Timeout for OCOTP controller operations 73 Timeout time.Duration 74 75 // control registers 76 ctrl uint32 77 ctrl_clr uint32 78 data uint32 79 } 80 81 // Init initializes the OCOTP controller instance. 82 func (hw *OCOTP) Init() { 83 hw.Lock() 84 defer hw.Unlock() 85 86 if hw.Base == 0 || hw.BankBase == 0 || hw.CCGR == 0 { 87 panic("invalid OCOTP instance") 88 } 89 90 if hw.Timeout == 0 { 91 hw.Timeout = Timeout 92 } 93 94 hw.ctrl = hw.Base + OCOTP_CTRL 95 hw.ctrl_clr = hw.Base + OCOTP_CTRL_CLR 96 hw.data = hw.Base + OCOTP_DATA 97 98 // enable clock 99 reg.SetN(hw.CCGR, hw.CG, 0b11, 0b11) 100 } 101 102 // Read returns the value in the argument bank and word location. 103 func (hw *OCOTP) Read(bank int, word int) (value uint32, err error) { 104 if bank > hw.Banks || word > BankSize { 105 return 0, errors.New("invalid argument") 106 } 107 108 // Within the shadow register address map the addresses are spaced 0x10 109 // apart. 110 offset := 0x10 * uint32(BankSize*bank+word) 111 112 // Account for the gap in shadow registers address map between bank 5 113 // and bank 6. 114 if bank > 5 { 115 offset += 0x100 116 } 117 118 hw.Lock() 119 defer hw.Unlock() 120 121 value = reg.Read(hw.BankBase + offset) 122 123 return 124 } 125 126 // Blow fuses a value in the argument bank and word location. 127 // (p2384, 37.3.1.3 Fuse and Shadow Register Writes, IMX6ULLRM). 128 // 129 // WARNING: Fusing SoC OTPs is an **irreversible** action that permanently 130 // fuses values on the device. This means that any errors in the process, or 131 // lost fused data such as cryptographic key material, might result in a 132 // **bricked** device. 133 // 134 // The use of this function is therefore **at your own risk**. 135 func (hw *OCOTP) Blow(bank int, word int, value uint32) (err error) { 136 hw.Lock() 137 defer hw.Unlock() 138 139 if !reg.WaitFor(hw.Timeout, hw.ctrl, CTRL_BUSY, 1, 0) { 140 return errors.New("OCOTP controller busy") 141 } 142 143 // We do not configure the OCOTP_TIMING register. Timings depend on 144 // IPG_CLK_ROOT frequency. Default values work for default frequency of 145 // 66 MHz. 146 147 // p2393, OCOTP_CTRLn field descriptions, IMX6ULLRM 148 149 // clear error bit 150 reg.Set(hw.ctrl_clr, CTRL_ERROR) 151 // set OTP write register 152 reg.SetN(hw.ctrl, CTRL_ADDR, 0x7f, uint32(BankSize*bank+word)) 153 // enable OTP write access 154 reg.SetN(hw.ctrl, CTRL_WRUNLOCK, 0xffff, 0x3e77) 155 156 // blow the fuse 157 reg.Write(hw.data, value) 158 159 if err = hw.checkOp(); err != nil { 160 return 161 } 162 163 // 2385, 37.3.1.4 Write Postamble, IMX6ULLRM 164 time.Sleep(2 * time.Microsecond) 165 166 // ensure update of shadow registers 167 return hw.shadowReload() 168 } 169 170 func (hw *OCOTP) checkOp() (err error) { 171 if !reg.WaitFor(hw.Timeout, hw.ctrl, CTRL_BUSY, 1, 0) { 172 return errors.New("operation timeout") 173 } 174 175 if reg.Get(hw.ctrl, CTRL_ERROR, 1) != 0 { 176 return errors.New("operation error") 177 } 178 179 return 180 } 181 182 // shadowReload reloads memory mapped shadow registers from OTP fuse banks 183 // (p2383, 37.3.1.1 Shadow Register Reload, IMX6ULLRM). 184 func (hw *OCOTP) shadowReload() (err error) { 185 if !reg.WaitFor(hw.Timeout, hw.ctrl, CTRL_BUSY, 1, 0) { 186 return errors.New("OCOTP controller busy") 187 } 188 189 // clear error bit 190 reg.Set(hw.ctrl_clr, CTRL_ERROR) 191 // force re-loading of shadow registers 192 reg.Set(hw.ctrl, CTRL_RELOAD_SHADOWS) 193 194 return hw.checkOp() 195 }