1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021, Microchip 4 */ 5 6 #include <drivers/nvmem.h> 7 #include <io.h> 8 #include <kernel/dt_driver.h> 9 #include <malloc.h> 10 #include <matrix.h> 11 #include <platform_config.h> 12 #include <string.h> 13 #include <tee_api_defines.h> 14 #include <tee_api_types.h> 15 #include <types_ext.h> 16 17 #define ATMEL_SFC_KR 0x0 18 #define ATMEL_SFC_SR 0x1C 19 #define ATMEL_SFC_SR_PGMC BIT(0) 20 #define ATMEL_SFC_SR_PGMF BIT(1) 21 #define ATMEL_SFC_DR 0x20 22 23 #define ATMEL_SFC_CELLS_32 17 24 #define ATMEL_SFC_CELLS_8 (ATMEL_SFC_CELLS_32 * sizeof(uint32_t)) 25 26 struct atmel_sfc { 27 vaddr_t base; 28 uint8_t fuses[ATMEL_SFC_CELLS_8]; 29 }; 30 31 static TEE_Result atmel_sfc_read_cell(struct nvmem_cell *cell, uint8_t *data) 32 { 33 struct atmel_sfc *atmel_sfc = cell->drv_data; 34 35 memcpy(data, &atmel_sfc->fuses[cell->offset], cell->len); 36 37 return TEE_SUCCESS; 38 } 39 40 static void atmel_sfc_put_cell(struct nvmem_cell *cell) 41 { 42 free(cell); 43 } 44 45 static const struct nvmem_ops atmel_sfc_nvmem_ops = { 46 .read_cell = atmel_sfc_read_cell, 47 .put_cell = atmel_sfc_put_cell, 48 }; 49 50 static TEE_Result atmel_sfc_dt_get(struct dt_pargs *args, 51 void *data, struct nvmem_cell **out_cell) 52 { 53 TEE_Result res = TEE_ERROR_GENERIC; 54 struct nvmem_cell *cell = NULL; 55 56 /* Freed from atmel_sfc_put_cell() */ 57 cell = calloc(1, sizeof(*cell)); 58 if (!cell) 59 return TEE_ERROR_OUT_OF_MEMORY; 60 61 res = nvmem_cell_parse_dt(args->fdt, args->phandle_node, cell); 62 if (res) 63 goto out_free; 64 65 if (cell->offset + cell->len > ATMEL_SFC_CELLS_8) { 66 res = TEE_ERROR_GENERIC; 67 goto out_free; 68 } 69 70 cell->ops = &atmel_sfc_nvmem_ops; 71 cell->drv_data = data; 72 *out_cell = cell; 73 74 return TEE_SUCCESS; 75 76 out_free: 77 free(cell); 78 79 return res; 80 } 81 82 static void atmel_sfc_read_fuse(struct atmel_sfc *atmel_sfc) 83 { 84 size_t i = 0; 85 uint32_t val = 0; 86 87 for (i = 0; i < ATMEL_SFC_CELLS_32; i++) { 88 val = io_read32(atmel_sfc->base + ATMEL_SFC_DR + i * 4); 89 memcpy(&atmel_sfc->fuses[i * 4], &val, sizeof(val)); 90 } 91 } 92 93 static TEE_Result atmel_sfc_probe(const void *fdt, int node, 94 const void *compat_data __unused) 95 { 96 vaddr_t base = 0; 97 size_t size = 0; 98 struct atmel_sfc *atmel_sfc = NULL; 99 100 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 101 return TEE_ERROR_NODE_DISABLED; 102 103 matrix_configure_periph_secure(AT91C_ID_SFC); 104 105 if (dt_map_dev(fdt, node, &base, &size, DT_MAP_AUTO) < 0) 106 return TEE_ERROR_GENERIC; 107 108 atmel_sfc = calloc(1, sizeof(*atmel_sfc)); 109 if (!atmel_sfc) 110 return TEE_ERROR_OUT_OF_MEMORY; 111 112 atmel_sfc->base = base; 113 114 atmel_sfc_read_fuse(atmel_sfc); 115 116 return nvmem_register_provider(fdt, node, atmel_sfc_dt_get, atmel_sfc); 117 } 118 119 static const struct dt_device_match atmel_sfc_match_table[] = { 120 { .compatible = "atmel,sama5d2-sfc" }, 121 { } 122 }; 123 124 DEFINE_DT_DRIVER(atmel_sfc_dt_driver) = { 125 .name = "atmel_sfc", 126 .type = DT_DRIVER_NVMEM, 127 .match_table = atmel_sfc_match_table, 128 .probe = atmel_sfc_probe, 129 }; 130