Skip to content

Commit 68d0b5f

Browse files
iuliana-prodansmb49
authored andcommitted
remoteproc: imx_dsp_rproc: Add custom memory copy implementation for i.MX DSP Cores
BugLink: https://bugs.launchpad.net/bugs/2028808 [ Upstream commit 408ec1f ] The IRAM is part of the HiFi DSP. According to hardware specification only 32-bits write are allowed otherwise we get a Kernel panic. Therefore add a custom memory copy and memset functions to deal with the above restriction. Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com> Link: https://lore.kernel.org/r/20230221170356.27923-1-iuliana.prodan@oss.nxp.com Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Kamal Mostafa <kamal@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
1 parent dc95d6e commit 68d0b5f

1 file changed

Lines changed: 186 additions & 1 deletion

File tree

drivers/remoteproc/imx_dsp_rproc.c

Lines changed: 186 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,191 @@ static void imx_dsp_rproc_kick(struct rproc *rproc, int vqid)
721721
dev_err(dev, "%s: failed (%d, err:%d)\n", __func__, vqid, err);
722722
}
723723

724+
/*
725+
* Custom memory copy implementation for i.MX DSP Cores
726+
*
727+
* The IRAM is part of the HiFi DSP.
728+
* According to hw specs only 32-bits writes are allowed.
729+
*/
730+
static int imx_dsp_rproc_memcpy(void *dest, const void *src, size_t size)
731+
{
732+
const u8 *src_byte = src;
733+
const u32 *source = src;
734+
u32 affected_mask;
735+
u32 *dst = dest;
736+
int i, q, r;
737+
u32 tmp;
738+
739+
/* destination must be 32bit aligned */
740+
if (!IS_ALIGNED((uintptr_t)dest, 4))
741+
return -EINVAL;
742+
743+
q = size / 4;
744+
r = size % 4;
745+
746+
/* copy data in units of 32 bits at a time */
747+
for (i = 0; i < q; i++)
748+
writel(source[i], &dst[i]);
749+
750+
if (r) {
751+
affected_mask = GENMASK(8 * r, 0);
752+
753+
/*
754+
* first read the 32bit data of dest, then change affected
755+
* bytes, and write back to dest.
756+
* For unaffected bytes, it should not be changed
757+
*/
758+
tmp = readl(dest + q * 4);
759+
tmp &= ~affected_mask;
760+
761+
/* avoid reading after end of source */
762+
for (i = 0; i < r; i++)
763+
tmp |= (src_byte[q * 4 + i] << (8 * i));
764+
765+
writel(tmp, dest + q * 4);
766+
}
767+
768+
return 0;
769+
}
770+
771+
/*
772+
* Custom memset implementation for i.MX DSP Cores
773+
*
774+
* The IRAM is part of the HiFi DSP.
775+
* According to hw specs only 32-bits writes are allowed.
776+
*/
777+
static int imx_dsp_rproc_memset(void *addr, u8 value, size_t size)
778+
{
779+
u32 tmp_val = value;
780+
u32 *tmp_dst = addr;
781+
u32 affected_mask;
782+
int q, r;
783+
u32 tmp;
784+
785+
/* destination must be 32bit aligned */
786+
if (!IS_ALIGNED((uintptr_t)addr, 4))
787+
return -EINVAL;
788+
789+
tmp_val |= tmp_val << 8;
790+
tmp_val |= tmp_val << 16;
791+
792+
q = size / 4;
793+
r = size % 4;
794+
795+
while (q--)
796+
writel(tmp_val, tmp_dst++);
797+
798+
if (r) {
799+
affected_mask = GENMASK(8 * r, 0);
800+
801+
/*
802+
* first read the 32bit data of addr, then change affected
803+
* bytes, and write back to addr.
804+
* For unaffected bytes, it should not be changed
805+
*/
806+
tmp = readl(tmp_dst);
807+
tmp &= ~affected_mask;
808+
809+
tmp |= (tmp_val & affected_mask);
810+
writel(tmp, tmp_dst);
811+
}
812+
813+
return 0;
814+
}
815+
816+
/*
817+
* imx_dsp_rproc_elf_load_segments() - load firmware segments to memory
818+
* @rproc: remote processor which will be booted using these fw segments
819+
* @fw: the ELF firmware image
820+
*
821+
* This function loads the firmware segments to memory, where the remote
822+
* processor expects them.
823+
*
824+
* Return: 0 on success and an appropriate error code otherwise
825+
*/
826+
static int imx_dsp_rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
827+
{
828+
struct device *dev = &rproc->dev;
829+
const void *ehdr, *phdr;
830+
int i, ret = 0;
831+
u16 phnum;
832+
const u8 *elf_data = fw->data;
833+
u8 class = fw_elf_get_class(fw);
834+
u32 elf_phdr_get_size = elf_size_of_phdr(class);
835+
836+
ehdr = elf_data;
837+
phnum = elf_hdr_get_e_phnum(class, ehdr);
838+
phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
839+
840+
/* go through the available ELF segments */
841+
for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
842+
u64 da = elf_phdr_get_p_paddr(class, phdr);
843+
u64 memsz = elf_phdr_get_p_memsz(class, phdr);
844+
u64 filesz = elf_phdr_get_p_filesz(class, phdr);
845+
u64 offset = elf_phdr_get_p_offset(class, phdr);
846+
u32 type = elf_phdr_get_p_type(class, phdr);
847+
void *ptr;
848+
849+
if (type != PT_LOAD || !memsz)
850+
continue;
851+
852+
dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
853+
type, da, memsz, filesz);
854+
855+
if (filesz > memsz) {
856+
dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
857+
filesz, memsz);
858+
ret = -EINVAL;
859+
break;
860+
}
861+
862+
if (offset + filesz > fw->size) {
863+
dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
864+
offset + filesz, fw->size);
865+
ret = -EINVAL;
866+
break;
867+
}
868+
869+
if (!rproc_u64_fit_in_size_t(memsz)) {
870+
dev_err(dev, "size (%llx) does not fit in size_t type\n",
871+
memsz);
872+
ret = -EOVERFLOW;
873+
break;
874+
}
875+
876+
/* grab the kernel address for this device address */
877+
ptr = rproc_da_to_va(rproc, da, memsz, NULL);
878+
if (!ptr) {
879+
dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
880+
memsz);
881+
ret = -EINVAL;
882+
break;
883+
}
884+
885+
/* put the segment where the remote processor expects it */
886+
if (filesz) {
887+
ret = imx_dsp_rproc_memcpy(ptr, elf_data + offset, filesz);
888+
if (ret) {
889+
dev_err(dev, "memory copy failed for da 0x%llx memsz 0x%llx\n",
890+
da, memsz);
891+
break;
892+
}
893+
}
894+
895+
/* zero out remaining memory for this segment */
896+
if (memsz > filesz) {
897+
ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz);
898+
if (ret) {
899+
dev_err(dev, "memset failed for da 0x%llx memsz 0x%llx\n",
900+
da, memsz);
901+
break;
902+
}
903+
}
904+
}
905+
906+
return ret;
907+
}
908+
724909
static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
725910
{
726911
if (rproc_elf_load_rsc_table(rproc, fw))
@@ -735,7 +920,7 @@ static const struct rproc_ops imx_dsp_rproc_ops = {
735920
.start = imx_dsp_rproc_start,
736921
.stop = imx_dsp_rproc_stop,
737922
.kick = imx_dsp_rproc_kick,
738-
.load = rproc_elf_load_segments,
923+
.load = imx_dsp_rproc_elf_load_segments,
739924
.parse_fw = imx_dsp_rproc_parse_fw,
740925
.sanity_check = rproc_elf_sanity_check,
741926
.get_boot_addr = rproc_elf_get_boot_addr,

0 commit comments

Comments
 (0)