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