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 if (cell->offset + cell->len > ATMEL_SFC_CELLS_8) 36 return TEE_ERROR_GENERIC; 37 38 memcpy(data, &atmel_sfc->fuses[cell->offset], cell->len); 39 40 return TEE_SUCCESS; 41 } 42 43 static void atmel_sfc_put_cell(struct nvmem_cell *cell) 44 { 45 free(cell); 46 } 47 48 static const struct nvmem_ops atmel_sfc_nvmem_ops = { 49 .read_cell = atmel_sfc_read_cell, 50 .put_cell = atmel_sfc_put_cell, 51 }; 52 53 static TEE_Result atmel_sfc_dt_get(struct dt_pargs *args, 54 void *data, struct nvmem_cell **out_cell) 55 { 56 TEE_Result res = TEE_ERROR_GENERIC; 57 struct nvmem_cell *cell = NULL; 58 59 /* Freed from atmel_sfc_put_cell() */ 60 cell = calloc(1, sizeof(*cell)); 61 if (!cell) 62 return TEE_ERROR_OUT_OF_MEMORY; 63 64 res = nvmem_cell_parse_dt(args->fdt, args->phandle_node, cell); 65 if (res) 66 goto out_free; 67 68 if (cell->offset + cell->len > ATMEL_SFC_CELLS_8) { 69 res = TEE_ERROR_GENERIC; 70 goto out_free; 71 } 72 73 cell->ops = &atmel_sfc_nvmem_ops; 74 cell->drv_data = data; 75 *out_cell = cell; 76 77 return TEE_SUCCESS; 78 79 out_free: 80 free(cell); 81 82 return res; 83 } 84 85 static void atmel_sfc_read_fuse(struct atmel_sfc *atmel_sfc) 86 { 87 size_t i = 0; 88 uint32_t val = 0; 89 90 for (i = 0; i < ATMEL_SFC_CELLS_32; i++) { 91 val = io_read32(atmel_sfc->base + ATMEL_SFC_DR + i * 4); 92 memcpy(&atmel_sfc->fuses[i * 4], &val, sizeof(val)); 93 } 94 } 95 96 static TEE_Result atmel_sfc_probe(const void *fdt, int node, 97 const void *compat_data __unused) 98 { 99 vaddr_t base = 0; 100 size_t size = 0; 101 struct atmel_sfc *atmel_sfc = NULL; 102 103 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 104 return TEE_ERROR_NODE_DISABLED; 105 106 matrix_configure_periph_secure(AT91C_ID_SFC); 107 108 if (dt_map_dev(fdt, node, &base, &size, DT_MAP_AUTO) < 0) 109 return TEE_ERROR_GENERIC; 110 111 atmel_sfc = calloc(1, sizeof(*atmel_sfc)); 112 if (!atmel_sfc) 113 return TEE_ERROR_OUT_OF_MEMORY; 114 115 atmel_sfc->base = base; 116 117 atmel_sfc_read_fuse(atmel_sfc); 118 119 return nvmem_register_provider(fdt, node, atmel_sfc_dt_get, atmel_sfc); 120 } 121 122 static const struct dt_device_match atmel_sfc_match_table[] = { 123 { .compatible = "atmel,sama5d2-sfc" }, 124 { } 125 }; 126 127 DEFINE_DT_DRIVER(atmel_sfc_dt_driver) = { 128 .name = "atmel_sfc", 129 .type = DT_DRIVER_NVMEM, 130 .match_table = atmel_sfc_match_table, 131 .probe = atmel_sfc_probe, 132 }; 133