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>
This commit is contained in:
		
				
					committed by
					
						
						Petr Štetiar
					
				
			
			
				
	
			
			
			
						parent
						
							cde218d14b
						
					
				
				
					commit
					c864f587a2
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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";
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -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";
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -179,7 +179,7 @@
 | 
			
		||||
		nand-ecc-step-size = <512>;
 | 
			
		||||
 | 
			
		||||
		partitions {
 | 
			
		||||
			compatible = "qcom,smem";
 | 
			
		||||
			compatible = "qcom,smem-part";
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -182,7 +182,7 @@
 | 
			
		||||
			reg = <0>;
 | 
			
		||||
 | 
			
		||||
			partitions {
 | 
			
		||||
				compatible = "qcom,smem";
 | 
			
		||||
				compatible = "qcom,smem-part";
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 
 | 
			
		||||
@@ -184,7 +184,7 @@
 | 
			
		||||
			reg = <0>;
 | 
			
		||||
 | 
			
		||||
			partitions {
 | 
			
		||||
				compatible = "qcom,smem";
 | 
			
		||||
				compatible = "qcom,smem-part";
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 
 | 
			
		||||
@@ -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");
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -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/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/clk.h>
 | 
			
		||||
+#include <linux/delay.h>
 | 
			
		||||
+#include <linux/device.h>
 | 
			
		||||
+#include <linux/platform_device.h>
 | 
			
		||||
+#include <linux/dmaengine.h>
 | 
			
		||||
+#include <linux/dma-mapping.h>
 | 
			
		||||
+#include <linux/init.h>
 | 
			
		||||
+#include <linux/interrupt.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,9 +111,9 @@ 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 */
 | 
			
		||||
@@ -121,7 +130,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
 | 
			
		||||
+#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)
 | 
			
		||||
@@ -132,14 +141,14 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
 | 
			
		||||
+#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_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_CNT(x)		((x) << 8)
 | 
			
		||||
+
 | 
			
		||||
+/* Command pointer list entry */
 | 
			
		||||
+#define ADM_CPLE_LP			BIT(31)
 | 
			
		||||
@@ -281,8 +290,9 @@ 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,
 | 
			
		||||
+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;
 | 
			
		||||
@@ -349,8 +359,8 @@ 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,
 | 
			
		||||
+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;
 | 
			
		||||
@@ -398,8 +408,10 @@ 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,
 | 
			
		||||
+							 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);
 | 
			
		||||
@@ -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;
 | 
			
		||||
+
 | 
			
		||||
@@ -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,57 +791,53 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
 | 
			
		||||
+	if (IS_ERR(adev->core_clk))
 | 
			
		||||
+		return PTR_ERR(adev->core_clk);
 | 
			
		||||
+
 | 
			
		||||
+	adev->iface_clk = devm_clk_get(adev->dev, "iface");
 | 
			
		||||
+	if (IS_ERR(adev->iface_clk))
 | 
			
		||||
+		return PTR_ERR(adev->iface_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");
 | 
			
		||||
+		return PTR_ERR(adev->clk_reset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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");
 | 
			
		||||
+		return PTR_ERR(adev->c0_reset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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");
 | 
			
		||||
+		return PTR_ERR(adev->c1_reset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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");
 | 
			
		||||
+		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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->clk_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->c0_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->c1_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->c2_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	reset_control_assert(adev->clk_reset);
 | 
			
		||||
+	reset_control_assert(adev->c0_reset);
 | 
			
		||||
+	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);
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
@@ -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);
 | 
			
		||||
@@ -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");
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -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/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/clk.h>
 | 
			
		||||
+#include <linux/delay.h>
 | 
			
		||||
+#include <linux/device.h>
 | 
			
		||||
+#include <linux/platform_device.h>
 | 
			
		||||
+#include <linux/dmaengine.h>
 | 
			
		||||
+#include <linux/dma-mapping.h>
 | 
			
		||||
+#include <linux/init.h>
 | 
			
		||||
+#include <linux/interrupt.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,9 +111,9 @@ 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 */
 | 
			
		||||
@@ -121,7 +130,7 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
 | 
			
		||||
+#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)
 | 
			
		||||
@@ -132,14 +141,14 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
 | 
			
		||||
+#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_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_CNT(x)		((x) << 8)
 | 
			
		||||
+
 | 
			
		||||
+/* Command pointer list entry */
 | 
			
		||||
+#define ADM_CPLE_LP			BIT(31)
 | 
			
		||||
@@ -281,8 +290,9 @@ 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,
 | 
			
		||||
+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;
 | 
			
		||||
@@ -349,8 +359,8 @@ 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,
 | 
			
		||||
+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;
 | 
			
		||||
@@ -398,8 +408,10 @@ 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,
 | 
			
		||||
+							 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);
 | 
			
		||||
@@ -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;
 | 
			
		||||
+
 | 
			
		||||
@@ -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,57 +791,53 @@ Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
 | 
			
		||||
+	if (IS_ERR(adev->core_clk))
 | 
			
		||||
+		return PTR_ERR(adev->core_clk);
 | 
			
		||||
+
 | 
			
		||||
+	adev->iface_clk = devm_clk_get(adev->dev, "iface");
 | 
			
		||||
+	if (IS_ERR(adev->iface_clk))
 | 
			
		||||
+		return PTR_ERR(adev->iface_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");
 | 
			
		||||
+		return PTR_ERR(adev->clk_reset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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");
 | 
			
		||||
+		return PTR_ERR(adev->c0_reset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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");
 | 
			
		||||
+		return PTR_ERR(adev->c1_reset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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");
 | 
			
		||||
+		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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->clk_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->c0_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->c1_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	adev->c2_reset = devm_reset_control_get(&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;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	reset_control_assert(adev->clk_reset);
 | 
			
		||||
+	reset_control_assert(adev->c0_reset);
 | 
			
		||||
+	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);
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
@@ -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);
 | 
			
		||||
		Reference in New Issue
	
	Block a user