Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: core: add OTP nvmem provider support

Flash OTP regions can already be read via user space. Some boards have
their serial number or MAC addresses stored in the OTP regions. Add
support for them being a (read-only) nvmem provider.

The API to read the OTP data is already in place. It distinguishes
between factory and user OTP, thus there are up to two different
providers.

Signed-off-by: Michael Walle <michael@walle.cc>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210424110608.15748-6-michael@walle.cc

authored by

Michael Walle and committed by
Miquel Raynal
4b361cfa 96d3af22

+150
+148
drivers/mtd/mtdcore.c
··· 776 776 mutex_init(&mtd->master.chrdev_lock); 777 777 } 778 778 779 + static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user) 780 + { 781 + struct otp_info *info = kmalloc(PAGE_SIZE, GFP_KERNEL); 782 + ssize_t size = 0; 783 + unsigned int i; 784 + size_t retlen; 785 + int ret; 786 + 787 + if (is_user) 788 + ret = mtd_get_user_prot_info(mtd, PAGE_SIZE, &retlen, info); 789 + else 790 + ret = mtd_get_fact_prot_info(mtd, PAGE_SIZE, &retlen, info); 791 + if (ret) 792 + goto err; 793 + 794 + for (i = 0; i < retlen / sizeof(*info); i++) { 795 + size += info->length; 796 + info++; 797 + } 798 + 799 + kfree(info); 800 + return size; 801 + 802 + err: 803 + kfree(info); 804 + return ret; 805 + } 806 + 807 + static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, 808 + const char *compatible, 809 + int size, 810 + nvmem_reg_read_t reg_read) 811 + { 812 + struct nvmem_device *nvmem = NULL; 813 + struct nvmem_config config = {}; 814 + struct device_node *np; 815 + 816 + /* DT binding is optional */ 817 + np = of_get_compatible_child(mtd->dev.of_node, compatible); 818 + 819 + /* OTP nvmem will be registered on the physical device */ 820 + config.dev = mtd->dev.parent; 821 + /* just reuse the compatible as name */ 822 + config.name = compatible; 823 + config.id = NVMEM_DEVID_NONE; 824 + config.owner = THIS_MODULE; 825 + config.type = NVMEM_TYPE_OTP; 826 + config.root_only = true; 827 + config.reg_read = reg_read; 828 + config.size = size; 829 + config.of_node = np; 830 + config.priv = mtd; 831 + 832 + nvmem = nvmem_register(&config); 833 + /* Just ignore if there is no NVMEM support in the kernel */ 834 + if (IS_ERR(nvmem) && PTR_ERR(nvmem) == -EOPNOTSUPP) 835 + nvmem = NULL; 836 + 837 + of_node_put(np); 838 + 839 + return nvmem; 840 + } 841 + 842 + static int mtd_nvmem_user_otp_reg_read(void *priv, unsigned int offset, 843 + void *val, size_t bytes) 844 + { 845 + struct mtd_info *mtd = priv; 846 + size_t retlen; 847 + int ret; 848 + 849 + ret = mtd_read_user_prot_reg(mtd, offset, bytes, &retlen, val); 850 + if (ret) 851 + return ret; 852 + 853 + return retlen == bytes ? 0 : -EIO; 854 + } 855 + 856 + static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset, 857 + void *val, size_t bytes) 858 + { 859 + struct mtd_info *mtd = priv; 860 + size_t retlen; 861 + int ret; 862 + 863 + ret = mtd_read_fact_prot_reg(mtd, offset, bytes, &retlen, val); 864 + if (ret) 865 + return ret; 866 + 867 + return retlen == bytes ? 0 : -EIO; 868 + } 869 + 870 + static int mtd_otp_nvmem_add(struct mtd_info *mtd) 871 + { 872 + struct nvmem_device *nvmem; 873 + ssize_t size; 874 + int err; 875 + 876 + if (mtd->_get_user_prot_info && mtd->_read_user_prot_reg) { 877 + size = mtd_otp_size(mtd, true); 878 + if (size < 0) 879 + return size; 880 + 881 + if (size > 0) { 882 + nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, 883 + mtd_nvmem_user_otp_reg_read); 884 + if (IS_ERR(nvmem)) { 885 + dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); 886 + return PTR_ERR(nvmem); 887 + } 888 + mtd->otp_user_nvmem = nvmem; 889 + } 890 + } 891 + 892 + if (mtd->_get_fact_prot_info && mtd->_read_fact_prot_reg) { 893 + size = mtd_otp_size(mtd, false); 894 + if (size < 0) { 895 + err = size; 896 + goto err; 897 + } 898 + 899 + if (size > 0) { 900 + nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, 901 + mtd_nvmem_fact_otp_reg_read); 902 + if (IS_ERR(nvmem)) { 903 + dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); 904 + err = PTR_ERR(nvmem); 905 + goto err; 906 + } 907 + mtd->otp_factory_nvmem = nvmem; 908 + } 909 + } 910 + 911 + return 0; 912 + 913 + err: 914 + if (mtd->otp_user_nvmem) 915 + nvmem_unregister(mtd->otp_user_nvmem); 916 + return err; 917 + } 918 + 779 919 /** 780 920 * mtd_device_parse_register - parse partitions and register an MTD device. 781 921 * ··· 991 851 register_reboot_notifier(&mtd->reboot_notifier); 992 852 } 993 853 854 + ret = mtd_otp_nvmem_add(mtd); 855 + 994 856 out: 995 857 if (ret && device_is_registered(&mtd->dev)) 996 858 del_mtd_device(mtd); ··· 1013 871 1014 872 if (master->_reboot) 1015 873 unregister_reboot_notifier(&master->reboot_notifier); 874 + 875 + if (master->otp_user_nvmem) 876 + nvmem_unregister(master->otp_user_nvmem); 877 + 878 + if (master->otp_factory_nvmem) 879 + nvmem_unregister(master->otp_factory_nvmem); 1016 880 1017 881 err = del_mtd_partitions(master); 1018 882 if (err)
+2
include/linux/mtd/mtd.h
··· 380 380 int usecount; 381 381 struct mtd_debug_info dbg; 382 382 struct nvmem_device *nvmem; 383 + struct nvmem_device *otp_user_nvmem; 384 + struct nvmem_device *otp_factory_nvmem; 383 385 384 386 /* 385 387 * Parent device from the MTD partition point of view.