1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2021 NXP 4 */ 5 #include <arm.h> 6 #include <initcall.h> 7 #include <mm/core_memprot.h> 8 #include <mm/core_mmu.h> 9 #include <imx.h> 10 #include <io.h> 11 #include <drivers/imx_ocotp.h> 12 #include <kernel/tee_common_otp.h> 13 14 #define OCOTP_CTRL 0x0 15 #define OCOTP_CTRL_CLR 0x8 16 17 #if defined(CFG_MX8MP) 18 #define OCOTP_CTRL_ERROR BIT32(10) 19 #define OCOTP_CTRL_BUSY BIT32(9) 20 #else 21 #define OCOTP_CTRL_ERROR BIT32(9) 22 #define OCOTP_CTRL_BUSY BIT32(8) 23 #endif 24 25 #if defined(CFG_MX6) || defined(CFG_MX7ULP) 26 #define OCOTP_SHADOW_OFFSET(_b, _w) ((_b) * (0x80) + (_w) * (0x10) + 0x400) 27 #else 28 #define OCOTP_SHADOW_OFFSET(_b, _w) ((_b) * (0x40) + (_w) * (0x10) + 0x400) 29 #endif 30 31 struct ocotp_instance { 32 unsigned char nb_banks; 33 unsigned char nb_words; 34 TEE_Result (*get_die_id)(uint64_t *ret_uid); 35 }; 36 37 static vaddr_t g_base_addr; 38 static struct mutex fuse_read = MUTEX_INITIALIZER; 39 static const struct ocotp_instance *g_ocotp; 40 41 #if defined(CFG_MX6) 42 static void ocotp_clock_enable(void) 43 { 44 vaddr_t va = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC, CCM_SIZE); 45 46 io_setbits32(va + CCM_CCGR2, BM_CCM_CCGR2_OCOTP_CTRL); 47 } 48 #elif defined(CFG_MX7) 49 static void ocotp_clock_enable(void) 50 { 51 vaddr_t va = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC, CCM_SIZE); 52 53 io_setbits32(va + CCM_CCGRx_SET(CCM_CLOCK_DOMAIN_OCOTP), 54 CCM_CCGRx_ALWAYS_ON(0)); 55 } 56 #elif defined(CFG_MX8M) 57 static void ocotp_clock_enable(void) 58 { 59 vaddr_t va = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC, CCM_SIZE); 60 61 io_setbits32(va + CCM_CCGRx_SET(CCM_CCRG_OCOTP), 62 CCM_CCGRx_ALWAYS_ON(0)); 63 } 64 #elif defined(CFG_MX7ULP) 65 /* The i.MX7ULP has the OCOTP always powered on */ 66 static inline void ocotp_clock_enable(void) { } 67 #else 68 #error "Platform not supported" 69 #endif 70 71 static TEE_Result ocotp_ctrl_wait_for(uint32_t mask) 72 { 73 unsigned int loop = 0; 74 uint32_t reg = 0; 75 76 assert(g_base_addr); 77 78 /* 20us delay assuming the CPU clock running at 500MHz */ 79 for (loop = 10000; loop > 0; loop--) { 80 reg = io_read32(g_base_addr + OCOTP_CTRL) & mask; 81 if (!reg) 82 return TEE_SUCCESS; 83 dsb(); 84 isb(); 85 } 86 87 return TEE_ERROR_BUSY; 88 } 89 90 TEE_Result imx_ocotp_read(unsigned int bank, unsigned int word, uint32_t *val) 91 { 92 TEE_Result ret = TEE_ERROR_GENERIC; 93 94 if (!val) 95 return TEE_ERROR_BAD_PARAMETERS; 96 97 if (bank > g_ocotp->nb_banks || word > g_ocotp->nb_words) 98 return TEE_ERROR_BAD_PARAMETERS; 99 100 assert(g_base_addr && g_ocotp); 101 102 mutex_lock(&fuse_read); 103 104 ocotp_clock_enable(); 105 106 /* Clear error bit */ 107 io_write32(g_base_addr + OCOTP_CTRL_CLR, OCOTP_CTRL_ERROR); 108 109 /* Wait for busy flag to be cleared */ 110 ret = ocotp_ctrl_wait_for(OCOTP_CTRL_BUSY); 111 if (ret) { 112 EMSG("OCOTP is busy"); 113 goto out; 114 } 115 116 /* Read shadow register */ 117 *val = io_read32(g_base_addr + OCOTP_SHADOW_OFFSET(bank, word)); 118 119 DMSG("OCOTP Bank %d Word %d Fuse 0x%" PRIx32, bank, word, *val); 120 out: 121 mutex_unlock(&fuse_read); 122 123 return ret; 124 } 125 126 static TEE_Result ocotp_get_die_id_mx7ulp(uint64_t *ret_uid) 127 { 128 TEE_Result res = TEE_ERROR_GENERIC; 129 uint32_t val = 0; 130 uint64_t uid = 0; 131 132 res = imx_ocotp_read(1, 6, &val); 133 if (res) 134 goto out; 135 uid = val & GENMASK_32(15, 0); 136 137 res = imx_ocotp_read(1, 5, &val); 138 if (res) 139 goto out; 140 uid = SHIFT_U64(uid, 16) | (val & GENMASK_32(15, 0)); 141 142 res = imx_ocotp_read(1, 4, &val); 143 if (res) 144 goto out; 145 uid = SHIFT_U64(uid, 16) | (val & GENMASK_32(15, 0)); 146 147 res = imx_ocotp_read(1, 3, &val); 148 if (res) 149 goto out; 150 uid = SHIFT_U64(uid, 16) | (val & GENMASK_32(15, 0)); 151 152 out: 153 if (res == TEE_SUCCESS) 154 *ret_uid = uid; 155 156 return res; 157 } 158 159 static TEE_Result ocotp_get_die_id_mx(uint64_t *ret_uid) 160 { 161 TEE_Result res = TEE_ERROR_GENERIC; 162 uint32_t val = 0; 163 uint64_t uid = 0; 164 165 res = imx_ocotp_read(0, 2, &val); 166 if (res) 167 goto out; 168 uid = val; 169 170 res = imx_ocotp_read(0, 1, &val); 171 if (res) 172 goto out; 173 uid = SHIFT_U64(uid, 32) | val; 174 175 out: 176 if (res == TEE_SUCCESS) 177 *ret_uid = uid; 178 179 return res; 180 } 181 182 static const struct ocotp_instance ocotp_imx6q = { 183 .nb_banks = 16, 184 .nb_words = 8, 185 .get_die_id = ocotp_get_die_id_mx, 186 }; 187 188 static const struct ocotp_instance ocotp_imx6sl = { 189 .nb_banks = 8, 190 .nb_words = 8, 191 .get_die_id = ocotp_get_die_id_mx, 192 }; 193 194 static const struct ocotp_instance ocotp_imx6sll = { 195 .nb_banks = 16, 196 .nb_words = 8, 197 .get_die_id = ocotp_get_die_id_mx, 198 }; 199 200 static const struct ocotp_instance ocotp_imx6sx = { 201 .nb_banks = 16, 202 .nb_words = 8, 203 .get_die_id = ocotp_get_die_id_mx, 204 }; 205 206 static const struct ocotp_instance ocotp_imx6ul = { 207 .nb_banks = 16, 208 .nb_words = 8, 209 .get_die_id = ocotp_get_die_id_mx, 210 }; 211 212 static const struct ocotp_instance ocotp_imx6ull = { 213 .nb_banks = 8, 214 .nb_words = 8, 215 .get_die_id = ocotp_get_die_id_mx, 216 }; 217 218 static const struct ocotp_instance ocotp_imx7d = { 219 .nb_banks = 8, 220 .nb_words = 8, 221 .get_die_id = ocotp_get_die_id_mx, 222 }; 223 224 static const struct ocotp_instance ocotp_imx7ulp = { 225 .nb_banks = 32, 226 .nb_words = 8, 227 .get_die_id = ocotp_get_die_id_mx7ulp, 228 }; 229 230 static const struct ocotp_instance ocotp_imx8m = { 231 .nb_banks = 32, 232 .nb_words = 8, 233 .get_die_id = ocotp_get_die_id_mx, 234 }; 235 236 static const struct ocotp_instance ocotp_imx8mp = { 237 .nb_banks = 48, 238 .nb_words = 8, 239 .get_die_id = ocotp_get_die_id_mx, 240 }; 241 242 int tee_otp_get_die_id(uint8_t *buffer, size_t len) 243 { 244 size_t max_size_uid = IMX_UID_SIZE; 245 uint64_t uid = 0; 246 247 assert(buffer); 248 assert(g_base_addr && g_ocotp); 249 250 if (g_ocotp->get_die_id(&uid)) 251 goto err; 252 253 memcpy(buffer, &uid, MIN(max_size_uid, len)); 254 return 0; 255 256 err: 257 EMSG("Error while getting die ID"); 258 return -1; 259 } 260 261 register_phys_mem_pgdir(MEM_AREA_IO_SEC, OCOTP_BASE, CORE_MMU_PGDIR_SIZE); 262 static TEE_Result imx_ocotp_init(void) 263 { 264 g_base_addr = core_mmu_get_va(OCOTP_BASE, MEM_AREA_IO_SEC, OCOTP_SIZE); 265 if (!g_base_addr) 266 return TEE_ERROR_GENERIC; 267 268 if (soc_is_imx6sdl() || soc_is_imx6dq() || soc_is_imx6dqp()) { 269 g_ocotp = &ocotp_imx6q; 270 } else if (soc_is_imx6sl()) { 271 g_ocotp = &ocotp_imx6sl; 272 } else if (soc_is_imx6sll()) { 273 g_ocotp = &ocotp_imx6sll; 274 } else if (soc_is_imx6sx()) { 275 g_ocotp = &ocotp_imx6sx; 276 } else if (soc_is_imx6ul()) { 277 g_ocotp = &ocotp_imx6ul; 278 } else if (soc_is_imx6ull()) { 279 g_ocotp = &ocotp_imx6ull; 280 } else if (soc_is_imx7ds()) { 281 g_ocotp = &ocotp_imx7d; 282 } else if (soc_is_imx7ulp()) { 283 g_ocotp = &ocotp_imx7ulp; 284 } else if (soc_is_imx8mm() || soc_is_imx8mn() || soc_is_imx8mq()) { 285 g_ocotp = &ocotp_imx8m; 286 } else if (soc_is_imx8mp()) { 287 g_ocotp = &ocotp_imx8mp; 288 } else { 289 g_ocotp = NULL; 290 return TEE_ERROR_NOT_SUPPORTED; 291 } 292 293 return TEE_SUCCESS; 294 } 295 service_init(imx_ocotp_init); 296