stm32-romem.c (4925B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * STM32 Factory-programmed memory read access driver 4 * 5 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 6 * Author: Fabrice Gasnier <fabrice.gasnier@st.com> for STMicroelectronics. 7 */ 8 9#include <linux/arm-smccc.h> 10#include <linux/io.h> 11#include <linux/module.h> 12#include <linux/nvmem-provider.h> 13#include <linux/of_device.h> 14 15/* BSEC secure service access from non-secure */ 16#define STM32_SMC_BSEC 0x82001003 17#define STM32_SMC_READ_SHADOW 0x01 18#define STM32_SMC_PROG_OTP 0x02 19#define STM32_SMC_WRITE_SHADOW 0x03 20#define STM32_SMC_READ_OTP 0x04 21 22/* shadow registers offest */ 23#define STM32MP15_BSEC_DATA0 0x200 24 25/* 32 (x 32-bits) lower shadow registers */ 26#define STM32MP15_BSEC_NUM_LOWER 32 27 28struct stm32_romem_cfg { 29 int size; 30}; 31 32struct stm32_romem_priv { 33 void __iomem *base; 34 struct nvmem_config cfg; 35}; 36 37static int stm32_romem_read(void *context, unsigned int offset, void *buf, 38 size_t bytes) 39{ 40 struct stm32_romem_priv *priv = context; 41 u8 *buf8 = buf; 42 int i; 43 44 for (i = offset; i < offset + bytes; i++) 45 *buf8++ = readb_relaxed(priv->base + i); 46 47 return 0; 48} 49 50static int stm32_bsec_smc(u8 op, u32 otp, u32 data, u32 *result) 51{ 52#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) 53 struct arm_smccc_res res; 54 55 arm_smccc_smc(STM32_SMC_BSEC, op, otp, data, 0, 0, 0, 0, &res); 56 if (res.a0) 57 return -EIO; 58 59 if (result) 60 *result = (u32)res.a1; 61 62 return 0; 63#else 64 return -ENXIO; 65#endif 66} 67 68static int stm32_bsec_read(void *context, unsigned int offset, void *buf, 69 size_t bytes) 70{ 71 struct stm32_romem_priv *priv = context; 72 struct device *dev = priv->cfg.dev; 73 u32 roffset, rbytes, val; 74 u8 *buf8 = buf, *val8 = (u8 *)&val; 75 int i, j = 0, ret, skip_bytes, size; 76 77 /* Round unaligned access to 32-bits */ 78 roffset = rounddown(offset, 4); 79 skip_bytes = offset & 0x3; 80 rbytes = roundup(bytes + skip_bytes, 4); 81 82 if (roffset + rbytes > priv->cfg.size) 83 return -EINVAL; 84 85 for (i = roffset; (i < roffset + rbytes); i += 4) { 86 u32 otp = i >> 2; 87 88 if (otp < STM32MP15_BSEC_NUM_LOWER) { 89 /* read lower data from shadow registers */ 90 val = readl_relaxed( 91 priv->base + STM32MP15_BSEC_DATA0 + i); 92 } else { 93 ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, otp, 0, 94 &val); 95 if (ret) { 96 dev_err(dev, "Can't read data%d (%d)\n", otp, 97 ret); 98 return ret; 99 } 100 } 101 /* skip first bytes in case of unaligned read */ 102 if (skip_bytes) 103 size = min(bytes, (size_t)(4 - skip_bytes)); 104 else 105 size = min(bytes, (size_t)4); 106 memcpy(&buf8[j], &val8[skip_bytes], size); 107 bytes -= size; 108 j += size; 109 skip_bytes = 0; 110 } 111 112 return 0; 113} 114 115static int stm32_bsec_write(void *context, unsigned int offset, void *buf, 116 size_t bytes) 117{ 118 struct stm32_romem_priv *priv = context; 119 struct device *dev = priv->cfg.dev; 120 u32 *buf32 = buf; 121 int ret, i; 122 123 /* Allow only writing complete 32-bits aligned words */ 124 if ((bytes % 4) || (offset % 4)) 125 return -EINVAL; 126 127 for (i = offset; i < offset + bytes; i += 4) { 128 ret = stm32_bsec_smc(STM32_SMC_PROG_OTP, i >> 2, *buf32++, 129 NULL); 130 if (ret) { 131 dev_err(dev, "Can't write data%d (%d)\n", i >> 2, ret); 132 return ret; 133 } 134 } 135 136 return 0; 137} 138 139static int stm32_romem_probe(struct platform_device *pdev) 140{ 141 const struct stm32_romem_cfg *cfg; 142 struct device *dev = &pdev->dev; 143 struct stm32_romem_priv *priv; 144 struct resource *res; 145 146 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 147 if (!priv) 148 return -ENOMEM; 149 150 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 151 priv->base = devm_ioremap_resource(dev, res); 152 if (IS_ERR(priv->base)) 153 return PTR_ERR(priv->base); 154 155 priv->cfg.name = "stm32-romem"; 156 priv->cfg.word_size = 1; 157 priv->cfg.stride = 1; 158 priv->cfg.dev = dev; 159 priv->cfg.priv = priv; 160 priv->cfg.owner = THIS_MODULE; 161 162 cfg = (const struct stm32_romem_cfg *) 163 of_match_device(dev->driver->of_match_table, dev)->data; 164 if (!cfg) { 165 priv->cfg.read_only = true; 166 priv->cfg.size = resource_size(res); 167 priv->cfg.reg_read = stm32_romem_read; 168 } else { 169 priv->cfg.size = cfg->size; 170 priv->cfg.reg_read = stm32_bsec_read; 171 priv->cfg.reg_write = stm32_bsec_write; 172 } 173 174 return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); 175} 176 177static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { 178 .size = 384, /* 96 x 32-bits data words */ 179}; 180 181static const struct of_device_id stm32_romem_of_match[] = { 182 { .compatible = "st,stm32f4-otp", }, { 183 .compatible = "st,stm32mp15-bsec", 184 .data = (void *)&stm32mp15_bsec_cfg, 185 }, { 186 }, 187}; 188MODULE_DEVICE_TABLE(of, stm32_romem_of_match); 189 190static struct platform_driver stm32_romem_driver = { 191 .probe = stm32_romem_probe, 192 .driver = { 193 .name = "stm32-romem", 194 .of_match_table = of_match_ptr(stm32_romem_of_match), 195 }, 196}; 197module_platform_driver(stm32_romem_driver); 198 199MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); 200MODULE_DESCRIPTION("STMicroelectronics STM32 RO-MEM"); 201MODULE_ALIAS("platform:nvmem-stm32-romem"); 202MODULE_LICENSE("GPL v2");