diff options
| author | Ugljesa Jovanovic <[email protected]> | 2024-11-16 22:22:47 +0100 |
|---|---|---|
| committer | Ugljesa Jovanovic <[email protected]> | 2024-11-16 22:22:47 +0100 |
| commit | 69cb30ebf3772a20612f53202ab4b8e880b0583c (patch) | |
| tree | 3c671b99f99c2720f3185218740d8b61ac4cec84 | |
| parent | 6c4b3d82b637fce5ab6efdc312d7852381d8ddeb (diff) | |
Add OTP write
| -rw-r--r-- | embassy-rp/src/otp.rs | 71 |
1 files changed, 69 insertions, 2 deletions
diff --git a/embassy-rp/src/otp.rs b/embassy-rp/src/otp.rs index cdaf5bded..6091f71b2 100644 --- a/embassy-rp/src/otp.rs +++ b/embassy-rp/src/otp.rs | |||
| @@ -3,15 +3,24 @@ | |||
| 3 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) | 3 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) |
| 4 | // https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs | 4 | // https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs |
| 5 | 5 | ||
| 6 | /// The ways in which we can fail to read OTP | 6 | use crate::rom_data::otp_access; |
| 7 | |||
| 8 | /// The ways in which we can fail to access OTP | ||
| 7 | #[derive(Debug, Clone)] | 9 | #[derive(Debug, Clone)] |
| 8 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 9 | pub enum Error { | 11 | pub enum Error { |
| 10 | /// The user passed an invalid index to a function. | 12 | /// The user passed an invalid index to a function. |
| 11 | InvalidIndex, | 13 | InvalidIndex, |
| 12 | /// The hardware refused to let us read this word, probably due to | 14 | /// The hardware refused to let us read this word, probably due to |
| 13 | /// read lock set earlier in the boot process. | 15 | /// read or write lock set earlier in the boot process. |
| 14 | InvalidPermissions, | 16 | InvalidPermissions, |
| 17 | /// Modification is impossible based on current state; e.g. | ||
| 18 | /// attempted to clear an OTP bit. | ||
| 19 | UnsupportedModification, | ||
| 20 | /// Value being written is bigger than 24 bits allowed for raw writes. | ||
| 21 | Overflow, | ||
| 22 | /// An unexpected failure that contains the exact return code | ||
| 23 | UnexpectedFailure(i32), | ||
| 15 | } | 24 | } |
| 16 | 25 | ||
| 17 | /// OTP read address, using automatic Error Correction. | 26 | /// OTP read address, using automatic Error Correction. |
| @@ -34,6 +43,9 @@ pub const NUM_ROWS_PER_PAGE: usize = 64; | |||
| 34 | /// How many rows in OTP (post error-correction) | 43 | /// How many rows in OTP (post error-correction) |
| 35 | pub const NUM_ROWS: usize = NUM_PAGES * NUM_ROWS_PER_PAGE; | 44 | pub const NUM_ROWS: usize = NUM_PAGES * NUM_ROWS_PER_PAGE; |
| 36 | 45 | ||
| 46 | /// 24bit mask for raw writes | ||
| 47 | pub const RAW_WRITE_BIT_MASK: u32 = 0x00FF_FFFF; | ||
| 48 | |||
| 37 | /// Read one ECC protected word from the OTP | 49 | /// Read one ECC protected word from the OTP |
| 38 | pub fn read_ecc_word(row: usize) -> Result<u16, Error> { | 50 | pub fn read_ecc_word(row: usize) -> Result<u16, Error> { |
| 39 | if row >= NUM_ROWS { | 51 | if row >= NUM_ROWS { |
| @@ -72,6 +84,61 @@ pub fn read_raw_word(row: usize) -> Result<u32, Error> { | |||
| 72 | Ok(value) | 84 | Ok(value) |
| 73 | } | 85 | } |
| 74 | } | 86 | } |
| 87 | /// Write one raw word to the OTP | ||
| 88 | /// | ||
| 89 | /// 24 bit value will be written to the OTP | ||
| 90 | pub fn write_raw_word(row: usize, data: u32) -> Result<(), Error> { | ||
| 91 | if data > RAW_WRITE_BIT_MASK { | ||
| 92 | return Err(Error::Overflow); | ||
| 93 | } | ||
| 94 | if row >= NUM_ROWS { | ||
| 95 | return Err(Error::InvalidIndex); | ||
| 96 | } | ||
| 97 | let row_with_write_bit = row | 0x00010000; | ||
| 98 | // # Safety | ||
| 99 | // | ||
| 100 | // We checked this row was in range already. | ||
| 101 | let result = unsafe { otp_access(data.to_le_bytes().as_mut_ptr(), 4, row_with_write_bit as u32) }; | ||
| 102 | if result == 0 { | ||
| 103 | Ok(()) | ||
| 104 | } else { | ||
| 105 | // 5.4.3. API Function Return Codes | ||
| 106 | let error = match result { | ||
| 107 | -4 => Error::InvalidPermissions, | ||
| 108 | -18 => Error::UnsupportedModification, | ||
| 109 | _ => Error::UnexpectedFailure(result), | ||
| 110 | }; | ||
| 111 | Err(error) | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Write one raw word to the OTP with ECC | ||
| 116 | /// | ||
| 117 | /// 16 bit value will be written + ECC | ||
| 118 | pub fn write_ecc_word(row: usize, data: u16) -> Result<(), Error> { | ||
| 119 | if row >= NUM_ROWS { | ||
| 120 | return Err(Error::InvalidIndex); | ||
| 121 | } | ||
| 122 | let row_with_write_and_ecc_bit = row | 0x00030000; | ||
| 123 | |||
| 124 | // # Safety | ||
| 125 | // | ||
| 126 | // We checked this row was in range already. | ||
| 127 | |||
| 128 | let result = unsafe { otp_access(data.to_le_bytes().as_mut_ptr(), 2, row_with_write_and_ecc_bit as u32) }; | ||
| 129 | if result == 0 { | ||
| 130 | Ok(()) | ||
| 131 | } else { | ||
| 132 | // 5.4.3. API Function Return Codes | ||
| 133 | // 5.4.3. API Function Return Codes | ||
| 134 | let error = match result { | ||
| 135 | -4 => Error::InvalidPermissions, | ||
| 136 | -18 => Error::UnsupportedModification, | ||
| 137 | _ => Error::UnexpectedFailure(result), | ||
| 138 | }; | ||
| 139 | Err(error) | ||
| 140 | } | ||
| 141 | } | ||
| 75 | 142 | ||
| 76 | /// Get the random 64bit chipid from rows 0x0-0x3. | 143 | /// Get the random 64bit chipid from rows 0x0-0x3. |
| 77 | pub fn get_chipid() -> Result<u64, Error> { | 144 | pub fn get_chipid() -> Result<u64, Error> { |
