^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2019-2020 Linaro Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "qcom_pil_info.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * The PIL relocation information region is used to communicate memory regions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * occupied by co-processor firmware for post mortem crash analysis.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * It consists of an array of entries with an 8 byte textual identifier of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * region followed by a 64 bit base address and 32 bit size, both little
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * endian.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define PIL_RELOC_NAME_LEN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define PIL_RELOC_ENTRY_SIZE (PIL_RELOC_NAME_LEN + sizeof(__le64) + sizeof(__le32))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct pil_reloc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) size_t num_entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static struct pil_reloc _reloc __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static DEFINE_MUTEX(pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static int qcom_pil_info_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct resource imem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Already initialized? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (_reloc.base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) np = of_find_compatible_node(NULL, NULL, "qcom,pil-reloc-info");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ret = of_address_to_resource(np, 0, &imem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) base = ioremap(imem.start, resource_size(&imem));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) pr_err("failed to map PIL relocation info region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) memset_io(base, 0, resource_size(&imem));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) _reloc.base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) _reloc.num_entries = (u32)resource_size(&imem) / PIL_RELOC_ENTRY_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * qcom_pil_info_store() - store PIL information of image in IMEM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * @image: name of the image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @base: base address of the loaded image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * @size: size of the loaded image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * Return: 0 on success, negative errno on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) char buf[PIL_RELOC_NAME_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) void __iomem *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) mutex_lock(&pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ret = qcom_pil_info_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mutex_unlock(&pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) for (i = 0; i < _reloc.num_entries; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) entry = _reloc.base + i * PIL_RELOC_ENTRY_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) memcpy_fromio(buf, entry, PIL_RELOC_NAME_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * An empty record means we didn't find it, given that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * records are packed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!buf[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) goto found_unused;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (!strncmp(buf, image, PIL_RELOC_NAME_LEN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) goto found_existing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) pr_warn("insufficient PIL info slots\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) mutex_unlock(&pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) found_unused:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) memcpy_toio(entry, image, strnlen(image, PIL_RELOC_NAME_LEN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) found_existing:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* Use two writel() as base is only aligned to 4 bytes on odd entries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) writel(base, entry + PIL_RELOC_NAME_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) writel((u64)base >> 32, entry + PIL_RELOC_NAME_LEN + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) writel(size, entry + PIL_RELOC_NAME_LEN + sizeof(__le64));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) mutex_unlock(&pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) EXPORT_SYMBOL_GPL(qcom_pil_info_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void __exit pil_reloc_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mutex_lock(&pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) iounmap(_reloc.base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) _reloc.base = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mutex_unlock(&pil_reloc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) module_exit(pil_reloc_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) MODULE_DESCRIPTION("Qualcomm PIL relocation info");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) MODULE_LICENSE("GPL v2");