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  }