0001
0002
0003
0004
0005 #include <linux/kernel.h>
0006 #include <linux/module.h>
0007 #include <linux/mutex.h>
0008 #include <linux/of_address.h>
0009 #include "qcom_pil_info.h"
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #define PIL_RELOC_NAME_LEN 8
0020 #define PIL_RELOC_ENTRY_SIZE (PIL_RELOC_NAME_LEN + sizeof(__le64) + sizeof(__le32))
0021
0022 struct pil_reloc {
0023 void __iomem *base;
0024 size_t num_entries;
0025 };
0026
0027 static struct pil_reloc _reloc __read_mostly;
0028 static DEFINE_MUTEX(pil_reloc_lock);
0029
0030 static int qcom_pil_info_init(void)
0031 {
0032 struct device_node *np;
0033 struct resource imem;
0034 void __iomem *base;
0035 int ret;
0036
0037
0038 if (_reloc.base)
0039 return 0;
0040
0041 np = of_find_compatible_node(NULL, NULL, "qcom,pil-reloc-info");
0042 if (!np)
0043 return -ENOENT;
0044
0045 ret = of_address_to_resource(np, 0, &imem);
0046 of_node_put(np);
0047 if (ret < 0)
0048 return ret;
0049
0050 base = ioremap(imem.start, resource_size(&imem));
0051 if (!base) {
0052 pr_err("failed to map PIL relocation info region\n");
0053 return -ENOMEM;
0054 }
0055
0056 memset_io(base, 0, resource_size(&imem));
0057
0058 _reloc.base = base;
0059 _reloc.num_entries = (u32)resource_size(&imem) / PIL_RELOC_ENTRY_SIZE;
0060
0061 return 0;
0062 }
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size)
0073 {
0074 char buf[PIL_RELOC_NAME_LEN];
0075 void __iomem *entry;
0076 int ret;
0077 int i;
0078
0079 mutex_lock(&pil_reloc_lock);
0080 ret = qcom_pil_info_init();
0081 if (ret < 0) {
0082 mutex_unlock(&pil_reloc_lock);
0083 return ret;
0084 }
0085
0086 for (i = 0; i < _reloc.num_entries; i++) {
0087 entry = _reloc.base + i * PIL_RELOC_ENTRY_SIZE;
0088
0089 memcpy_fromio(buf, entry, PIL_RELOC_NAME_LEN);
0090
0091
0092
0093
0094
0095 if (!buf[0])
0096 goto found_unused;
0097
0098 if (!strncmp(buf, image, PIL_RELOC_NAME_LEN))
0099 goto found_existing;
0100 }
0101
0102 pr_warn("insufficient PIL info slots\n");
0103 mutex_unlock(&pil_reloc_lock);
0104 return -ENOMEM;
0105
0106 found_unused:
0107 memcpy_toio(entry, image, strnlen(image, PIL_RELOC_NAME_LEN));
0108 found_existing:
0109
0110 writel(base, entry + PIL_RELOC_NAME_LEN);
0111 writel((u64)base >> 32, entry + PIL_RELOC_NAME_LEN + 4);
0112 writel(size, entry + PIL_RELOC_NAME_LEN + sizeof(__le64));
0113 mutex_unlock(&pil_reloc_lock);
0114
0115 return 0;
0116 }
0117 EXPORT_SYMBOL_GPL(qcom_pil_info_store);
0118
0119 static void __exit pil_reloc_exit(void)
0120 {
0121 mutex_lock(&pil_reloc_lock);
0122 iounmap(_reloc.base);
0123 _reloc.base = NULL;
0124 mutex_unlock(&pil_reloc_lock);
0125 }
0126 module_exit(pil_reloc_exit);
0127
0128 MODULE_DESCRIPTION("Qualcomm PIL relocation info");
0129 MODULE_LICENSE("GPL v2");