diff options
author | Ansuel Smith <ansuelsmth@gmail.com> | 2021-03-01 01:06:22 +0100 |
---|---|---|
committer | Petr Štetiar <ynezz@true.cz> | 2021-05-07 07:05:16 +0200 |
commit | c864f587a25effa1cb18c63ec7eee6a966618b59 (patch) | |
tree | a172684c56ec5a899b4592c2af5655649f67bd9f | |
parent | cde218d14b118e76099b0b0af992b3d3126c8035 (diff) | |
download | upstream-c864f587a25effa1cb18c63ec7eee6a966618b59.tar.gz upstream-c864f587a25effa1cb18c63ec7eee6a966618b59.tar.bz2 upstream-c864f587a25effa1cb18c63ec7eee6a966618b59.zip |
ipq806x: backport mtd adm and smem driver
- Backport mtd adm driver from kernel 5.12
- Backport mtd parser smem from kernel 5.11
- Fix mtd rootfs patch
- Update qcom,smem compatible to qcom,smem-parts
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
16 files changed, 806 insertions, 896 deletions
diff --git a/target/linux/ipq806x/config-5.4 b/target/linux/ipq806x/config-5.4 index 78a9ad7077..c582b7a52b 100644 --- a/target/linux/ipq806x/config-5.4 +++ b/target/linux/ipq806x/config-5.4 @@ -313,7 +313,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_NAND_CORE=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_QCOM=y -CONFIG_MTD_QCOM_SMEM_PARTS=y +CONFIG_MTD_QCOMSMEM_PARTS=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPLIT_FIRMWARE=y diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts index b2fdc427e2..29476e3877 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts @@ -30,7 +30,7 @@ &flash { partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; @@ -66,7 +66,7 @@ nand-ecc-step-size = <512>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts index 6ba3d70808..914c370552 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts @@ -38,7 +38,7 @@ &flash { partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; @@ -78,7 +78,7 @@ nand-ecc-step-size = <512>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts index 15ed5b4773..ccefc23011 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts @@ -179,7 +179,7 @@ nand-ecc-step-size = <512>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts index 119598d074..34b9c5fc87 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts @@ -182,7 +182,7 @@ reg = <0>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts index 712910c261..9b14bb2c29 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts @@ -184,7 +184,7 @@ reg = <0>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch deleted file mode 100644 index 6aa404c8c5..0000000000 --- a/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch +++ /dev/null @@ -1,282 +0,0 @@ -From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Thu, 9 Mar 2017 08:18:08 +0100 -Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms - -On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is -used to store partition layout. This new parser can now be used to read -SMEM and use it to register an MTD layout according to its content. - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> -Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org> ---- - drivers/mtd/parsers/Kconfig | 7 ++ - drivers/mtd/parsers/Makefile | 1 + - drivers/mtd/parsers/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 236 insertions(+) - create mode 100644 drivers/mtd/parsers/qcom_smem_part.c - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -119,6 +119,13 @@ config MTD_PARSER_TRX - This driver will parse TRX header and report at least two partitions: - kernel and rootfs. - -+config MTD_QCOM_SMEM_PARTS -+ tristate "QCOM SMEM partitioning support" -+ depends on QCOM_SMEM -+ help -+ This provides partitions parser for QCOM devices using SMEM -+ such as IPQ806x. -+ - config MTD_SHARPSL_PARTS - tristate "Sharp SL Series NAND flash partition parser" - depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST ---- a/drivers/mtd/parsers/Makefile -+++ b/drivers/mtd/parsers/Makefile -@@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o - obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o -+obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o - obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o ---- /dev/null -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -0,0 +1,235 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/device.h> -+#include <linux/slab.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/partitions.h> -+#include <linux/spi/spi.h> -+#include <linux/module.h> -+ -+#include <linux/soc/qcom/smem.h> -+ -+/* Processor/host identifier for the application processor */ -+#define SMEM_HOST_APPS 0 -+ -+/* SMEM items index */ -+#define SMEM_AARM_PARTITION_TABLE 9 -+#define SMEM_BOOT_FLASH_TYPE 421 -+#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 -+ -+/* SMEM Flash types */ -+#define SMEM_FLASH_NAND 2 -+#define SMEM_FLASH_SPI 6 -+ -+#define SMEM_PART_NAME_SZ 16 -+#define SMEM_PARTS_MAX 32 -+ -+struct smem_partition { -+ char name[SMEM_PART_NAME_SZ]; -+ __le32 start; -+ __le32 size; -+ __le32 attr; -+}; -+ -+struct smem_partition_table { -+ u8 magic[8]; -+ __le32 version; -+ __le32 len; -+ struct smem_partition parts[SMEM_PARTS_MAX]; -+}; -+ -+/* SMEM Magic values in partition table */ -+static const u8 SMEM_PTABLE_MAGIC[] = { -+ 0xaa, 0x73, 0xee, 0x55, -+ 0xdb, 0xbd, 0x5e, 0xe3, -+}; -+ -+static int qcom_smem_get_flash_blksz(u64 **smem_blksz) -+{ -+ size_t size; -+ -+ *smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, -+ &size); -+ -+ if (IS_ERR(*smem_blksz)) { -+ pr_err("Unable to read flash blksz from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_blksz)) { -+ pr_err("Invalid flash blksz size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_type(u64 **smem_flash_type) -+{ -+ size_t size; -+ -+ *smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, -+ &size); -+ -+ if (IS_ERR(*smem_flash_type)) { -+ pr_err("Unable to read flash type from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_flash_type)) { -+ pr_err("Invalid flash type size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) -+{ -+ size_t size; -+ -+ *pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, -+ &size); -+ -+ if (IS_ERR(*pparts)) { -+ pr_err("Unable to read partition table from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ return 0; -+} -+ -+static int of_dev_node_match(struct device *dev, const void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static bool is_spi_device(struct device_node *np) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); -+ if (!dev) -+ return false; -+ -+ put_device(dev); -+ return true; -+} -+ -+static int parse_qcom_smem_partitions(struct mtd_info *master, -+ const struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ struct smem_partition_table *smem_parts; -+ u64 *smem_flash_type, *smem_blksz; -+ struct mtd_partition *mtd_parts; -+ struct device_node *of_node = master->dev.of_node; -+ int i, ret; -+ -+ /* -+ * SMEM will only store the partition table of the boot device. -+ * If this is not the boot device, do not return any partition. -+ */ -+ ret = qcom_smem_get_flash_type(&smem_flash_type); -+ if (ret < 0) -+ return ret; -+ -+ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) -+ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) -+ return 0; -+ -+ /* -+ * Just for sanity purpose, make sure the block size in SMEM matches the -+ * block size of the MTD device -+ */ -+ ret = qcom_smem_get_flash_blksz(&smem_blksz); -+ if (ret < 0) -+ return ret; -+ -+ if (*smem_blksz != master->erasesize) { -+ pr_err("SMEM block size differs from MTD block size\n"); -+ return -EINVAL; -+ } -+ -+ /* Get partition pointer from SMEM */ -+ ret = qcom_smem_get_flash_partitions(&smem_parts); -+ if (ret < 0) -+ return ret; -+ -+ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, -+ sizeof(SMEM_PTABLE_MAGIC))) { -+ pr_err("SMEM partition magic invalid\n"); -+ return -EINVAL; -+ } -+ -+ /* Allocate and populate the mtd structures */ -+ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), -+ GFP_KERNEL); -+ if (!mtd_parts) -+ return -ENOMEM; -+ -+ for (i = 0; i < smem_parts->len; i++) { -+ struct smem_partition *s_part = &smem_parts->parts[i]; -+ struct mtd_partition *m_part = &mtd_parts[i]; -+ -+ m_part->name = s_part->name; -+ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); -+ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); -+ -+ /* -+ * The last SMEM partition may have its size marked as -+ * something like 0xffffffff, which means "until the end of the -+ * flash device". In this case, truncate it. -+ */ -+ if (m_part->offset + m_part->size > master->size) -+ m_part->size = master->size - m_part->offset; -+ } -+ -+ *pparts = mtd_parts; -+ -+ return smem_parts->len; -+} -+ -+static const struct of_device_id qcom_smem_of_match_table[] = { -+ { .compatible = "qcom,smem" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table); -+ -+static struct mtd_part_parser qcom_smem_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_qcom_smem_partitions, -+ .name = "qcom-smem", -+ .of_match_table = qcom_smem_of_match_table, -+}; -+ -+static int __init qcom_smem_parser_init(void) -+{ -+ register_mtd_parser(&qcom_smem_parser); -+ return 0; -+} -+ -+static void __exit qcom_smem_parser_exit(void) -+{ -+ deregister_mtd_parser(&qcom_smem_parser); -+} -+ -+module_init(qcom_smem_parser_init); -+module_exit(qcom_smem_parser_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>"); -+MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); diff --git a/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch deleted file mode 100644 index ff6f6edf49..0000000000 --- a/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 -From: John Crispin <john@phrozen.org> -Date: Thu, 9 Mar 2017 09:31:44 +0100 -Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting - -Signed-off-by: John Crispin <john@phrozen.org> ---- - drivers/mtd/parsers/qcom_smem_part.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/mtd/parsers/qcom_smem_part.c -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -189,6 +189,10 @@ static int parse_qcom_smem_partitions(st - m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); - m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); - -+ /* "rootfs" conflicts with OpenWrt auto mounting */ -+ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs")) -+ m_part->name = "ubi"; -+ - /* - * The last SMEM partition may have its size marked as - * something like 0xffffffff, which means "until the end of the diff --git a/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch index aa7d2e791e..45062d52fc 100644 --- a/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch +++ b/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -1,86 +1,95 @@ -From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001 -From: Thomas Pedersen <twp@codeaurora.org> -Date: Mon, 16 May 2016 17:58:51 -0700 -Subject: [PATCH 02/69] dmaengine: Add ADM driver - -Original patch by Andy Gross. +From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 +From: Jonathan McDowell <noodles@earth.li> +Date: Sat, 14 Nov 2020 14:02:33 +0000 +Subject: dmaengine: qcom: Add ADM driver Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA controller found in the MSM8x60 and IPQ/APQ8064 platforms. The ADM supports both memory to memory transactions and memory -to/from peripheral device transactions. The controller also provides flow -control capabilities for transactions to/from peripheral devices. +to/from peripheral device transactions. The controller also provides +flow control capabilities for transactions to/from peripheral devices. + +The initial release of this driver supports slave transfers to/from +peripherals and also incorporates CRCI (client rate control interface) +flow control. -The initial release of this driver supports slave transfers to/from peripherals -and also incorporates CRCI (client rate control interface) flow control. +The hardware only supports a 32 bit physical address, so specifying +!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to +spend effort on kludging things in the code that will never actually be +needed on real hardware. Signed-off-by: Andy Gross <agross@codeaurora.org> Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +Signed-off-by: Jonathan McDowell <noodles@earth.li> +Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li +Signed-off-by: Vinod Koul <vkoul@kernel.org> --- - drivers/dma/qcom/Kconfig | 10 + + drivers/dma/qcom/Kconfig | 11 + drivers/dma/qcom/Makefile | 1 + - drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 911 insertions(+) + drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 915 insertions(+) create mode 100644 drivers/dma/qcom/qcom_adm.c +diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig +index 3bcb689162c67..0389d60d2604a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig -@@ -28,3 +28,13 @@ config QCOM_HIDMA - (user to kernel, kernel to kernel, etc.). It only supports - memcpy interface. The core is not intended for general - purpose slave DMA. -+ +@@ -1,4 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0-only +config QCOM_ADM + tristate "Qualcomm ADM support" -+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) ++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS -+ ---help--- -+ Enable support for the Qualcomm ADM DMA controller. This controller -+ provides DMA capabilities for both general purpose and on-chip -+ peripheral devices. ++ help ++ Enable support for the Qualcomm Application Data Mover (ADM) DMA ++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. ++ This controller provides DMA capabilities for both general purpose ++ and on-chip peripheral devices. ++ + config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) +diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile +index 1ae92da88b0c9..346e643fbb6db 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg - hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o - obj-$(CONFIG_QCOM_HIDMA) += hdma.o - hdma-objs := hidma_ll.o hidma.o hidma_dbg.o +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_ADM) += qcom_adm.o + obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o + obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o +diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c +new file mode 100644 +index 0000000000000..9b6f8e050ecce --- /dev/null +++ b/drivers/dma/qcom/qcom_adm.c -@@ -0,0 +1,914 @@ +@@ -0,0 +1,903 @@ ++// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * + */ + -+#include <linux/kernel.h> -+#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/dmaengine.h> ++#include <linux/dma-mapping.h> +#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/module.h> +#include <linux/interrupt.h> -+#include <linux/dma-mapping.h> -+#include <linux/scatterlist.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_dma.h> ++#include <linux/platform_device.h> +#include <linux/reset.h> -+#include <linux/clk.h> -+#include <linux/dmaengine.h> ++#include <linux/scatterlist.h> ++#include <linux/slab.h> + +#include "../dmaengine.h" +#include "../virt-dma.h" @@ -90,10 +99,10 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +#define ADM_CI_MULTI 0x4 +#define ADM_CRCI_MULTI 0x4 +#define ADM_EE_MULTI 0x800 -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) -+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) +#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) +#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) +#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) @@ -102,62 +111,62 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) +#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) -+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI) ++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) +#define ADM_GP_CTL 0x3d8 -+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \ ++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ + ADM_EE_OFFS(ee)) + +/* channel status */ -+#define ADM_CH_STATUS_VALID BIT(1) ++#define ADM_CH_STATUS_VALID BIT(1) + +/* channel result */ -+#define ADM_CH_RSLT_VALID BIT(31) -+#define ADM_CH_RSLT_ERR BIT(3) -+#define ADM_CH_RSLT_FLUSH BIT(2) -+#define ADM_CH_RSLT_TPD BIT(1) ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) + +/* channel conf */ +#define ADM_CH_CONF_SHADOW_EN BIT(12) +#define ADM_CH_CONF_MPU_DISABLE BIT(11) +#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) +#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) -+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11)) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) + +/* channel result conf */ +#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) +#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) + +/* CRCI CTL */ -+#define ADM_CRCI_CTL_MUX_SEL BIT(18) -+#define ADM_CRCI_CTL_RST BIT(17) ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) + +/* CI configuration */ -+#define ADM_CI_RANGE_END(x) (x << 24) -+#define ADM_CI_RANGE_START(x) (x << 16) -+#define ADM_CI_BURST_4_WORDS BIT(2) -+#define ADM_CI_BURST_8_WORDS BIT(3) ++#define ADM_CI_RANGE_END(x) ((x) << 24) ++#define ADM_CI_RANGE_START(x) ((x) << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) + +/* GP CTL */ -+#define ADM_GP_CTL_LP_EN BIT(12) -+#define ADM_GP_CTL_LP_CNT(x) (x << 8) ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) + +/* Command pointer list entry */ -+#define ADM_CPLE_LP BIT(31) -+#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) + +/* Command list entry */ -+#define ADM_CMD_LC BIT(31) -+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) -+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) + -+#define ADM_CMD_TYPE_SINGLE 0x0 -+#define ADM_CMD_TYPE_BOX 0x3 ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 + -+#define ADM_CRCI_MUX_SEL BIT(4) -+#define ADM_DESC_ALIGN 8 -+#define ADM_MAX_XFER (SZ_64K-1) -+#define ADM_MAX_ROWS (SZ_64K-1) -+#define ADM_MAX_CHANNELS 16 ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K - 1) ++#define ADM_MAX_ROWS (SZ_64K - 1) ++#define ADM_MAX_CHANNELS 16 + +struct adm_desc_hw_box { + u32 cmd; @@ -255,7 +264,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + case 32: + case 64: + case 128: -+ ret = ffs(burst>>4) - 1; ++ ret = ffs(burst >> 4) - 1; + break; + case 192: + ret = 4; @@ -281,9 +290,10 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * @burst: Burst size of transaction + * @direction: DMA transfer direction + */ -+static void *adm_process_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, u32 crci, u32 burst, -+ enum dma_transfer_direction direction) ++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, u32 crci, ++ u32 burst, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_box *box_desc = NULL; + struct adm_desc_hw_single *single_desc; @@ -349,9 +359,9 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * @sg: Scatterlist entry + * @direction: DMA transfer direction + */ -+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, -+ enum dma_transfer_direction direction) ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_single *single_desc; + u32 remainder = sg_dma_len(sg); @@ -398,9 +408,11 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * @context: transfer context (unused) + */ +static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_transfer_direction direction, unsigned long flags, -+ void *context) ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_transfer_direction direction, ++ unsigned long flags, ++ void *context) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct adm_device *adev = achan->adev; @@ -427,7 +439,6 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* if using flow control, validate burst and crci values */ + if (achan->slave.device_fc) { -+ + blk_size = adm_get_blksize(burst); + if (blk_size < 0) { + dev_err(adev->dev, "invalid burst value: %d\n", @@ -455,7 +466,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + } + } + -+ async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC); ++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); + if (!async_desc) + return ERR_PTR(-ENOMEM); + @@ -468,7 +479,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + box_count * sizeof(struct adm_desc_hw_box) + + sizeof(*cple) + 2 * ADM_DESC_ALIGN; + -+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC); ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); + if (!async_desc->cpl) + goto free; + @@ -483,10 +494,10 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + if (achan->slave.device_fc) + desc = adm_process_fc_descriptors(achan, desc, sg, crci, -+ burst, direction); ++ burst, direction); + else + desc = adm_process_non_fc_descriptors(achan, desc, sg, -+ direction); ++ direction); + } + + async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, @@ -532,7 +543,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* send flush command to terminate current transaction */ + writel_relaxed(0x0, -+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); + + spin_unlock_irqrestore(&achan->vc.lock, flags); + @@ -586,7 +597,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + adev->regs + ADM_CH_CONF(achan->id)); + + writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, -+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + + achan->initialized = 1; + } @@ -594,7 +605,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + /* set the crci block size if this transaction requires CRCI */ + if (async_desc->crci) { + writel(async_desc->mux | async_desc->blk_size, -+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); + } + + /* make sure IRQ enable doesn't get reordered */ @@ -602,7 +613,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* write next command list out to the CMD FIFO */ + writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, -+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); +} + +/** @@ -628,7 +639,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + if (srcs & BIT(i)) { + status = readl_relaxed(adev->regs + -+ ADM_CH_STATUS_SD(i, adev->ee)); ++ ADM_CH_STATUS_SD(i, adev->ee)); + + /* if no result present, skip */ + if (!(status & ADM_CH_STATUS_VALID)) @@ -673,7 +684,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * Return status of dma transaction + */ +static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, -+ struct dma_tx_state *txstate) ++ struct dma_tx_state *txstate) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct virt_dma_desc *vd; @@ -697,7 +708,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * residue is either the full length if it is in the issued list, or 0 + * if it is in progress. We have no reliable way of determining + * anything inbetween -+ */ ++ */ + dma_set_residue(txstate, residue); + + if (achan->error) @@ -741,7 +752,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +} + +static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, -+ u32 index) ++ u32 index) +{ + achan->id = index; + achan->adev = adev; @@ -753,7 +764,6 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +static int adm_dma_probe(struct platform_device *pdev) +{ + struct adm_device *adev; -+ struct resource *iores; + int ret; + u32 i; + @@ -763,8 +773,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + adev->dev = &pdev->dev; + -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ adev->regs = devm_ioremap_resource(&pdev->dev, iores); ++ adev->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adev->regs)) + return PTR_ERR(adev->regs); + @@ -782,50 +791,44 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + if (IS_ERR(adev->core_clk)) + return PTR_ERR(adev->core_clk); + -+ ret = clk_prepare_enable(adev->core_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable core clock\n"); -+ return ret; -+ } -+ + adev->iface_clk = devm_clk_get(adev->dev, "iface"); -+ if (IS_ERR(adev->iface_clk)) { -+ ret = PTR_ERR(adev->iface_clk); -+ goto err_disable_core_clk; -+ } -+ -+ ret = clk_prepare_enable(adev->iface_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); -+ goto err_disable_core_clk; -+ } ++ if (IS_ERR(adev->iface_clk)) ++ return PTR_ERR(adev->iface_clk); + -+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk"); ++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); + if (IS_ERR(adev->clk_reset)) { + dev_err(adev->dev, "failed to get ADM0 reset\n"); -+ ret = PTR_ERR(adev->clk_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->clk_reset); + } + -+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0"); ++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); + if (IS_ERR(adev->c0_reset)) { + dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); -+ ret = PTR_ERR(adev->c0_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->c0_reset); + } + -+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1"); ++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); + if (IS_ERR(adev->c1_reset)) { + dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); -+ ret = PTR_ERR(adev->c1_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->c1_reset); + } + -+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2"); ++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); + if (IS_ERR(adev->c2_reset)) { + dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); -+ ret = PTR_ERR(adev->c2_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->c2_reset); ++ } ++ ++ ret = clk_prepare_enable(adev->core_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable core clock\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(adev->iface_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); ++ goto err_disable_core_clk; + } + + reset_control_assert(adev->clk_reset); @@ -833,13 +836,15 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + reset_control_assert(adev->c1_reset); + reset_control_assert(adev->c2_reset); + ++ udelay(2); ++ + reset_control_deassert(adev->clk_reset); + reset_control_deassert(adev->c0_reset); + reset_control_deassert(adev->c1_reset); + reset_control_deassert(adev->c2_reset); + + adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, -+ sizeof(*adev->channels), GFP_KERNEL); ++ sizeof(*adev->channels), GFP_KERNEL); + + if (!adev->channels) { + ret = -ENOMEM; @@ -859,16 +864,16 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* configure client interfaces */ + writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); + writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); + writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); + writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), -+ adev->regs + ADM_GP_CTL); ++ adev->regs + ADM_GP_CTL); + + ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, -+ 0, "adm_dma", adev); ++ 0, "adm_dma", adev); + if (ret) + goto err_disable_clks; + @@ -933,6 +938,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + /* mask IRQs for this channel/EE pair */ + writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + ++ tasklet_kill(&adev->channels[i].vc.task); + adm_terminate_all(&adev->channels[i].vc.chan); + } + @@ -964,3 +970,6 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>"); +MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); +MODULE_LICENSE("GPL v2"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch new file mode 100644 index 0000000000..7aec4fcc83 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -0,0 +1,227 @@ +From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +Date: Mon, 4 Jan 2021 09:41:35 +0530 +Subject: mtd: parsers: Add Qcom SMEM parser + +NAND based Qualcomm platforms have the partition table populated in the +Shared Memory (SMEM). Hence, add a parser for parsing the partitions +from it. + +Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> +Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org +--- + drivers/mtd/parsers/Kconfig | 8 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/mtd/parsers/qcomsmempart.c + +diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig +index e72354322f628..d90c302290522 100644 +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -160,6 +160,14 @@ config MTD_REDBOOT_PARTS_READONLY + 'FIS directory' images, enable this option. + + endif # MTD_REDBOOT_PARTS ++ ++config MTD_QCOMSMEM_PARTS ++ tristate "Qualcomm SMEM NAND flash partition parser" ++ depends on MTD_NAND_QCOM || COMPILE_TEST ++ depends on QCOM_SMEM ++ help ++ This provides support for parsing partitions from Shared Memory (SMEM) ++ for NAND flash on Qualcomm platforms. + + config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" +diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile +index b0c5f62f9e858..50eb0b0a22105 100644 +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -9,4 +9,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c +new file mode 100644 +index 0000000000000..808cb33d71f8e +--- /dev/null ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Qualcomm SMEM NAND flash partition parser ++ * ++ * Copyright (C) 2020, Linaro Ltd. ++ */ ++ ++#include <linux/ctype.h> ++#include <linux/module.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/slab.h> ++#include <linux/soc/qcom/smem.h> ++ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_APPS 0 ++ ++#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa ++#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb ++#define SMEM_FLASH_PTABLE_V3 3 ++#define SMEM_FLASH_PTABLE_V4 4 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 ++#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) ++#define SMEM_FLASH_PTABLE_NAME_SIZE 16 ++ ++/** ++ * struct smem_flash_pentry - SMEM Flash partition entry ++ * @name: Name of the partition ++ * @offset: Offset in blocks ++ * @length: Length of the partition in blocks ++ * @attr: Flags for this partition ++ */ ++struct smem_flash_pentry { ++ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; ++ __le32 offset; ++ __le32 length; ++ u8 attr; ++} __packed __aligned(4); ++ ++/** ++ * struct smem_flash_ptable - SMEM Flash partition table ++ * @magic1: Partition table Magic 1 ++ * @magic2: Partition table Magic 2 ++ * @version: Partition table version ++ * @numparts: Number of partitions in this ptable ++ * @pentry: Flash partition entries belonging to this ptable ++ */ ++struct smem_flash_ptable { ++ __le32 magic1; ++ __le32 magic2; ++ __le32 version; ++ __le32 numparts; ++ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; ++} __packed __aligned(4); ++ ++static int parse_qcomsmem_part(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_flash_pentry *pentry; ++ struct smem_flash_ptable *ptable; ++ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; ++ struct mtd_partition *parts; ++ int ret, i, numparts; ++ char *name, *c; ++ ++ pr_debug("Parsing partition table info from SMEM\n"); ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR(ptable)) { ++ pr_err("Error reading partition table header\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ /* Verify ptable magic */ ++ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || ++ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { ++ pr_err("Partition table magic verification failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Ensure that # of partitions is less than the max we have allocated */ ++ numparts = le32_to_cpu(ptable->numparts); ++ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { ++ pr_err("Partition numbers exceed the max limit\n"); ++ return -EINVAL; ++ } ++ ++ /* Find out length of partition data based on table version */ ++ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * ++ sizeof(struct smem_flash_pentry); ++ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * ++ sizeof(struct smem_flash_pentry); ++ } else { ++ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now that the partition table header has been parsed, verified ++ * and the length of the partition table calculated, read the ++ * complete partition table ++ */ ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR_OR_NULL(ptable)) { ++ pr_err("Error reading partition table\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < numparts; i++) { ++ pentry = &ptable->pentry[i]; ++ if (pentry->name[0] == '\0') ++ continue; ++ ++ name = kstrdup(pentry->name, GFP_KERNEL); ++ if (!name) { ++ ret = -ENOMEM; ++ goto out_free_parts; ++ } ++ ++ /* Convert name to lower case */ ++ for (c = name; *c != '\0'; c++) ++ *c = tolower(*c); ++ ++ parts[i].name = name; ++ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; ++ parts[i].mask_flags = pentry->attr; ++ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", ++ i, pentry->name, le32_to_cpu(pentry->offset), ++ le32_to_cpu(pentry->length), pentry->attr); ++ } ++ ++ pr_debug("SMEM partition table found: ver: %d len: %d\n", ++ le32_to_cpu(ptable->version), numparts); ++ *pparts = parts; ++ ++ return numparts; ++ ++out_free_parts: ++ while (--i >= 0) ++ kfree(parts[i].name); ++ kfree(parts); ++ *pparts = NULL; ++ ++ return ret; ++} ++ ++static const struct of_device_id qcomsmem_of_match_table[] = { ++ { .compatible = "qcom,smem-part" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_qcomsmem = { ++ .parse_fn = parse_qcomsmem_part, ++ .name = "qcomsmem", ++ .of_match_table = qcomsmem_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_qcomsmem); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); ++MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000000..47f3bfba8d --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,24 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin <john@phrozen.org> +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin <john@phrozen.org> +--- + drivers/mtd/parsers/qcomsmempart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -189,6 +189,11 @@ static int parse_qcomsmem_part(st + parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[i].mask_flags = pentry->attr; + parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs")) ++ parts[i].name = "ubi"; ++ + pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", + i, pentry->name, le32_to_cpu(pentry->offset), + le32_to_cpu(pentry->length), pentry->attr); diff --git a/target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch deleted file mode 100644 index 6b7119b8e0..0000000000 --- a/target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch +++ /dev/null @@ -1,282 +0,0 @@ -From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Thu, 9 Mar 2017 08:18:08 +0100 -Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms - -On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is -used to store partition layout. This new parser can now be used to read -SMEM and use it to register an MTD layout according to its content. - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> -Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org> ---- - drivers/mtd/parsers/Kconfig | 7 ++ - drivers/mtd/parsers/Makefile | 1 + - drivers/mtd/parsers/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 236 insertions(+) - create mode 100644 drivers/mtd/parsers/qcom_smem_part.c - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -138,6 +138,13 @@ config MTD_PARSER_TRX - This driver will parse TRX header and report at least two partitions: - kernel and rootfs. - -+config MTD_QCOM_SMEM_PARTS -+ tristate "QCOM SMEM partitioning support" -+ depends on QCOM_SMEM -+ help -+ This provides partitions parser for QCOM devices using SMEM -+ such as IPQ806x. -+ - config MTD_SHARPSL_PARTS - tristate "Sharp SL Series NAND flash partition parser" - depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST ---- a/drivers/mtd/parsers/Makefile -+++ b/drivers/mtd/parsers/Makefile -@@ -11,6 +11,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS) - obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o -+obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o - obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o ---- /dev/null -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -0,0 +1,235 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/device.h> -+#include <linux/slab.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/partitions.h> -+#include <linux/spi/spi.h> -+#include <linux/module.h> -+ -+#include <linux/soc/qcom/smem.h> -+ -+/* Processor/host identifier for the application processor */ -+#define SMEM_HOST_APPS 0 -+ -+/* SMEM items index */ -+#define SMEM_AARM_PARTITION_TABLE 9 -+#define SMEM_BOOT_FLASH_TYPE 421 -+#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 -+ -+/* SMEM Flash types */ -+#define SMEM_FLASH_NAND 2 -+#define SMEM_FLASH_SPI 6 -+ -+#define SMEM_PART_NAME_SZ 16 -+#define SMEM_PARTS_MAX 32 -+ -+struct smem_partition { -+ char name[SMEM_PART_NAME_SZ]; -+ __le32 start; -+ __le32 size; -+ __le32 attr; -+}; -+ -+struct smem_partition_table { -+ u8 magic[8]; -+ __le32 version; -+ __le32 len; -+ struct smem_partition parts[SMEM_PARTS_MAX]; -+}; -+ -+/* SMEM Magic values in partition table */ -+static const u8 SMEM_PTABLE_MAGIC[] = { -+ 0xaa, 0x73, 0xee, 0x55, -+ 0xdb, 0xbd, 0x5e, 0xe3, -+}; -+ -+static int qcom_smem_get_flash_blksz(u64 **smem_blksz) -+{ -+ size_t size; -+ -+ *smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, -+ &size); -+ -+ if (IS_ERR(*smem_blksz)) { -+ pr_err("Unable to read flash blksz from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_blksz)) { -+ pr_err("Invalid flash blksz size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_type(u64 **smem_flash_type) -+{ -+ size_t size; -+ -+ *smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, -+ &size); -+ -+ if (IS_ERR(*smem_flash_type)) { -+ pr_err("Unable to read flash type from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_flash_type)) { -+ pr_err("Invalid flash type size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) -+{ -+ size_t size; -+ -+ *pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, -+ &size); -+ -+ if (IS_ERR(*pparts)) { -+ pr_err("Unable to read partition table from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ return 0; -+} -+ -+static int of_dev_node_match(struct device *dev, const void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static bool is_spi_device(struct device_node *np) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); -+ if (!dev) -+ return false; -+ -+ put_device(dev); -+ return true; -+} -+ -+static int parse_qcom_smem_partitions(struct mtd_info *master, -+ const struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ struct smem_partition_table *smem_parts; -+ u64 *smem_flash_type, *smem_blksz; -+ struct mtd_partition *mtd_parts; -+ struct device_node *of_node = master->dev.of_node; -+ int i, ret; -+ -+ /* -+ * SMEM will only store the partition table of the boot device. -+ * If this is not the boot device, do not return any partition. -+ */ -+ ret = qcom_smem_get_flash_type(&smem_flash_type); -+ if (ret < 0) -+ return ret; -+ -+ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) -+ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) -+ return 0; -+ -+ /* -+ * Just for sanity purpose, make sure the block size in SMEM matches the -+ * block size of the MTD device -+ */ -+ ret = qcom_smem_get_flash_blksz(&smem_blksz); -+ if (ret < 0) -+ return ret; -+ -+ if (*smem_blksz != master->erasesize) { -+ pr_err("SMEM block size differs from MTD block size\n"); -+ return -EINVAL; -+ } -+ -+ /* Get partition pointer from SMEM */ -+ ret = qcom_smem_get_flash_partitions(&smem_parts); -+ if (ret < 0) -+ return ret; -+ -+ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, -+ sizeof(SMEM_PTABLE_MAGIC))) { -+ pr_err("SMEM partition magic invalid\n"); -+ return -EINVAL; -+ } -+ -+ /* Allocate and populate the mtd structures */ -+ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), -+ GFP_KERNEL); -+ if (!mtd_parts) -+ return -ENOMEM; -+ -+ for (i = 0; i < smem_parts->len; i++) { -+ struct smem_partition *s_part = &smem_parts->parts[i]; -+ struct mtd_partition *m_part = &mtd_parts[i]; -+ -+ m_part->name = s_part->name; -+ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); -+ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); -+ -+ /* -+ * The last SMEM partition may have its size marked as -+ * something like 0xffffffff, which means "until the end of the -+ * flash device". In this case, truncate it. -+ */ -+ if (m_part->offset + m_part->size > master->size) -+ m_part->size = master->size - m_part->offset; -+ } -+ -+ *pparts = mtd_parts; -+ -+ return smem_parts->len; -+} -+ -+static const struct of_device_id qcom_smem_of_match_table[] = { -+ { .compatible = "qcom,smem" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table); -+ -+static struct mtd_part_parser qcom_smem_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_qcom_smem_partitions, -+ .name = "qcom-smem", -+ .of_match_table = qcom_smem_of_match_table, -+}; -+ -+static int __init qcom_smem_parser_init(void) -+{ -+ register_mtd_parser(&qcom_smem_parser); -+ return 0; -+} -+ -+static void __exit qcom_smem_parser_exit(void) -+{ -+ deregister_mtd_parser(&qcom_smem_parser); -+} -+ -+module_init(qcom_smem_parser_init); -+module_exit(qcom_smem_parser_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>"); -+MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); diff --git a/target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch deleted file mode 100644 index ff6f6edf49..0000000000 --- a/target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 -From: John Crispin <john@phrozen.org> -Date: Thu, 9 Mar 2017 09:31:44 +0100 -Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting - -Signed-off-by: John Crispin <john@phrozen.org> ---- - drivers/mtd/parsers/qcom_smem_part.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/mtd/parsers/qcom_smem_part.c -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -189,6 +189,10 @@ static int parse_qcom_smem_partitions(st - m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); - m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); - -+ /* "rootfs" conflicts with OpenWrt auto mounting */ -+ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs")) -+ m_part->name = "ubi"; -+ - /* - * The last SMEM partition may have its size marked as - * something like 0xffffffff, which means "until the end of the diff --git a/target/linux/ipq806x/patches-5.4/0002-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch index aa7d2e791e..45062d52fc 100644 --- a/target/linux/ipq806x/patches-5.4/0002-dmaengine-Add-ADM-driver.patch +++ b/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -1,86 +1,95 @@ -From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001 -From: Thomas Pedersen <twp@codeaurora.org> -Date: Mon, 16 May 2016 17:58:51 -0700 -Subject: [PATCH 02/69] dmaengine: Add ADM driver - -Original patch by Andy Gross. +From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 +From: Jonathan McDowell <noodles@earth.li> +Date: Sat, 14 Nov 2020 14:02:33 +0000 +Subject: dmaengine: qcom: Add ADM driver Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA controller found in the MSM8x60 and IPQ/APQ8064 platforms. The ADM supports both memory to memory transactions and memory -to/from peripheral device transactions. The controller also provides flow -control capabilities for transactions to/from peripheral devices. +to/from peripheral device transactions. The controller also provides +flow control capabilities for transactions to/from peripheral devices. + +The initial release of this driver supports slave transfers to/from +peripherals and also incorporates CRCI (client rate control interface) +flow control. -The initial release of this driver supports slave transfers to/from peripherals -and also incorporates CRCI (client rate control interface) flow control. +The hardware only supports a 32 bit physical address, so specifying +!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to +spend effort on kludging things in the code that will never actually be +needed on real hardware. Signed-off-by: Andy Gross <agross@codeaurora.org> Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +Signed-off-by: Jonathan McDowell <noodles@earth.li> +Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li +Signed-off-by: Vinod Koul <vkoul@kernel.org> --- - drivers/dma/qcom/Kconfig | 10 + + drivers/dma/qcom/Kconfig | 11 + drivers/dma/qcom/Makefile | 1 + - drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 911 insertions(+) + drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 915 insertions(+) create mode 100644 drivers/dma/qcom/qcom_adm.c +diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig +index 3bcb689162c67..0389d60d2604a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig -@@ -28,3 +28,13 @@ config QCOM_HIDMA - (user to kernel, kernel to kernel, etc.). It only supports - memcpy interface. The core is not intended for general - purpose slave DMA. -+ +@@ -1,4 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0-only +config QCOM_ADM + tristate "Qualcomm ADM support" -+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) ++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS -+ ---help--- -+ Enable support for the Qualcomm ADM DMA controller. This controller -+ provides DMA capabilities for both general purpose and on-chip -+ peripheral devices. ++ help ++ Enable support for the Qualcomm Application Data Mover (ADM) DMA ++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. ++ This controller provides DMA capabilities for both general purpose ++ and on-chip peripheral devices. ++ + config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) +diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile +index 1ae92da88b0c9..346e643fbb6db 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg - hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o - obj-$(CONFIG_QCOM_HIDMA) += hdma.o - hdma-objs := hidma_ll.o hidma.o hidma_dbg.o +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_ADM) += qcom_adm.o + obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o + obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o +diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c +new file mode 100644 +index 0000000000000..9b6f8e050ecce --- /dev/null +++ b/drivers/dma/qcom/qcom_adm.c -@@ -0,0 +1,914 @@ +@@ -0,0 +1,903 @@ ++// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * + */ + -+#include <linux/kernel.h> -+#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/dmaengine.h> ++#include <linux/dma-mapping.h> +#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/module.h> +#include <linux/interrupt.h> -+#include <linux/dma-mapping.h> -+#include <linux/scatterlist.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_dma.h> ++#include <linux/platform_device.h> +#include <linux/reset.h> -+#include <linux/clk.h> -+#include <linux/dmaengine.h> ++#include <linux/scatterlist.h> ++#include <linux/slab.h> + +#include "../dmaengine.h" +#include "../virt-dma.h" @@ -90,10 +99,10 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +#define ADM_CI_MULTI 0x4 +#define ADM_CRCI_MULTI 0x4 +#define ADM_EE_MULTI 0x800 -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) -+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) +#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) +#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) +#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) @@ -102,62 +111,62 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) +#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) -+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI) ++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) +#define ADM_GP_CTL 0x3d8 -+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \ ++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ + ADM_EE_OFFS(ee)) + +/* channel status */ -+#define ADM_CH_STATUS_VALID BIT(1) ++#define ADM_CH_STATUS_VALID BIT(1) + +/* channel result */ -+#define ADM_CH_RSLT_VALID BIT(31) -+#define ADM_CH_RSLT_ERR BIT(3) -+#define ADM_CH_RSLT_FLUSH BIT(2) -+#define ADM_CH_RSLT_TPD BIT(1) ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) + +/* channel conf */ +#define ADM_CH_CONF_SHADOW_EN BIT(12) +#define ADM_CH_CONF_MPU_DISABLE BIT(11) +#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) +#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) -+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11)) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) + +/* channel result conf */ +#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) +#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) + +/* CRCI CTL */ -+#define ADM_CRCI_CTL_MUX_SEL BIT(18) -+#define ADM_CRCI_CTL_RST BIT(17) ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) + +/* CI configuration */ -+#define ADM_CI_RANGE_END(x) (x << 24) -+#define ADM_CI_RANGE_START(x) (x << 16) -+#define ADM_CI_BURST_4_WORDS BIT(2) -+#define ADM_CI_BURST_8_WORDS BIT(3) ++#define ADM_CI_RANGE_END(x) ((x) << 24) ++#define ADM_CI_RANGE_START(x) ((x) << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) + +/* GP CTL */ -+#define ADM_GP_CTL_LP_EN BIT(12) -+#define ADM_GP_CTL_LP_CNT(x) (x << 8) ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) + +/* Command pointer list entry */ -+#define ADM_CPLE_LP BIT(31) -+#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) + +/* Command list entry */ -+#define ADM_CMD_LC BIT(31) -+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) -+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) + -+#define ADM_CMD_TYPE_SINGLE 0x0 -+#define ADM_CMD_TYPE_BOX 0x3 ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 + -+#define ADM_CRCI_MUX_SEL BIT(4) -+#define ADM_DESC_ALIGN 8 -+#define ADM_MAX_XFER (SZ_64K-1) -+#define ADM_MAX_ROWS (SZ_64K-1) -+#define ADM_MAX_CHANNELS 16 ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K - 1) ++#define ADM_MAX_ROWS (SZ_64K - 1) ++#define ADM_MAX_CHANNELS 16 + +struct adm_desc_hw_box { + u32 cmd; @@ -255,7 +264,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + case 32: + case 64: + case 128: -+ ret = ffs(burst>>4) - 1; ++ ret = ffs(burst >> 4) - 1; + break; + case 192: + ret = 4; @@ -281,9 +290,10 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * @burst: Burst size of transaction + * @direction: DMA transfer direction + */ -+static void *adm_process_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, u32 crci, u32 burst, -+ enum dma_transfer_direction direction) ++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, u32 crci, ++ u32 burst, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_box *box_desc = NULL; + struct adm_desc_hw_single *single_desc; @@ -349,9 +359,9 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * @sg: Scatterlist entry + * @direction: DMA transfer direction + */ -+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, -+ enum dma_transfer_direction direction) ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_single *single_desc; + u32 remainder = sg_dma_len(sg); @@ -398,9 +408,11 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * @context: transfer context (unused) + */ +static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_transfer_direction direction, unsigned long flags, -+ void *context) ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_transfer_direction direction, ++ unsigned long flags, ++ void *context) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct adm_device *adev = achan->adev; @@ -427,7 +439,6 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* if using flow control, validate burst and crci values */ + if (achan->slave.device_fc) { -+ + blk_size = adm_get_blksize(burst); + if (blk_size < 0) { + dev_err(adev->dev, "invalid burst value: %d\n", @@ -455,7 +466,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + } + } + -+ async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC); ++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); + if (!async_desc) + return ERR_PTR(-ENOMEM); + @@ -468,7 +479,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + box_count * sizeof(struct adm_desc_hw_box) + + sizeof(*cple) + 2 * ADM_DESC_ALIGN; + -+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC); ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); + if (!async_desc->cpl) + goto free; + @@ -483,10 +494,10 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + if (achan->slave.device_fc) + desc = adm_process_fc_descriptors(achan, desc, sg, crci, -+ burst, direction); ++ burst, direction); + else + desc = adm_process_non_fc_descriptors(achan, desc, sg, -+ direction); ++ direction); + } + + async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, @@ -532,7 +543,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* send flush command to terminate current transaction */ + writel_relaxed(0x0, -+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); + + spin_unlock_irqrestore(&achan->vc.lock, flags); + @@ -586,7 +597,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + adev->regs + ADM_CH_CONF(achan->id)); + + writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, -+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + + achan->initialized = 1; + } @@ -594,7 +605,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + /* set the crci block size if this transaction requires CRCI */ + if (async_desc->crci) { + writel(async_desc->mux | async_desc->blk_size, -+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); + } + + /* make sure IRQ enable doesn't get reordered */ @@ -602,7 +613,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* write next command list out to the CMD FIFO */ + writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, -+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); +} + +/** @@ -628,7 +639,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + if (srcs & BIT(i)) { + status = readl_relaxed(adev->regs + -+ ADM_CH_STATUS_SD(i, adev->ee)); ++ ADM_CH_STATUS_SD(i, adev->ee)); + + /* if no result present, skip */ + if (!(status & ADM_CH_STATUS_VALID)) @@ -673,7 +684,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * Return status of dma transaction + */ +static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, -+ struct dma_tx_state *txstate) ++ struct dma_tx_state *txstate) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct virt_dma_desc *vd; @@ -697,7 +708,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + * residue is either the full length if it is in the issued list, or 0 + * if it is in progress. We have no reliable way of determining + * anything inbetween -+ */ ++ */ + dma_set_residue(txstate, residue); + + if (achan->error) @@ -741,7 +752,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +} + +static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, -+ u32 index) ++ u32 index) +{ + achan->id = index; + achan->adev = adev; @@ -753,7 +764,6 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +static int adm_dma_probe(struct platform_device *pdev) +{ + struct adm_device *adev; -+ struct resource *iores; + int ret; + u32 i; + @@ -763,8 +773,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + adev->dev = &pdev->dev; + -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ adev->regs = devm_ioremap_resource(&pdev->dev, iores); ++ adev->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adev->regs)) + return PTR_ERR(adev->regs); + @@ -782,50 +791,44 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + if (IS_ERR(adev->core_clk)) + return PTR_ERR(adev->core_clk); + -+ ret = clk_prepare_enable(adev->core_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable core clock\n"); -+ return ret; -+ } -+ + adev->iface_clk = devm_clk_get(adev->dev, "iface"); -+ if (IS_ERR(adev->iface_clk)) { -+ ret = PTR_ERR(adev->iface_clk); -+ goto err_disable_core_clk; -+ } -+ -+ ret = clk_prepare_enable(adev->iface_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); -+ goto err_disable_core_clk; -+ } ++ if (IS_ERR(adev->iface_clk)) ++ return PTR_ERR(adev->iface_clk); + -+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk"); ++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); + if (IS_ERR(adev->clk_reset)) { + dev_err(adev->dev, "failed to get ADM0 reset\n"); -+ ret = PTR_ERR(adev->clk_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->clk_reset); + } + -+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0"); ++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); + if (IS_ERR(adev->c0_reset)) { + dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); -+ ret = PTR_ERR(adev->c0_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->c0_reset); + } + -+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1"); ++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); + if (IS_ERR(adev->c1_reset)) { + dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); -+ ret = PTR_ERR(adev->c1_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->c1_reset); + } + -+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2"); ++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); + if (IS_ERR(adev->c2_reset)) { + dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); -+ ret = PTR_ERR(adev->c2_reset); -+ goto err_disable_clks; ++ return PTR_ERR(adev->c2_reset); ++ } ++ ++ ret = clk_prepare_enable(adev->core_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable core clock\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(adev->iface_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); ++ goto err_disable_core_clk; + } + + reset_control_assert(adev->clk_reset); @@ -833,13 +836,15 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + reset_control_assert(adev->c1_reset); + reset_control_assert(adev->c2_reset); + ++ udelay(2); ++ + reset_control_deassert(adev->clk_reset); + reset_control_deassert(adev->c0_reset); + reset_control_deassert(adev->c1_reset); + reset_control_deassert(adev->c2_reset); + + adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, -+ sizeof(*adev->channels), GFP_KERNEL); ++ sizeof(*adev->channels), GFP_KERNEL); + + if (!adev->channels) { + ret = -ENOMEM; @@ -859,16 +864,16 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + + /* configure client interfaces */ + writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); + writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); + writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); + writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), -+ adev->regs + ADM_GP_CTL); ++ adev->regs + ADM_GP_CTL); + + ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, -+ 0, "adm_dma", adev); ++ 0, "adm_dma", adev); + if (ret) + goto err_disable_clks; + @@ -933,6 +938,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> + /* mask IRQs for this channel/EE pair */ + writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + ++ tasklet_kill(&adev->channels[i].vc.task); + adm_terminate_all(&adev->channels[i].vc.chan); + } + @@ -964,3 +970,6 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org> +MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>"); +MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); +MODULE_LICENSE("GPL v2"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch new file mode 100644 index 0000000000..7aec4fcc83 --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -0,0 +1,227 @@ +From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +Date: Mon, 4 Jan 2021 09:41:35 +0530 +Subject: mtd: parsers: Add Qcom SMEM parser + +NAND based Qualcomm platforms have the partition table populated in the +Shared Memory (SMEM). Hence, add a parser for parsing the partitions +from it. + +Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> +Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org +--- + drivers/mtd/parsers/Kconfig | 8 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/mtd/parsers/qcomsmempart.c + +diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig +index e72354322f628..d90c302290522 100644 +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -160,6 +160,14 @@ config MTD_REDBOOT_PARTS_READONLY + 'FIS directory' images, enable this option. + + endif # MTD_REDBOOT_PARTS ++ ++config MTD_QCOMSMEM_PARTS ++ tristate "Qualcomm SMEM NAND flash partition parser" ++ depends on MTD_NAND_QCOM || COMPILE_TEST ++ depends on QCOM_SMEM ++ help ++ This provides support for parsing partitions from Shared Memory (SMEM) ++ for NAND flash on Qualcomm platforms. + + config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" +diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile +index b0c5f62f9e858..50eb0b0a22105 100644 +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -9,4 +9,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c +new file mode 100644 +index 0000000000000..808cb33d71f8e +--- /dev/null ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Qualcomm SMEM NAND flash partition parser ++ * ++ * Copyright (C) 2020, Linaro Ltd. ++ */ ++ ++#include <linux/ctype.h> ++#include <linux/module.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/slab.h> ++#include <linux/soc/qcom/smem.h> ++ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_APPS 0 ++ ++#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa ++#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb ++#define SMEM_FLASH_PTABLE_V3 3 ++#define SMEM_FLASH_PTABLE_V4 4 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 ++#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) ++#define SMEM_FLASH_PTABLE_NAME_SIZE 16 ++ ++/** ++ * struct smem_flash_pentry - SMEM Flash partition entry ++ * @name: Name of the partition ++ * @offset: Offset in blocks ++ * @length: Length of the partition in blocks ++ * @attr: Flags for this partition ++ */ ++struct smem_flash_pentry { ++ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; ++ __le32 offset; ++ __le32 length; ++ u8 attr; ++} __packed __aligned(4); ++ ++/** ++ * struct smem_flash_ptable - SMEM Flash partition table ++ * @magic1: Partition table Magic 1 ++ * @magic2: Partition table Magic 2 ++ * @version: Partition table version ++ * @numparts: Number of partitions in this ptable ++ * @pentry: Flash partition entries belonging to this ptable ++ */ ++struct smem_flash_ptable { ++ __le32 magic1; ++ __le32 magic2; ++ __le32 version; ++ __le32 numparts; ++ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; ++} __packed __aligned(4); ++ ++static int parse_qcomsmem_part(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_flash_pentry *pentry; ++ struct smem_flash_ptable *ptable; ++ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; ++ struct mtd_partition *parts; ++ int ret, i, numparts; ++ char *name, *c; ++ ++ pr_debug("Parsing partition table info from SMEM\n"); ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR(ptable)) { ++ pr_err("Error reading partition table header\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ /* Verify ptable magic */ ++ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || ++ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { ++ pr_err("Partition table magic verification failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Ensure that # of partitions is less than the max we have allocated */ ++ numparts = le32_to_cpu(ptable->numparts); ++ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { ++ pr_err("Partition numbers exceed the max limit\n"); ++ return -EINVAL; ++ } ++ ++ /* Find out length of partition data based on table version */ ++ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * ++ sizeof(struct smem_flash_pentry); ++ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * ++ sizeof(struct smem_flash_pentry); ++ } else { ++ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now that the partition table header has been parsed, verified ++ * and the length of the partition table calculated, read the ++ * complete partition table ++ */ ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR_OR_NULL(ptable)) { ++ pr_err("Error reading partition table\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < numparts; i++) { ++ pentry = &ptable->pentry[i]; ++ if (pentry->name[0] == '\0') ++ continue; ++ ++ name = kstrdup(pentry->name, GFP_KERNEL); ++ if (!name) { ++ ret = -ENOMEM; ++ goto out_free_parts; ++ } ++ ++ /* Convert name to lower case */ ++ for (c = name; *c != '\0'; c++) ++ *c = tolower(*c); ++ ++ parts[i].name = name; ++ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; ++ parts[i].mask_flags = pentry->attr; ++ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", ++ i, pentry->name, le32_to_cpu(pentry->offset), ++ le32_to_cpu(pentry->length), pentry->attr); ++ } ++ ++ pr_debug("SMEM partition table found: ver: %d len: %d\n", ++ le32_to_cpu(ptable->version), numparts); ++ *pparts = parts; ++ ++ return numparts; ++ ++out_free_parts: ++ while (--i >= 0) ++ kfree(parts[i].name); ++ kfree(parts); ++ *pparts = NULL; ++ ++ return ret; ++} ++ ++static const struct of_device_id qcomsmem_of_match_table[] = { ++ { .compatible = "qcom,smem-part" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_qcomsmem = { ++ .parse_fn = parse_qcomsmem_part, ++ .name = "qcomsmem", ++ .of_match_table = qcomsmem_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_qcomsmem); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); ++MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000000..e83872935f --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,24 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin <john@phrozen.org> +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin <john@phrozen.org> +--- + drivers/mtd/parsers/qcomsmempart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -132,6 +132,11 @@ static int parse_qcomsmem_part(struct mt + parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[i].mask_flags = pentry->attr; + parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs")) ++ parts[i].name = "ubi"; ++ + pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", + i, pentry->name, le32_to_cpu(pentry->offset), + le32_to_cpu(pentry->length), pentry->attr); |