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