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