diff options
Diffstat (limited to 'drivers/nvmem')
-rw-r--r-- | drivers/nvmem/Kconfig | 13 | ||||
-rw-r--r-- | drivers/nvmem/Makefile | 2 | ||||
-rw-r--r-- | drivers/nvmem/apple-efuses.c | 80 | ||||
-rw-r--r-- | drivers/nvmem/bcm-ocotp.c | 2 | ||||
-rw-r--r-- | drivers/nvmem/brcm_nvram.c | 2 | ||||
-rw-r--r-- | drivers/nvmem/core.c | 1 | ||||
-rw-r--r-- | drivers/nvmem/layerscape-sfp.c | 36 | ||||
-rw-r--r-- | drivers/nvmem/qfprom.c | 3 | ||||
-rw-r--r-- | drivers/nvmem/sunplus-ocotp.c | 4 |
9 files changed, 129 insertions, 14 deletions
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 555aa77a574d..967d0084800e 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -304,6 +304,7 @@ config NVMEM_LAYERSCAPE_SFP tristate "Layerscape SFP (Security Fuse Processor) support" depends on ARCH_LAYERSCAPE || COMPILE_TEST depends on HAS_IOMEM + select REGMAP_MMIO help This driver provides support to read the eFuses on Freescale Layerscape SoC's. For example, the vendor provides a per part @@ -324,4 +325,16 @@ config NVMEM_SUNPLUS_OCOTP This driver can also be built as a module. If so, the module will be called nvmem-sunplus-ocotp. +config NVMEM_APPLE_EFUSES + tristate "Apple eFuse support" + depends on ARCH_APPLE || COMPILE_TEST + default ARCH_APPLE + help + Say y here to enable support for reading eFuses on Apple SoCs + such as the M1. These are e.g. used to store factory programmed + calibration data required for the PCIe or the USB-C PHY. + + This driver can also be built as a module. If so, the module will + be called nvmem-apple-efuses. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 891958e29d25..00e136a0a123 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -65,3 +65,5 @@ obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o nvmem-layerscape-sfp-y := layerscape-sfp.o obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o nvmem_sunplus_ocotp-y := sunplus-ocotp.o +obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o +nvmem-apple-efuses-y := apple-efuses.o diff --git a/drivers/nvmem/apple-efuses.c b/drivers/nvmem/apple-efuses.c new file mode 100644 index 000000000000..9b7c87102104 --- /dev/null +++ b/drivers/nvmem/apple-efuses.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Apple SoC eFuse driver + * + * Copyright (C) The Asahi Linux Contributors + */ + +#include <linux/io.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/platform_device.h> + +struct apple_efuses_priv { + void __iomem *fuses; +}; + +static int apple_efuses_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct apple_efuses_priv *priv = context; + u32 *dst = val; + + while (bytes >= sizeof(u32)) { + *dst++ = readl_relaxed(priv->fuses + offset); + bytes -= sizeof(u32); + offset += sizeof(u32); + } + + return 0; +} + +static int apple_efuses_probe(struct platform_device *pdev) +{ + struct apple_efuses_priv *priv; + struct resource *res; + struct nvmem_config config = { + .dev = &pdev->dev, + .read_only = true, + .reg_read = apple_efuses_read, + .stride = sizeof(u32), + .word_size = sizeof(u32), + .name = "apple_efuses_nvmem", + .id = NVMEM_DEVID_AUTO, + .root_only = true, + }; + + priv = devm_kzalloc(config.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->fuses = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->fuses)) + return PTR_ERR(priv->fuses); + + config.priv = priv; + config.size = resource_size(res); + + return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); +} + +static const struct of_device_id apple_efuses_of_match[] = { + { .compatible = "apple,efuses", }, + {} +}; + +MODULE_DEVICE_TABLE(of, apple_efuses_of_match); + +static struct platform_driver apple_efuses_driver = { + .driver = { + .name = "apple_efuses", + .of_match_table = apple_efuses_of_match, + }, + .probe = apple_efuses_probe, +}; + +module_platform_driver(apple_efuses_driver); + +MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c index a8097511582a..dfea96c52463 100644 --- a/drivers/nvmem/bcm-ocotp.c +++ b/drivers/nvmem/bcm-ocotp.c @@ -244,7 +244,7 @@ static const struct of_device_id bcm_otpc_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, bcm_otpc_dt_ids); -static const struct acpi_device_id bcm_otpc_acpi_ids[] = { +static const struct acpi_device_id bcm_otpc_acpi_ids[] __maybe_unused = { { .id = "BRCM0700", .driver_data = (kernel_ulong_t)&otp_map }, { .id = "BRCM0701", .driver_data = (kernel_ulong_t)&otp_map_v2 }, { /* sentinel */ } diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c index 439f00b9eef6..450b927691c3 100644 --- a/drivers/nvmem/brcm_nvram.c +++ b/drivers/nvmem/brcm_nvram.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/nvmem-consumer.h> #include <linux/nvmem-provider.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -72,6 +73,7 @@ static int brcm_nvram_add_cells(struct brcm_nvram *priv, uint8_t *data, return -ENOMEM; priv->cells[idx].offset = value - (char *)data; priv->cells[idx].bytes = strlen(value); + priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); } return 0; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index f58d9bc7aa08..1e3c754efd0d 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -467,6 +467,7 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, cell->bit_offset = info->bit_offset; cell->nbits = info->nbits; + cell->np = info->np; if (cell->nbits) cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, diff --git a/drivers/nvmem/layerscape-sfp.c b/drivers/nvmem/layerscape-sfp.c index e591c1511e33..e2b424561949 100644 --- a/drivers/nvmem/layerscape-sfp.c +++ b/drivers/nvmem/layerscape-sfp.c @@ -13,15 +13,17 @@ #include <linux/nvmem-provider.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/regmap.h> #define LAYERSCAPE_SFP_OTP_OFFSET 0x0200 struct layerscape_sfp_priv { - void __iomem *base; + struct regmap *regmap; }; struct layerscape_sfp_data { int size; + enum regmap_endian endian; }; static int layerscape_sfp_read(void *context, unsigned int offset, void *val, @@ -29,15 +31,16 @@ static int layerscape_sfp_read(void *context, unsigned int offset, void *val, { struct layerscape_sfp_priv *priv = context; - memcpy_fromio(val, priv->base + LAYERSCAPE_SFP_OTP_OFFSET + offset, - bytes); - - return 0; + return regmap_bulk_read(priv->regmap, + LAYERSCAPE_SFP_OTP_OFFSET + offset, val, + bytes / 4); } static struct nvmem_config layerscape_sfp_nvmem_config = { .name = "fsl-sfp", .reg_read = layerscape_sfp_read, + .word_size = 4, + .stride = 4, }; static int layerscape_sfp_probe(struct platform_device *pdev) @@ -45,16 +48,26 @@ static int layerscape_sfp_probe(struct platform_device *pdev) const struct layerscape_sfp_data *data; struct layerscape_sfp_priv *priv; struct nvmem_device *nvmem; + struct regmap_config config = { 0 }; + void __iomem *base; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); data = device_get_match_data(&pdev->dev); + config.reg_bits = 32; + config.reg_stride = 4; + config.val_bits = 32; + config.val_format_endian = data->endian; + config.max_register = LAYERSCAPE_SFP_OTP_OFFSET + data->size - 4; + priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, &config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); layerscape_sfp_nvmem_config.size = data->size; layerscape_sfp_nvmem_config.dev = &pdev->dev; @@ -65,11 +78,18 @@ static int layerscape_sfp_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(nvmem); } +static const struct layerscape_sfp_data ls1021a_data = { + .size = 0x88, + .endian = REGMAP_ENDIAN_BIG, +}; + static const struct layerscape_sfp_data ls1028a_data = { .size = 0x88, + .endian = REGMAP_ENDIAN_LITTLE, }; static const struct of_device_id layerscape_sfp_dt_ids[] = { + { .compatible = "fsl,ls1021a-sfp", .data = &ls1021a_data }, { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data }, {}, }; diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 162132c7dab9..c1e893c8a247 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -217,9 +217,8 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, goto err_clk_rate_set; } - ret = pm_runtime_get_sync(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); if (ret < 0) { - pm_runtime_put_noidle(priv->dev); dev_err(priv->dev, "Failed to enable power-domain\n"); goto err_reg_enable; } diff --git a/drivers/nvmem/sunplus-ocotp.c b/drivers/nvmem/sunplus-ocotp.c index 2dc59c22eb55..52b928a7a6d5 100644 --- a/drivers/nvmem/sunplus-ocotp.c +++ b/drivers/nvmem/sunplus-ocotp.c @@ -71,7 +71,7 @@ struct sp_ocotp_data { int size; }; -const struct sp_ocotp_data sp_otp_v0 = { +static const struct sp_ocotp_data sp_otp_v0 = { .size = QAC628_OTP_SIZE, }; @@ -202,8 +202,6 @@ static int sp_ocotp_probe(struct platform_device *pdev) (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK, (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE); - dev_info(dev, "by Sunplus (C) 2020"); - return 0; } |