Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 10/16] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

Current ARM SMMUv3 probe functions intermingle HW and DT probing in the
initialization functions to detect and programme the ARM SMMU v3 driver
features. In order to allow probing the ARM SMMUv3 with other firmwares
than DT, this patch splits the ARM SMMUv3 init functions into DT and HW
specific portions so that other FW interfaces (ie ACPI) can reuse the HW
probing functions and skip the DT portion accordingly.

This patch implements no functional change, only code reshuffling.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
 drivers/iommu/arm-smmu-v3.c | 43 +++++++++++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index e6e1c87..2b3f9ac 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2381,10 +2381,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 	return 0;
 }
 
-static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
+static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 {
 	u32 reg;
-	bool coherent;
+	bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;
 
 	/* IDR0 */
 	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
@@ -2436,13 +2436,9 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
 		smmu->features |= ARM_SMMU_FEAT_HYP;
 
 	/*
-	 * The dma-coherent property is used in preference to the ID
+	 * The coherency feature as set by FW is used in preference to the ID
 	 * register, but warn on mismatch.
 	 */
-	coherent = of_dma_is_coherent(smmu->dev->of_node);
-	if (coherent)
-		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
-
 	if (!!(reg & IDR0_COHACC) != coherent)
 		dev_warn(smmu->dev, "IDR0.COHACC overridden by dma-coherent property (%s)\n",
 			 coherent ? "true" : "false");
@@ -2563,21 +2559,35 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+				    struct arm_smmu_device *smmu)
 {
-	int irq, ret;
-	struct resource *res;
-	struct arm_smmu_device *smmu;
 	struct device *dev = &pdev->dev;
-	bool bypass = true;
 	u32 cells;
+	int ret = -EINVAL;
 
 	if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
 		dev_err(dev, "missing #iommu-cells property\n");
 	else if (cells != 1)
 		dev_err(dev, "invalid #iommu-cells value (%d)\n", cells);
 	else
-		bypass = false;
+		ret = 0;
+
+	parse_driver_options(smmu);
+
+	if (of_dma_is_coherent(dev->of_node))
+		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+	return ret;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+	int irq, ret;
+	struct resource *res;
+	struct arm_smmu_device *smmu;
+	struct device *dev = &pdev->dev;
+	bool bypass;
 
 	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
 	if (!smmu) {
@@ -2614,10 +2624,11 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 	if (irq > 0)
 		smmu->gerr_irq = irq;
 
-	parse_driver_options(smmu);
+	/* Set bypass mode according to firmware probing result */
+	bypass = !!arm_smmu_device_dt_probe(pdev, smmu);
 
 	/* Probe the h/w */
-	ret = arm_smmu_device_probe(smmu);
+	ret = arm_smmu_device_hw_probe(smmu);
 	if (ret)
 		return ret;
 
@@ -2679,7 +2690,7 @@ static struct platform_driver arm_smmu_driver = {
 		.name		= "arm-smmu-v3",
 		.of_match_table	= of_match_ptr(arm_smmu_of_match),
 	},
-	.probe	= arm_smmu_device_dt_probe,
+	.probe	= arm_smmu_device_probe,
 	.remove	= arm_smmu_device_remove,
 };
 
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 09/16] drivers: acpi: iort: add support for ARM SMMU platform devices creation
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

In ARM ACPI systems, IOMMU components are specified through static
IORT table entries. In order to create platform devices for the
corresponding ARM SMMU components, IORT kernel code should be made
able to parse IORT table entries and create platform devices
dynamically.

This patch adds the generic IORT infrastructure required to create
platform devices for ARM SMMUs.

ARM SMMU versions have different resources requirement therefore this
patch also introduces an IORT specific structure (ie iort_iommu_config)
that contains hooks (to be defined when the corresponding ARM SMMU
driver support is added to the kernel) to be used to define the
platform devices names, init the IOMMUs, count their resources and
finally initialize them.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/arm64/iort.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4bb6acb..ddf83b5 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -19,9 +19,11 @@
 #define pr_fmt(fmt)	"ACPI: IORT: " fmt
 
 #include <linux/acpi_iort.h>
+#include <linux/iommu.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 
 struct iort_its_msi_chip {
@@ -457,6 +459,153 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
 	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
 }
 
+struct iort_iommu_config {
+	const char *name;
+	int (*iommu_init)(struct acpi_iort_node *node);
+	bool (*iommu_is_coherent)(struct acpi_iort_node *node);
+	int (*iommu_count_resources)(struct acpi_iort_node *node);
+	void (*iommu_init_resources)(struct resource *res,
+				     struct acpi_iort_node *node);
+};
+
+static __init
+const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
+{
+	return NULL;
+}
+
+/**
+ * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
+ * @node: Pointer to SMMU ACPI IORT node
+ *
+ * Returns: 0 on success, <0 failure
+ */
+static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
+{
+	struct fwnode_handle *fwnode;
+	struct platform_device *pdev;
+	struct resource *r;
+	enum dev_dma_attr attr;
+	int ret, count;
+	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
+
+	if (!ops)
+		return -ENODEV;
+
+	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return PTR_ERR(pdev);
+
+	count = ops->iommu_count_resources(node);
+
+	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
+	if (!r) {
+		ret = -ENOMEM;
+		goto dev_put;
+	}
+
+	ops->iommu_init_resources(r, node);
+
+	ret = platform_device_add_resources(pdev, r, count);
+	/*
+	 * Resources are duplicated in platform_device_add_resources,
+	 * free their allocated memory
+	 */
+	kfree(r);
+
+	if (ret)
+		goto dev_put;
+
+	/*
+	 * Add a copy of IORT node pointer to platform_data to
+	 * be used to retrieve IORT data information.
+	 */
+	ret = platform_device_add_data(pdev, &node, sizeof(node));
+	if (ret)
+		goto dev_put;
+
+	/*
+	 * We expect the dma masks to be equivalent for
+	 * all SMMUs set-ups
+	 */
+	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+	fwnode = iort_get_fwnode(node);
+
+	if (!fwnode) {
+		ret = -ENODEV;
+		goto dev_put;
+	}
+
+	pdev->dev.fwnode = fwnode;
+
+	attr = ops->iommu_is_coherent(node) ?
+			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
+
+	/* Configure DMA for the page table walker */
+	acpi_dma_configure(&pdev->dev, attr);
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto dma_deconfigure;
+
+	return 0;
+
+dma_deconfigure:
+	acpi_dma_deconfigure(&pdev->dev);
+dev_put:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static void __init iort_init_platform_devices(void)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	struct fwnode_handle *fwnode;
+	int i, ret;
+
+	/*
+	 * iort_table and iort both point to the start of IORT table, but
+	 * have different struct types
+	 */
+	iort = (struct acpi_table_iort *)iort_table;
+
+	/* Get the first IORT node */
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				iort_table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (iort_node >= iort_end) {
+			pr_err("iort node pointer overflows, bad table\n");
+			return;
+		}
+
+		if ((iort_node->type == ACPI_IORT_NODE_SMMU) ||
+			(iort_node->type == ACPI_IORT_NODE_SMMU_V3)) {
+
+			fwnode = acpi_alloc_fwnode_static();
+			if (!fwnode)
+				return;
+
+			iort_set_fwnode(iort_node, fwnode);
+
+			ret = iort_add_smmu_platform_device(iort_node);
+			if (ret) {
+				iort_delete_fwnode(iort_node);
+				acpi_free_fwnode_static(fwnode);
+				return;
+			}
+		}
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+}
+
 void __init acpi_iort_init(void)
 {
 	acpi_status status;
@@ -472,5 +621,7 @@ void __init acpi_iort_init(void)
 		return;
 	}
 
+	iort_init_platform_devices();
+
 	acpi_probe_device_table(iort);
 }
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 08/16] drivers: acpi: iort: add node match function
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

Device drivers (eg ARM SMMU) need to know if a specific component
is part of the IORT table, so that kernel data structures are not
initialized at initcalls time if the respective component is not
part of the IORT table.

To this end, this patch adds a trivial function that allows detecting
if a given IORT node type is present or not in the ACPI table, providing
an ACPI IORT equivalent for of_find_matching_node().

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/arm64/iort.c | 15 +++++++++++++++
 include/linux/acpi_iort.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 1ac2720..4bb6acb 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -227,6 +227,21 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
 	return NULL;
 }
 
+static acpi_status
+iort_match_type_callback(struct acpi_iort_node *node, void *context)
+{
+	return AE_OK;
+}
+
+bool iort_node_match(u8 type)
+{
+	struct acpi_iort_node *node;
+
+	node = iort_scan_node(type, iort_match_type_callback, NULL);
+
+	return node != NULL;
+}
+
 static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 					    void *context)
 {
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index d16fdda..17bb078 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -28,10 +28,12 @@ void iort_deregister_domain_token(int trans_id);
 struct fwnode_handle *iort_find_domain_token(int trans_id);
 #ifdef CONFIG_ACPI_IORT
 void acpi_iort_init(void);
+bool iort_node_match(u8 type);
 u32 iort_msi_map_rid(struct device *dev, u32 req_id);
 struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
 #else
 static inline void acpi_iort_init(void) { }
+static inline bool iort_node_match(u8 type) { return false; }
 static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 { return req_id; }
 static inline struct irq_domain *iort_get_device_domain(struct device *dev,
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 07/16] drivers: acpi: implement acpi_dma_configure
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

On DT based systems, the of_dma_configure() API implements DMA
configuration for a given device. On ACPI systems an API equivalent to
of_dma_configure() is missing which implies that it is currently not
possible to set-up DMA operations for devices through the ACPI generic
kernel layer.

This patch fills the gap by introducing acpi_dma_configure/deconfigure()
calls that for now are just wrappers around arch_setup_dma_ops() and
arch_teardown_dma_ops() and also updates ACPI and PCI core code to use
the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions.

Since acpi_dma_configure() is used to configure DMA operations, the
function initializes the dma/coherent_dma masks to sane default values
if the current masks are uninitialized (also to keep the default values
consistent with DT systems) to make sure the device has a complete
default DMA set-up.

The DMA range size passed to arch_setup_dma_ops() is sized according
to the device coherent_dma_mask (starting at address 0x0), mirroring the
DT probing path behaviour when a dma-ranges property is not provided
for the device being probed; this changes the current arch_setup_dma_ops()
call parameters in the ACPI probing case, but since arch_setup_dma_ops()
is a NOP on all architectures but ARM/ARM64 this patch does not change
the current kernel behaviour on them.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> [pci]
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/glue.c     |  4 ++--
 drivers/acpi/scan.c     | 40 ++++++++++++++++++++++++++++++++++++++++
 drivers/pci/probe.c     |  3 +--
 include/acpi/acpi_bus.h |  2 ++
 include/linux/acpi.h    |  5 +++++
 5 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 5ea5dc2..f8d6564 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 
 	attr = acpi_get_dma_attr(acpi_dev);
 	if (attr != DEV_DMA_NOT_SUPPORTED)
-		arch_setup_dma_ops(dev, 0, 0, NULL,
-				   attr == DEV_DMA_COHERENT);
+		acpi_dma_configure(dev, attr);
 
 	acpi_physnode_link_name(physical_node_name, node_id);
 	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
@@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 	return 0;
 
  err:
+	acpi_dma_deconfigure(dev);
 	ACPI_COMPANION_SET(dev, NULL);
 	put_device(dev);
 	put_device(&acpi_dev->dev);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 3d1856f..45b5710 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1370,6 +1370,46 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
 		return DEV_DMA_NON_COHERENT;
 }
 
+/**
+ * acpi_dma_configure - Set-up DMA configuration for the device.
+ * @dev: The pointer to the device
+ * @attr: device dma attributes
+ */
+void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
+{
+	/*
+	 * Set default coherent_dma_mask to 32 bit.  Drivers are expected to
+	 * setup the correct supported mask.
+	 */
+	if (!dev->coherent_dma_mask)
+		dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	/*
+	 * Set it to coherent_dma_mask by default if the architecture
+	 * code has not set it.
+	 */
+	if (!dev->dma_mask)
+		dev->dma_mask = &dev->coherent_dma_mask;
+
+	/*
+	 * Assume dma valid range starts at 0 and covers the whole
+	 * coherent_dma_mask.
+	 */
+	arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+			   attr == DEV_DMA_COHERENT);
+}
+EXPORT_SYMBOL_GPL(acpi_dma_configure);
+
+/**
+ * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
+ * @dev: The pointer to the device
+ */
+void acpi_dma_deconfigure(struct device *dev)
+{
+	arch_teardown_dma_ops(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_dma_deconfigure);
+
 static void acpi_init_coherency(struct acpi_device *adev)
 {
 	unsigned long long cca = 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ab00267..c29e07a 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1738,8 +1738,7 @@ static void pci_dma_configure(struct pci_dev *dev)
 		if (attr == DEV_DMA_NOT_SUPPORTED)
 			dev_warn(&dev->dev, "DMA not supported.\n");
 		else
-			arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
-					   attr == DEV_DMA_COHERENT);
+			acpi_dma_configure(&dev->dev, attr);
 	}
 
 	pci_put_host_bridge_device(bridge);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c1a524d..4242c31 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -573,6 +573,8 @@ struct acpi_pci_root {
 
 bool acpi_dma_supported(struct acpi_device *adev);
 enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
+void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
+void acpi_dma_deconfigure(struct device *dev);
 
 struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
 					   u64 address, bool check_children);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 996a29c..8d15fc5 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -765,6 +765,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
 	return DEV_DMA_NOT_SUPPORTED;
 }
 
+static inline void acpi_dma_configure(struct device *dev,
+				      enum dev_dma_attr attr) { }
+
+static inline void acpi_dma_deconfigure(struct device *dev) { }
+
 #define ACPI_PTR(_ptr)	(NULL)
 
 static inline void acpi_device_set_enumerated(struct acpi_device *adev)
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 06/16] drivers: iommu: arm-smmu-v3: convert struct device of_node to fwnode usage
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

Current ARM SMMU v3 driver rely on the struct device.of_node pointer for
device look-up and iommu_ops retrieval.

In preparation for ACPI probing enablement, convert the driver to use
the struct device.fwnode member for device and iommu_ops look-up so that
the driver infrastructure can be used also on systems that do not
associate an of_node pointer to a struct device (eg ACPI), making the
device look-up and iommu_ops retrieval firmware agnostic.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/arm-smmu-v3.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index e6f9b2d..e6e1c87 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1723,13 +1723,14 @@ static struct platform_driver arm_smmu_driver;
 
 static int arm_smmu_match_node(struct device *dev, void *data)
 {
-	return dev->of_node == data;
+	return dev->fwnode == data;
 }
 
-static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
 {
 	struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
-						np, arm_smmu_match_node);
+						fwnode, arm_smmu_match_node);
 	put_device(dev);
 	return dev ? dev_get_drvdata(dev) : NULL;
 }
@@ -1765,7 +1766,7 @@ static int arm_smmu_add_device(struct device *dev)
 		master = fwspec->iommu_priv;
 		smmu = master->smmu;
 	} else {
-		smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode));
+		smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
 		if (!smmu)
 			return -ENODEV;
 		master = kzalloc(sizeof(*master), GFP_KERNEL);
@@ -2634,7 +2635,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 		return ret;
 
 	/* And we're up. Go go go! */
-	of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+	iommu_register_instance(dev->fwnode, &arm_smmu_ops);
+
 #ifdef CONFIG_PCI
 	if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
 		pci_request_acs();
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 05/16] drivers: iommu: arm-smmu: convert struct device of_node to fwnode usage
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

Current ARM SMMU driver rely on the struct device.of_node pointer for
device look-up and iommu_ops retrieval.

In preparation for ACPI probing enablement, convert the driver to use
the struct device.fwnode member for device and iommu_ops look-up so that
the driver infrastructure can be used also on systems that do not
associate an of_node pointer to a struct device (eg ACPI), making the
device look-up and iommu_ops retrieval firmware agnostic.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/arm-smmu.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8f72814..339a8d3 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1379,13 +1379,14 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 
 static int arm_smmu_match_node(struct device *dev, void *data)
 {
-	return dev->of_node == data;
+	return dev->fwnode == data;
 }
 
-static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
 {
 	struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
-						np, arm_smmu_match_node);
+						fwnode, arm_smmu_match_node);
 	put_device(dev);
 	return dev ? dev_get_drvdata(dev) : NULL;
 }
@@ -1403,7 +1404,7 @@ static int arm_smmu_add_device(struct device *dev)
 		if (ret)
 			goto out_free;
 	} else if (fwspec && fwspec->ops == &arm_smmu_ops) {
-		smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode));
+		smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
 	} else {
 		return -ENODEV;
 	}
@@ -2007,7 +2008,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 		}
 	}
 
-	of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+	iommu_register_instance(dev->fwnode, &arm_smmu_ops);
 	platform_set_drvdata(pdev, smmu);
 	arm_smmu_device_reset(smmu);
 
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 04/16] drivers: iommu: make of_iommu_set/get_ops() DT agnostic
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

The of_iommu_{set/get}_ops() API is used to associate a device
tree node with a specific set of IOMMU operations. The same
kernel interface is required on systems booting with ACPI, where
devices are not associated with a device tree node, therefore
the interface requires generalization.

The struct device fwnode member represents the fwnode token associated
with the device and the struct it points at is firmware specific;
regardless, it is initialized on both ACPI and DT systems and makes an
ideal candidate to use it to associate a set of IOMMU operations to a
given device, through its struct device.fwnode member pointer, paving
the way for representing per-device iommu_ops (ie an iommu instance
associated with a device).

Convert the DT specific of_iommu_{set/get}_ops() interface to
use struct device.fwnode as a look-up token, making the interface
usable on ACPI systems and rename the data structures and the
registration API so that they are made to represent their usage
more clearly.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
 drivers/iommu/iommu.c    | 40 ++++++++++++++++++++++++++++++++++++++++
 drivers/iommu/of_iommu.c | 39 ---------------------------------------
 include/linux/iommu.h    | 14 ++++++++++++++
 include/linux/of_iommu.h | 12 ++++++++++--
 4 files changed, 64 insertions(+), 41 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9a2f196..8d3e847 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1615,6 +1615,46 @@ int iommu_request_dm_for_dev(struct device *dev)
 	return ret;
 }
 
+struct iommu_instance {
+	struct list_head list;
+	struct fwnode_handle *fwnode;
+	const struct iommu_ops *ops;
+};
+static LIST_HEAD(iommu_instance_list);
+static DEFINE_SPINLOCK(iommu_instance_lock);
+
+void iommu_register_instance(struct fwnode_handle *fwnode,
+			     const struct iommu_ops *ops)
+{
+	struct iommu_instance *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+
+	if (WARN_ON(!iommu))
+		return;
+
+	of_node_get(to_of_node(fwnode));
+	INIT_LIST_HEAD(&iommu->list);
+	iommu->fwnode = fwnode;
+	iommu->ops = ops;
+	spin_lock(&iommu_instance_lock);
+	list_add_tail(&iommu->list, &iommu_instance_list);
+	spin_unlock(&iommu_instance_lock);
+}
+
+const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
+{
+	struct iommu_instance *instance;
+	const struct iommu_ops *ops = NULL;
+
+	spin_lock(&iommu_instance_lock);
+	list_for_each_entry(instance, &iommu_instance_list, list)
+		if (instance->fwnode == fwnode) {
+			ops = instance->ops;
+			break;
+		}
+	spin_unlock(&iommu_instance_lock);
+	return ops;
+}
+
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
 		      const struct iommu_ops *ops)
 {
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 5b82862..0f57ddc 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -96,45 +96,6 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
 }
 EXPORT_SYMBOL_GPL(of_get_dma_window);
 
-struct of_iommu_node {
-	struct list_head list;
-	struct device_node *np;
-	const struct iommu_ops *ops;
-};
-static LIST_HEAD(of_iommu_list);
-static DEFINE_SPINLOCK(of_iommu_lock);
-
-void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops)
-{
-	struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
-
-	if (WARN_ON(!iommu))
-		return;
-
-	of_node_get(np);
-	INIT_LIST_HEAD(&iommu->list);
-	iommu->np = np;
-	iommu->ops = ops;
-	spin_lock(&of_iommu_lock);
-	list_add_tail(&iommu->list, &of_iommu_list);
-	spin_unlock(&of_iommu_lock);
-}
-
-const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
-{
-	struct of_iommu_node *node;
-	const struct iommu_ops *ops = NULL;
-
-	spin_lock(&of_iommu_lock);
-	list_for_each_entry(node, &of_iommu_list, list)
-		if (node->np == np) {
-			ops = node->ops;
-			break;
-		}
-	spin_unlock(&of_iommu_lock);
-	return ops;
-}
-
 static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
 {
 	struct of_phandle_args *iommu_spec = data;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 436dc21..f2960e4 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -351,6 +351,9 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
 		      const struct iommu_ops *ops);
 void iommu_fwspec_free(struct device *dev);
 int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+void iommu_register_instance(struct fwnode_handle *fwnode,
+			     const struct iommu_ops *ops);
+const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -580,6 +583,17 @@ static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
 	return -ENODEV;
 }
 
+static inline void iommu_register_instance(struct fwnode_handle *fwnode,
+					   const struct iommu_ops *ops)
+{
+}
+
+static inline
+const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
+{
+	return NULL;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index e80b9c7..6a7fc50 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -31,8 +31,16 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
 
 #endif	/* CONFIG_OF_IOMMU */
 
-void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops);
-const struct iommu_ops *of_iommu_get_ops(struct device_node *np);
+static inline void of_iommu_set_ops(struct device_node *np,
+				    const struct iommu_ops *ops)
+{
+	iommu_register_instance(&np->fwnode, ops);
+}
+
+static inline const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
+{
+	return iommu_get_instance(&np->fwnode);
+}
 
 extern struct of_device_id __iommu_of_table;
 
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 03/16] drivers: acpi: iort: add support for IOMMU fwnode registration
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

The ACPI IORT table provide entries for IOMMU (aka SMMU in ARM world)
components that allow creating the kernel data structures required to
probe and initialize the IOMMU devices.

This patch provides support in the IORT kernel code to register IOMMU
components and their respective fwnode.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/acpi/arm64/iort.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 2c46ebc..1ac2720 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -20,7 +20,9 @@
 
 #include <linux/acpi_iort.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/pci.h>
+#include <linux/slab.h>
 
 struct iort_its_msi_chip {
 	struct list_head	list;
@@ -28,6 +30,90 @@ struct iort_its_msi_chip {
 	u32			translation_id;
 };
 
+struct iort_fwnode {
+	struct list_head list;
+	struct acpi_iort_node *iort_node;
+	struct fwnode_handle *fwnode;
+};
+static LIST_HEAD(iort_fwnode_list);
+static DEFINE_SPINLOCK(iort_fwnode_lock);
+
+/**
+ * iort_set_fwnode() - Create iort_fwnode and use it to register
+ *		       iommu data in the iort_fwnode_list
+ *
+ * @node: IORT table node associated with the IOMMU
+ * @fwnode: fwnode associated with the IORT node
+ *
+ * Returns: 0 on success
+ *          <0 on failure
+ */
+static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
+				  struct fwnode_handle *fwnode)
+{
+	struct iort_fwnode *np;
+
+	np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
+
+	if (WARN_ON(!np))
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&np->list);
+	np->iort_node = iort_node;
+	np->fwnode = fwnode;
+
+	spin_lock(&iort_fwnode_lock);
+	list_add_tail(&np->list, &iort_fwnode_list);
+	spin_unlock(&iort_fwnode_lock);
+
+	return 0;
+}
+
+/**
+ * iort_get_fwnode() - Retrieve fwnode associated with an IORT node
+ *
+ * @node: IORT table node to be looked-up
+ *
+ * Returns: fwnode_handle pointer on success, NULL on failure
+ */
+static inline
+struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
+{
+	struct iort_fwnode *curr;
+	struct fwnode_handle *fwnode = NULL;
+
+	spin_lock(&iort_fwnode_lock);
+	list_for_each_entry(curr, &iort_fwnode_list, list) {
+		if (curr->iort_node == node) {
+			fwnode = curr->fwnode;
+			break;
+		}
+	}
+	spin_unlock(&iort_fwnode_lock);
+
+	return fwnode;
+}
+
+/**
+ * iort_delete_fwnode() - Delete fwnode associated with an IORT node
+ *
+ * @node: IORT table node associated with fwnode to delete
+ */
+static inline void iort_delete_fwnode(struct acpi_iort_node *node)
+{
+	struct iort_fwnode *curr, *tmp;
+
+	spin_lock(&iort_fwnode_lock);
+	list_for_each_entry_safe(curr, tmp, &iort_fwnode_list, list) {
+		if (curr->iort_node == node) {
+			list_del(&curr->list);
+			kfree(curr);
+			break;
+		}
+	}
+	spin_unlock(&iort_fwnode_lock);
+}
+
 typedef acpi_status (*iort_find_node_callback)
 	(struct acpi_iort_node *node, void *context);
 
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 02/16] drivers: acpi: iort: introduce linker section for IORT entries probing
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

Since commit e647b532275b ("ACPI: Add early device probing
infrastructure") the kernel has gained the infrastructure that allows
adding linker script section entries to execute ACPI driver callbacks
(ie probe routines) for all subsystems that register a table entry
in the respective kernel section (eg clocksource, irqchip).

Since ARM IOMMU devices data is described through IORT tables when
booting with ACPI, the ARM IOMMU drivers must be made able to hook ACPI
callback routines that are called to probe IORT entries and initialize
the respective IOMMU devices.

To avoid adding driver specific hooks into IORT table initialization
code (breaking therefore code modularity - ie ACPI IORT code must be made
aware of ARM SMMU drivers ACPI init callbacks), this patch adds code
that allows ARM SMMU drivers to take advantage of the ACPI early probing
infrastructure, so that they can add linker script section entries
containing drivers callback to be executed on IORT tables detection.

Since IORT nodes are differentiated by a type, the callback routines
can easily parse the IORT table entries, check the IORT nodes and
carry out some actions whenever the IORT node type associated with
the driver specific callback is matched.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/acpi/arm64/iort.c         | 13 ++++++++++---
 include/asm-generic/vmlinux.lds.h |  1 +
 include/linux/acpi_iort.h         |  3 +++
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6b81746..2c46ebc 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -361,8 +361,15 @@ void __init acpi_iort_init(void)
 	acpi_status status;
 
 	status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		const char *msg = acpi_format_exception(status);
-		pr_err("Failed to get table, %s\n", msg);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			const char *msg = acpi_format_exception(status);
+
+			pr_err("Failed to get table, %s\n", msg);
+		}
+
+		return;
 	}
+
+	acpi_probe_device_table(iort);
 }
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 31e1d63..9e3aa34 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -566,6 +566,7 @@
 	IRQCHIP_OF_MATCH_TABLE()					\
 	ACPI_PROBE_TABLE(irqchip)					\
 	ACPI_PROBE_TABLE(clksrc)					\
+	ACPI_PROBE_TABLE(iort)						\
 	EARLYCON_TABLE()
 
 #define INIT_TEXT							\
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 0e32dac..d16fdda 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -39,4 +39,7 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
 { return NULL; }
 #endif
 
+#define IORT_ACPI_DECLARE(name, table_id, fn)		\
+	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
+
 #endif /* __ACPI_IORT_H__ */
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 01/16] drivers: acpi: add FWNODE_ACPI_STATIC fwnode type
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121100148.24769-1-lorenzo.pieralisi@arm.com>

On systems booting with a device tree, every struct device is associated
with a struct device_node, that provides its DT firmware representation.
The device node can be used in generic kernel contexts (eg IRQ
translation, IOMMU streamid mapping), to retrieve the properties
associated with the device and carry out kernel operations accordingly.
Owing to the 1:1 relationship between the device and its device_node,
the device_node can also be used as a look-up token for the device (eg
looking up a device through its device_node), to retrieve the device in
kernel paths where the device_node is available.

On systems booting with ACPI, the same abstraction provided by
the device_node is required to provide look-up functionality.

The struct acpi_device, that represents firmware objects in the
ACPI namespace already includes a struct fwnode_handle of
type FWNODE_ACPI as their member; the same abstraction is missing
though for devices that are instantiated out of static ACPI tables
entries (eg ARM SMMU devices).

Add a new fwnode_handle type to associate devices created out
of static ACPI table entries to the respective firmware components
and create a simple ACPI core layer interface to dynamically allocate
and free the corresponding firmware nodes so that kernel subsystems
can use it to instantiate the nodes and associate them with the
respective devices.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 include/linux/acpi.h   | 21 +++++++++++++++++++++
 include/linux/fwnode.h |  3 ++-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 61a3d90..996a29c 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -56,6 +56,27 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
 	acpi_fwnode_handle(adev) : NULL)
 #define ACPI_HANDLE(dev)		acpi_device_handle(ACPI_COMPANION(dev))
 
+static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
+{
+	struct fwnode_handle *fwnode;
+
+	fwnode = kzalloc(sizeof(struct fwnode_handle), GFP_KERNEL);
+	if (!fwnode)
+		return NULL;
+
+	fwnode->type = FWNODE_ACPI_STATIC;
+
+	return fwnode;
+}
+
+static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
+{
+	if (WARN_ON(!fwnode || fwnode->type != FWNODE_ACPI_STATIC))
+		return;
+
+	kfree(fwnode);
+}
+
 /**
  * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with
  * the PCI-defined class-code information
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 8516717..8bd28ce 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -17,8 +17,9 @@ enum fwnode_type {
 	FWNODE_OF,
 	FWNODE_ACPI,
 	FWNODE_ACPI_DATA,
+	FWNODE_ACPI_STATIC,
 	FWNODE_PDATA,
-	FWNODE_IRQCHIP,
+	FWNODE_IRQCHIP
 };
 
 struct fwnode_handle {
-- 
2.10.0

^ permalink raw reply related

* [PATCH v9 00/16] ACPI IORT ARM SMMU support
From: Lorenzo Pieralisi @ 2016-11-21 10:01 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series is v9 of a previous posting:

https://lkml.org/lkml/2016/11/16/386

v8 -> v9
	- Updated bypass flag handling in ARM SMMU v3 according to
	  reviews
	- Removed SMMUv1/v2 configuration interrupt handling
	- Rebased against v4.9-rc5
	- Updated tags

v7 -> v8
	- Renamed fwnode iommu_ops registration API according to review
	- Minor change in ARM SMMU driver DT/ACPI split
	- Added review tags

v6 -> v7
	- Rebased against v4.9-rc4
	- Fixed IORT probing on ACPI systems with missing IORT table
	- Fixed SMMUv1/v2 global interrupt detection
	- Updated iommu_ops firmware look-up

v5 -> v6
	- Rebased against v4.9-rc1
	- Changed FWNODE_IOMMU to FWNODE_ACPI_STATIC
	- Moved platform devices creation into IORT code
	- Updated fwnode handling
	- Added default dma masks initialization

v4 -> v5
	- Added SMMUv1/v2 support
	- Rebased against v4.8-rc5 and dependencies series
	- Consolidated IORT platform devices creation

v3 -> v4
	- Added single mapping API (for IORT named components)
	- Fixed arm_smmu_iort_xlate() return value
	- Reworked fwnode registration and platform device creation
	  ordering to fix probe ordering dependencies
	- Added code to keep device_node ref count with new iommu
	  fwspec API
	- Added patch to make iommu_fwspec arch agnostic
	- Dropped RFC status
	- Rebased against v4.8-rc2

v2 -> v3
	- Rebased on top of dependencies series [1][2][3](v4.7-rc3)
	- Added back reliance on ACPI early probing infrastructure
	- Patch[1-3] merged through other dependent series
	- Added back IOMMU fwnode generalization
	- Move SMMU v3 static functions configuration to IORT code
	- Implemented generic IOMMU fwspec API
	- Added code to implement fwnode platform device look-up

v1 -> v2:
	- Rebased on top of dependencies series [1][2][3](v4.7-rc1)
	- Removed IOMMU fwnode generalization
	- Implemented ARM SMMU v3 ACPI probing instead of ARM SMMU v2
	  owing to patch series dependencies [1]
	- Moved platform device creation logic to IORT code to
	  generalize its usage for ARM SMMU v1-v2-v3 components
	- Removed reliance on ACPI early device probing
	- Created IORT specific iommu_xlate() translation hook leaving
	  OF code unchanged according to v1 reviews

The ACPI IORT table provides information that allows instantiating
ARM SMMU devices and carrying out id mappings between components on
ARM based systems (devices, IOMMUs, interrupt controllers).

http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf

Building on basic IORT support, this patchset enables ARM SMMUs support
on ACPI systems.

Most of the code is aimed at building the required generic ACPI
infrastructure to create and enable IOMMU components and to bring
the IOMMU infrastructure for ACPI on par with DT, which is going to
make future ARM SMMU components easier to integrate.

PATCH (1) adds a FWNODE_ACPI_STATIC type to the struct fwnode_handle type.
          It is required to attach a fwnode identifier to platform
          devices allocated/detected through static ACPI table entries
          (ie IORT tables entries).
          IOMMU devices have to have an identifier to look them up
          eg IOMMU core layer carrying out id translation. This can be
          done through a fwnode_handle (ie IOMMU platform devices created
          out of IORT tables are not ACPI devices hence they can't be
          allocated as such, otherwise they would have a fwnode_handle of
          type FWNODE_ACPI).

PATCH (2) makes use of the ACPI early probing API to add a linker script
          section for probing devices via IORT ACPI kernel code.

PATCH (3) provides IORT support for registering IOMMU IORT node through
          their fwnode handle.

PATCH (4) make of_iommu_{set/get}_ops() functions DT agnostic and
          rename the registration API.

PATCH (5) convert ARM SMMU driver to use fwnode instead of of_node as
          look-up and iommu_ops retrieval token.

PATCH (6) convert ARM SMMU v3 driver to use fwnode instead of of_node as
          look-up and iommu_ops retrieval token.

PATCH (7) implements the of_dma_configure() API in ACPI world -
          acpi_dma_configure() - and patches PCI and ACPI core code to
          start making use of it.

PATCH (8) provides an IORT function to detect existence of specific type
          of IORT components.

PATCH (9) creates the kernel infrastructure required to create ARM SMMU
          platform devices for IORT nodes.

PATCH (10) refactors the ARM SMMU v3 driver so that the init functions are
           split in a way that groups together code that probes through DT
           and code that carries out HW registers FW agnostic probing, in
           preparation for adding the ACPI probing path.

PATCH (11) adds ARM SMMU v3 IORT IOMMU operations to create and probe
           ARM SMMU v3 components.

PATCH (12) refactors the ARM SMMU v1/v2 driver so that the init functions
           are split in a way that groups together code that probes
           through DT and code that carries out HW registers FW agnostic
           probing, in preparation for adding the ACPI probing path.

PATCH (13) adds ARM SMMU v1/v2 IORT IOMMU operations to create and
           probe ARM SMMU v1/v2 components.

PATCH (14) Extend the IORT iort_node_map_rid() to work on a type mask
           instead of a single type so that the translation API can
           be used on a range of components.

PATCH (15) Add IORT API to carry out id mappings for components that do
           do not have an input identifier/RIDs (ie named components).

PATCH (16) provides IORT infrastructure to carry out IOMMU configuration
           for devices and hook it up to the previously introduced ACPI
           DMA configure API.

This patchset is provided for review/testing purposes here:

git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git acpi/iort-smmu-v9

Tested on Juno and FVP models for ARM SMMU v1 and v3 probing path.

Lorenzo Pieralisi (16):
  drivers: acpi: add FWNODE_ACPI_STATIC fwnode type
  drivers: acpi: iort: introduce linker section for IORT entries probing
  drivers: acpi: iort: add support for IOMMU fwnode registration
  drivers: iommu: make of_iommu_set/get_ops() DT agnostic
  drivers: iommu: arm-smmu: convert struct device of_node to fwnode
    usage
  drivers: iommu: arm-smmu-v3: convert struct device of_node to fwnode
    usage
  drivers: acpi: implement acpi_dma_configure
  drivers: acpi: iort: add node match function
  drivers: acpi: iort: add support for ARM SMMU platform devices
    creation
  drivers: iommu: arm-smmu-v3: split probe functions into DT/generic
    portions
  drivers: iommu: arm-smmu-v3: add IORT configuration
  drivers: iommu: arm-smmu: split probe functions into DT/generic
    portions
  drivers: iommu: arm-smmu: add IORT configuration
  drivers: acpi: iort: replace rid map type with type mask
  drivers: acpi: iort: add single mapping function
  drivers: acpi: iort: introduce iort_iommu_configure

 drivers/acpi/arm64/iort.c         | 585 +++++++++++++++++++++++++++++++++++++-
 drivers/acpi/glue.c               |   4 +-
 drivers/acpi/scan.c               |  45 +++
 drivers/iommu/arm-smmu-v3.c       | 102 +++++--
 drivers/iommu/arm-smmu.c          | 148 ++++++++--
 drivers/iommu/iommu.c             |  40 +++
 drivers/iommu/of_iommu.c          |  39 ---
 drivers/pci/probe.c               |   3 +-
 include/acpi/acpi_bus.h           |   2 +
 include/asm-generic/vmlinux.lds.h |   1 +
 include/linux/acpi.h              |  26 ++
 include/linux/acpi_iort.h         |  14 +
 include/linux/fwnode.h            |   3 +-
 include/linux/iommu.h             |  14 +
 include/linux/of_iommu.h          |  12 +-
 15 files changed, 934 insertions(+), 104 deletions(-)

-- 
2.10.0

^ permalink raw reply

* [PATCH] mtd: nand: tango: Use nand_to_mtd() instead of directly accessing chip->mtd
From: Marc Gonzalez @ 2016-11-21  9:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479718984-26491-1-git-send-email-boris.brezillon@free-electrons.com>

On 21/11/2016 10:03, Boris Brezillon wrote:

> The nand_to_mtd() helper is here to hide internal mtd_info <-> nand_chip
> association and ease future refactors.
> 
> Make use of this helper instead of directly accessing chip->mtd.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> ---
>  drivers/mtd/nand/tango_nand.c | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)

Acked-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>

Regards.

^ permalink raw reply

* [PATCH v16 06/15] clocksource/drivers/arm_arch_timer: separate out arch_timer_uses_ppi init code to prepare for GTDT.
From: Fu Wei @ 2016-11-21  9:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161118193054.GK1197@leverpostej>

Hi Mark,

On 19 November 2016 at 03:30, Mark Rutland <mark.rutland@arm.com> wrote:
> On Wed, Nov 16, 2016 at 09:48:59PM +0800, fu.wei at linaro.org wrote:
>> From: Fu Wei <fu.wei@linaro.org>
>>
>> The patch refactor original arch_timer_uses_ppi init code:
>> (1) Extract a subfunction: arch_timer_uses_ppi_init
>> (2) Use the new subfunction in arch_timer_of_init and
>> arch_timer_acpi_init
>
> This isn't a strict refactoring, since this now assigns
> ARCH_TIMER_PHYS_NONSECURE_PPI to arch_timer_uses_ppi, which we didn't do
> previously.
>
> As a general note, please write your commit messages as prose rather
> than a list of bullet points. Please also explain the rationale for the
> change, rather than enumerating the changes. Call out things which are
> important and/or likely to surprise reviewers, for example:
>
> * Can 32-bit ARM still use non-secure interrupts afer this change?
>
> * Does the "arm,cpu-registers-not-fw-configured"  proeprty still work?
>
> That will make it vastly easier to have this code reviewed, and it will
> be far more helpful for anyone looking at this in future.
>
> For example:
>
>   arm_arch_timer: rework PPI determination
>
>   Currently, the arch timer driver uses ARCH_TIMER_PHYS_SECURE_PPI to
>   mean the driver will use the secure PPI *and* potentialy also use the
>   non-secure PPI. This is somewhat confusing.
>
>   For arm64, where it never makes sense to use the secure PPI, this
>   means we must always request the useless secure PPI, adding to the
>   confusion. For ACPI, where we may not even have a valid secure PPI
>   number, this is additionally problematic. We need the driver to be
>   able to use *only* the non-secure PPI.
>
>   The logic to choose which PPI to use is intertwined with other logic
>   in arch_timer_init(). This patch factors the PPI determination out
>   into a new function, and then reworks it so that we can handle having
>   only a non-secure PPI.

Great thanks for your example, will use this,  :-)

maybe add :
For ARM32, it still can use non-secure interrupts after this change, and
the "arm,cpu-registers-not-fw-configured"  property still works.

>
> [...]
>
>> +/*
>> + * If HYP mode is available, we know that the physical timer
>> + * has been configured to be accessible from PL1. Use it, so
>> + * that a guest can use the virtual timer instead.
>> + *
>> + * If no interrupt provided for virtual timer, we'll have to
>> + * stick to the physical timer. It'd better be accessible...
>> + * On ARM64, we we only use ARCH_TIMER_PHYS_NONSECURE_PPI in Linux.
>
> It would be better to say that for arm64 we never use the secure
> interrupt.

For ARM64, we never use the secure interrupt, so it will be set to
ARCH_TIMER_PHYS_NONSECURE_PPI instead.

>
>> + *
>> + * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
>> + * accesses to CNTP_*_EL1 registers are silently redirected to
>> + * their CNTHP_*_EL2 counterparts, and use a different PPI
>> + * number.
>> + */
>> +static int __init arch_timer_uses_ppi_init(void)
>
> It would be better to call this something like arch_timer_select_ppi().
> As it stands, the name is difficult to read.

Yes, good idea, will do

>
>> @@ -902,6 +904,10 @@ static int __init arch_timer_of_init(struct device_node *np)
>>           of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
>>               arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
>>
>> +     ret = arch_timer_uses_ppi_init();
>> +     if (ret)
>> +             return ret;
>
> This is clearly broken if you consider what the statement above is
> doing.

Maybe I misunderstand this, I tried to follow the original logic.

Are you saying: we should use arch_timer_select_ppi() first,
then (maybe) change arch_timer_uses_ppi according to
"arm,cpu-registers-not-fw-configured"?

Please correct me, if I misunderstand this.

>
> Thanks,
> Mark.



-- 
Best regards,

Fu Wei
Software Engineer
Red Hat

^ permalink raw reply

* [BUG] hdlcd gets confused about base address
From: Daniel Vetter @ 2016-11-21  9:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161118233733.GP1041@n2100.armlinux.org.uk>

On Fri, Nov 18, 2016 at 11:37:33PM +0000, Russell King - ARM Linux wrote:
> Hi,
> 
> While testing HDMI with Xorg on the Juno board, I find that when Xorg
> starts up or shuts down, the display is shifted significantly to the
> right and wrapped in the active region.  (No sync bars are visible.)
> The timings are correct, it behaves as if the start address has been
> shifted many pixels _into_ the framebuffer.
> 
> This occurs whenever the display mode size is changed - using xrandr
> in Xorg shows that changing the resolution triggers the problem
> almost every time, but changing the refresh rate does not.
> 
> Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> and repeated disable/enable cycles do not make the issue re-appear.
> 
> So, I patched the HDLCD to do this, and testing it with Xorg after
> several repetitions seems to work.
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> ---
> What I think is going on is that the FIFO or address generator for
> reading data from the AXI bus is not properly reset when changing the
> resolution, and the enable-disable-enable cycle causes the HDLCD
> hardware to sort itself out.  It's (eg) significantly out - for example,
> to properly align the display, I have to program an address of
> 0xf4ff0200 into the hardware rather than 0xf5000000 - that's 896 pixels
> before the real start of the frame buffer.
> 
> With this patch, a patch to TDA998x to avoid the i2c-designware issue,
> and xf86-video-armada, I have LXDE running on the Juno.
> 
> Something I also noticed is this:
> 
>         scanout_start = gem->paddr + plane->state->fb->offsets[0] +
>                 plane->state->crtc_y * plane->state->fb->pitches[0] +
>                 plane->state->crtc_x * bpp / 8;
> 
> Surely this should be using src_[xy] (which are the position in the
> source - iow, memory, and not crtc_[xy] which is the position on the
> CRTC displayed window.  To put it another way, the src_* define the
> region of the source material that is mapped onto a rectangular area
> on the display defined by crtc_*.
> 
> Another note is that since the CRTC can't place the plane in arbitary
> positions and sizes within the active area, should the atomic_check
> ensure that crtc_x = crtc_y = 0, and the crtc width/height are the
> size of the active area?

Yup, it should. See drm_plane_helper_check_state() and its caller for a
helper to make this easier. Long-term computing this stuff by default and
having a bunch of igts to regression-test it would be good I think, but
that needs CRC support. And lots of work, since we have lots of drivers.
-Daniel

> 
>  drivers/gpu/drm/arm/hdlcd_crtc.c |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
> index 48019ae22ddb..3e97acf6e2a7 100644
> --- a/drivers/gpu/drm/arm/hdlcd_crtc.c
> +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
> @@ -150,6 +150,8 @@ static void hdlcd_crtc_enable(struct drm_crtc *crtc)
>  	clk_prepare_enable(hdlcd->clk);
>  	hdlcd_crtc_mode_set_nofb(crtc);
>  	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
> +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
>  }
>  
>  static void hdlcd_crtc_disable(struct drm_crtc *crtc)
> 
> 
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply

* [kvm-unit-tests PATCH v9 3/3] arm: pmu: Add CPI checking
From: Andrew Jones @ 2016-11-21  9:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479528942-21866-4-git-send-email-wei@redhat.com>

On Fri, Nov 18, 2016 at 10:15:42PM -0600, Wei Huang wrote:
> From: Christopher Covington <cov@codeaurora.org>
> 
> Calculate the numbers of cycles per instruction (CPI) implied by ARM
> PMU cycle counter values. The code includes a strict checking facility
> intended for the -icount option in TCG mode in the configuration file.
> 
> Signed-off-by: Christopher Covington <cov@codeaurora.org>
> Signed-off-by: Wei Huang <wei@redhat.com>
> ---
>  arm/pmu.c         | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  arm/unittests.cfg |  14 +++++++
>  2 files changed, 124 insertions(+), 1 deletion(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index fa87de4..b36c4fb 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -104,6 +104,25 @@ static inline uint32_t id_dfr0_read(void)
>  	asm volatile("mrc p15, 0, %0, c0, c1, 2" : "=r" (val));
>  	return val;
>  }
> +
> +/*
> + * Extra instructions inserted by the compiler would be difficult to compensate
> + * for, so hand assemble everything between, and including, the PMCR accesses
> + * to start and stop counting.
> + */
> +static inline void loop(int i, uint32_t pmcr)

Thought you were going to rename this function.

> +{
> +	asm volatile(
> +	"	mcr	p15, 0, %[pmcr], c9, c12, 0\n"
> +	"	isb\n"
> +	"1:	subs	%[i], %[i], #1\n"
> +	"	bgt	1b\n"
> +	"	mcr	p15, 0, %[z], c9, c12, 0\n"
> +	"	isb\n"
> +	: [i] "+r" (i)
> +	: [pmcr] "r" (pmcr), [z] "r" (0)
> +	: "cc");
> +}
>  #elif defined(__aarch64__)
>  static inline uint32_t pmcr_read(void)
>  {
> @@ -150,6 +169,25 @@ static inline uint32_t id_dfr0_read(void)
>  	asm volatile("mrs %0, id_dfr0_el1" : "=r" (id));
>  	return id;
>  }
> +
> +/*
> + * Extra instructions inserted by the compiler would be difficult to compensate
> + * for, so hand assemble everything between, and including, the PMCR accesses
> + * to start and stop counting.
> + */
> +static inline void loop(int i, uint32_t pmcr)
> +{
> +	asm volatile(
> +	"	msr	pmcr_el0, %[pmcr]\n"
> +	"	isb\n"
> +	"1:	subs	%[i], %[i], #1\n"
> +	"	b.gt	1b\n"
> +	"	msr	pmcr_el0, xzr\n"
> +	"	isb\n"
> +	: [i] "+r" (i)
> +	: [pmcr] "r" (pmcr)
> +	: "cc");
> +}
>  #endif
>  
>  /*
> @@ -204,6 +242,71 @@ static bool check_cycles_increase(void)
>  	return success;
>  }
>  
> +/*
> + * Execute a known number of guest instructions. Only odd instruction counts
> + * greater than or equal to 3 are supported by the in-line assembly code. The
> + * control register (PMCR_EL0) is initialized with the provided value (allowing
> + * for example for the cycle counter or event counters to be reset). At the end
> + * of the exact instruction loop, zero is written to PMCR_EL0 to disable
> + * counting, allowing the cycle counter or event counters to be read at the
> + * leisure of the calling code.
> + */
> +static void measure_instrs(int num, uint32_t pmcr)
> +{
> +	int i = (num - 1) / 2;
> +
> +	assert(num >= 3 && ((num - 1) % 2 == 0));
> +	loop(i, pmcr);
> +}
> +
> +/*
> + * Measure cycle counts for various known instruction counts. Ensure that the
> + * cycle counter progresses (similar to check_cycles_increase() but with more
> + * instructions and using reset and stop controls). If supplied a positive,
> + * nonzero CPI parameter, also strictly check that every measurement matches
> + * it. Strict CPI checking is used to test -icount mode.
> + */
> +static bool check_cpi(int cpi)
> +{
> +	uint32_t pmcr = pmcr_read() | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_E;
> +	
> +	if (cpi > 0)
> +		printf("Checking for CPI=%d.\n", cpi);
> +	printf("instrs : cycles0 cycles1 ...\n");
> +
> +	for (unsigned int i = 3; i < 300; i += 32) {
> +		uint64_t avg, sum = 0;
> +
> +		printf("%d :", i);
> +		for (int j = 0; j < NR_SAMPLES; j++) {
> +			uint64_t cycles;
> +
> +			pmccntr_write(0);
> +			measure_instrs(i, pmcr);
> +			cycles = pmccntr_read();
> +			printf(" %"PRId64"", cycles);
> +
> +			/*
> +			 * The cycles taken by the loop above should fit in
> +			 * 32 bits easily. We check the upper 32 bits of the
> +			 * cycle counter to make sure there is no supprise.
> +			 */
> +			if (!cycles || (cpi > 0 && cycles != i * cpi) ||
> +			    (cycles & 0xffffffff00000000)) {

 (cycles >> 32) != 0 would look better.

> +				printf("\n");

We have 3 cases where we return false here. How about doing the tests
separately and adding descriptive print statements for each?

 if (!cycles) {
     printf("\ncycles not incrementing!\n");
     return false;
 } else if (cpi > 0 && cycles != i * cpi) {
     ...
 } else if ((cycles >> 32) != 0) {
     ...
 }

> +				return false;
> +			}
> +
> +			sum += cycles;
> +		}
> +		avg = sum / NR_SAMPLES;
> +		printf(" sum=%"PRId64" avg=%"PRId64" avg_ipc=%"PRId64" "
> +		       "avg_cpi=%"PRId64"\n", sum, avg, i / avg, avg / i);
> +	}
> +
> +	return true;
> +}
> +
>  void pmu_init(void)
>  {
>  	uint32_t dfr0;
> @@ -218,13 +321,19 @@ void pmu_init(void)
>  	pmccfiltr_write(0); /* count cycles in EL0, EL1, but not EL2 */
>  }
>  
> -int main(void)
> +int main(int argc, char *argv[])
>  {
> +	int cpi = 0;
> +
> +	if (argc >= 1)
                  ^ this '=' shouldn't be here
> +		cpi = atol(argv[0]);
                                ^ sigh, this is still zero...

Looks like you forgot all my comments from the last review round...

> +
>  	report_prefix_push("pmu");
>  
>  	pmu_init();
>  	report("Control register", check_pmcr());
>  	report("Monotonically increasing cycle count", check_cycles_increase());
> +	report("Cycle/instruction ratio", check_cpi(cpi));
>  
>  	return report_summary();
>  }
> diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> index 7645180..2050dc8 100644
> --- a/arm/unittests.cfg
> +++ b/arm/unittests.cfg
> @@ -59,3 +59,17 @@ groups = selftest
>  [pmu]
>  file = pmu.flat
>  groups = pmu
> +
> +# Test PMU support (TCG) with -icount IPC=1
> +[pmu-tcg-icount-1]
> +file = pmu.flat
> +extra_params = -icount 0 -append '1'
> +groups = pmu
> +accel = tcg
> +
> +# Test PMU support (TCG) with -icount IPC=256
> +[pmu-tcg-icount-256]
> +file = pmu.flat
> +extra_params = -icount 8 -append '256'
> +groups = pmu
> +accel = tcg
> -- 
> 1.8.3.1
>

drew

^ permalink raw reply

* [PATCH] mfd: twl-core: export twl_get_regmap
From: Russell King - ARM Linux @ 2016-11-21  9:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161121092339.GA32509@dell>

On Mon, Nov 21, 2016 at 09:23:39AM +0000, Lee Jones wrote:
> It's common place to pass shared resources such as 'regmap' though
> device data.  You can find many examples of *__set_drvdata throughout
> the kernel.

Passing data between drivers using *_set_drvdata() is a layering
violation:

1. Driver data is supposed to be driver private data associated with
   the currently bound driver.
2. The driver data pointer is NULL'd when the driver unbinds from the
   device.  See __device_release_driver() and the
   dev_set_drvdata(dev, NULL).
3. It will break with CONFIG_DEBUG_TEST_DRIVER_REMOVE enabled for a
   similar reason to (2).

So, do not pass data between drivers using *_set_drvdata() - any
examples in the kernel already are founded on bad practice, are
fragile, and are already broken for some kernel configurations.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* [GIT PULL] Second Round of Renesas ARM Based SoC Updates for v4.10
From: Geert Uytterhoeven @ 2016-11-21  9:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161119012836.GA2543@localhost>

Hi Olof,

On Sat, Nov 19, 2016 at 2:28 AM, Olof Johansson <olof@lixom.net> wrote:
> On Thu, Nov 17, 2016 at 02:34:25PM +0100, Simon Horman wrote:
>> Please consider these second round of Renesas ARM based SoC updates for v4.10.

>> * Basic support for r8a7745 SoC
>>
>> ----------------------------------------------------------------
>> Sergei Shtylyov (2):
>>       ARM: shmobile: r8a7745: basic SoC support
>>       ARM: shmobile: document SK-RZG1E board
>
> Hi,
>
> Is there a reason you're adding a config option per SoC?
>
> I think you'd be better off not adding these config options, and just adding
> support for the SoCs through compatibles (and adding the drivers to defconfigs,
> etc).

Yes there is a reason: kernel size.
The main offenders are the pinctrl tables, which add ca. 20-50 KiB per
supported SoC.

Note that RZ/A1 (r7s72100) is used on some boards with its internal RAM
(10 MiB) only.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH v2] ARM: Drop fixed 200 Hz timer requirement from Samsung platforms
From: Russell King - ARM Linux @ 2016-11-21  9:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+Ln22GyRwywcxdO4Gp67d8TfpjfNzaE0z25=WW9GWibjGkDuQ@mail.gmail.com>

On Mon, Nov 21, 2016 at 03:01:57PM +0900, Tomasz Figa wrote:
> One thing to correct here is that the typical clock is PCLK, which is
> derived from one of the PLLs and AFAIR is between 33-66 MHz on
> s3c24xx. Technically you can drive the PWM block from an external
> clock (12 MHz for some board-file based boards), but for simplicity
> this functionality was omitted in the new PWM timer driver used for DT
> boards (which worked fine with the PWM driven by PCLK).

So that's a knowingly-made regression for s3c24xx then.  Pretty
disgusting developer behavior to do that, IMHO.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* [PATCH] mfd: twl-core: export twl_get_regmap
From: Lee Jones @ 2016-11-21  9:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKP5S=3quz8f1H0xnaffJ35L8qSOpSkBEGS8GsNhB5F=v3DoBg@mail.gmail.com>

On Sun, 20 Nov 2016, Nicolae Rosia wrote:

> On Fri, Nov 18, 2016 at 8:55 PM, Lee Jones <lee.jones@linaro.org> wrote:
> > On Sat, 12 Nov 2016, Nicolae Rosia wrote:
> >
> >> We want to get rid of global twl_i2c_{write/read}.
> >> As a first step, allow clients to get the regmap and write directly
> >
> > What's stopping you from passing it through device data?
> >
> Could you elaborate a bit?
> The regmaps are stored in struct twl_client [0], stored in struct
> twl_private [1], both structs are defined in the source file, not in
> header.
> I could however just fix the problem by reworking the struct, exposing
> it and use mfd_add_device as real mfd drivers do.

Woah!  Thanks for prompting me to read this driver.  It's a bit of a
mess isn't it?  I think it would be best to convert it to use the MFD
API, yes.

It's common place to pass shared resources such as 'regmap' though
device data.  You can find many examples of *__set_drvdata throughout
the kernel.

> [0] http://lxr.free-electrons.com/source/drivers/mfd/twl-core.c#L152
> [1] http://lxr.free-electrons.com/source/drivers/mfd/twl-core.c#L163

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [PATCH v3 6/9] mtd: spi-nor: Support R/W for S25FS-S family flash
From: Yao Yuan @ 2016-11-21  9:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AM4PR0701MB21302252988A38FE2A393FE4FEB50@AM4PR0701MB2130.eurprd07.prod.outlook.com>

On Thu, Nov 21, 2016 at 03:15 PM +0800, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
> > -----Original Message-----
> > From: Yao Yuan [mailto:yao.yuan at nxp.com]
> > Sent: Monday, November 21, 2016 7:28 AM
> > To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
> > <marcin.krzeminski@nokia.com>; Han Xu <xhnjupt@gmail.com>
> > Cc: David Woodhouse <dwmw2@infradead.org>; linux-
> > kernel at vger.kernel.org; linux-mtd at lists.infradead.org;
> > han.xu at freescale.com; Brian Norris <computersforpeace@gmail.com>;
> > jagannadh.teki at gmail.com; linux-arm-kernel at lists.infradead.org;
> > Cyrille Pitchen <cyrille.pitchen@atmel.com>
> > Subject: RE: [PATCH v3 6/9] mtd: spi-nor: Support R/W for S25FS-S
> > family flash
> >
> > On Thu, Nov 18, 2016 at 07:00 PM +0000, Krzeminski, Marcin (Nokia -
> > PL/Wroclaw) wrote:
> > > > -----Original Message-----
> > > > From: Yao Yuan [mailto:yao.yuan at nxp.com]
> > > > Sent: Friday, November 18, 2016 5:20 AM
> > > > To: Krzeminski, Marcin (Nokia - PL/Wroclaw)
> > > > <marcin.krzeminski@nokia.com>; Han Xu <xhnjupt@gmail.com>
> > > > Cc: David Woodhouse <dwmw2@infradead.org>; linux-
> > > > kernel at vger.kernel.org; linux-mtd at lists.infradead.org;
> > > > han.xu at freescale.com; Brian Norris <computersforpeace@gmail.com>;
> > > > jagannadh.teki at gmail.com; linux-arm-kernel at lists.infradead.org
> > > > Subject: RE: [PATCH v3 6/9] mtd: spi-nor: Support R/W for S25FS-S
> > > > family flash
> > > >
> > > > On Thu, Nov 17, 2016 at 10:14:55AM +0000, Krzeminski, Marcin
> > > > (Nokia
> > > > -
> > > > PL/Wroclaw) wrote:
> > > > > > On Thu, Nov 17, 2016 at 06:50:55AM +0000, Krzeminski, Marcin
> > > > > > (Nokia
> > > > > > -
> > > > > > PL/Wroclaw) wrote:
> > > > > > > > > > On Thu, Aug 18, 2016 at 2:38 AM, Yunhui Cui
> > > > > > > > > > <B56489@freescale.com>
> > > > > > > > > > wrote:
> > > > > > > > > > > From: Yunhui Cui <yunhui.cui@nxp.com>
> > > > > > > > > > >
> > > > > > > > > > > With the physical sectors combination, S25FS-S
> > > > > > > > > > > family flash requires some special operations for
> > > > > > > > > > > read/write
> > functions.
> > > > > > > > > > >
> > > > > > > > > > > Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
> > > > > > > > > > > ---
> > > > > > > > > > >  drivers/mtd/spi-nor/spi-nor.c | 56
> > > > > > > > > > > +++++++++++++++++++++++++++++++++++++++++++
> > > > > > > > > > >  1 file changed, 56 insertions(+)
> > > > > > > > > > >
> > > > > > > > > > > diff --git a/drivers/mtd/spi-nor/spi-nor.c
> > > > > > > > > > > b/drivers/mtd/spi-nor/spi-nor.c index
> > > > > > > > > > > d0fc165..495d0bb
> > > > > > > > > > > 100644
> > > > > > > > > > > --- a/drivers/mtd/spi-nor/spi-nor.c
> > > > > > > > > > > +++ b/drivers/mtd/spi-nor/spi-nor.c
> > > > > > > > > > > @@ -39,6 +39,10 @@
> > > > > > > > > > >
> > > > > > > > > > >  #define SPI_NOR_MAX_ID_LEN     6
> > > > > > > > > > >  #define SPI_NOR_MAX_ADDR_WIDTH 4
> > > > > > > > > > > +/* Added for S25FS-S family flash */
> > > > > > > > > > > +#define SPINOR_CONFIG_REG3_OFFSET      0x800004
> > > > > > > > > > > +#define CR3V_4KB_ERASE_UNABLE  0x8 #define
> > > > > > > > > > > +SPINOR_S25FS_FAMILY_EXT_JEDEC  0x81
> > > > > > > > > > >
> > > > > > > > > > >  struct flash_info {
> > > > > > > > > > >         char            *name;
> > > > > > > > > > > @@ -78,6 +82,7 @@ struct flash_info {  };
> > > > > > > > > > >
> > > > > > > > > > >  #define JEDEC_MFR(info)        ((info)->id[0])
> > > > > > > > > > > +#define EXT_JEDEC(info)        ((info)->id[5])
> > > > > > > > > > >
> > > > > > > > > > >  static const struct flash_info
> > > > > > > > > > > *spi_nor_match_id(const char *name);
> > > > > > > > > > >
> > > > > > > > > > > @@ -899,6 +904,7 @@ static const struct flash_info
> > > > spi_nor_ids[] = {
> > > > > > > > > > >          */
> > > > > > > > > > >         { "s25sl032p",  INFO(0x010215, 0x4d00,  64 *
> > > > > > > > > > > 1024, 64,
> > > > > > > > > > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> > > > > > > > > > >         { "s25sl064p",  INFO(0x010216, 0x4d00,  64 *
> > > > > > > > > > > 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
> > },
> > > > > > > > > > > +       { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64
> > > > > > > > > > > + * 1024, 512, 0)},
> > > > > > > > > > >         { "s25fl256s0", INFO(0x010219, 0x4d00, 256 *
> > > > > > > > > > > 1024, 128,
> > 0) },
> > > > > > > > > > >         { "s25fl256s1", INFO(0x010219, 0x4d01,  64 *
> > > > > > > > > > > 1024, 512,
> > > > > > > > > > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> > > > > > > > > > >         { "s25fl512s",  INFO(0x010220, 0x4d00, 256 *
> > > > > > > > > > > 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
> > },
> > > @@
> > > > > > > > > > > -
> > > > 1036,6
> > > > > > > > +1042,50
> > > > > > > > > > @@ static const struct flash_info
> > > > > > > > > > *spi_nor_read_id(struct spi_nor
> > > > > > > > > > *nor)
> > > > > > > > > > >         return ERR_PTR(-ENODEV);  }
> > > > > > > > > > >
> > > > > > > > > > > +/*
> > > > > > > > > > > + * The S25FS-S family physical sectors may be
> > > > > > > > > > > +configured as a
> > > > > > > > > > > + * hybrid combination of eight 4-kB parameter
> > > > > > > > > > > +sectors
> > > > > > > > > > > + * at the top or bottom of the address space with
> > > > > > > > > > > +all
> > > > > > > > > > > + * but one of the remaining sectors being uniform size.
> > > > > > > > > > > + * The Parameter Sector Erase commands (20h or 21h)
> > > > > > > > > > > +must
> > > > > > > > > > > + * be used to erase the 4-kB parameter sectors individually.
> > > > > > > > > > > + * The Sector (uniform sector) Erase commands (D8h
> > > > > > > > > > > +or
> > > > > > > > > > > +DCh)
> > > > > > > > > > > + * must be used to erase any of the remaining
> > > > > > > > > > > + * sectors, including the portion of highest or
> > > > > > > > > > > +lowest address
> > > > > > > > > > > + * sector that is not overlaid by the parameter sectors.
> > > > > > > > > > > + * The uniform sector erase command has no effect
> > > > > > > > > > > +on parameter
> > > > > > > > > > sectors.
> > > > > > > > > > > + */
> > > > > > > > > > > +static int spansion_s25fs_disable_4kb_erase(struct
> > > > > > > > > > > +spi_nor
> > > > *nor) {
> > > > > > > > > > > +       u32 cr3v_addr  = SPINOR_CONFIG_REG3_OFFSET;
> > > > > > > > > > > +       u8 cr3v = 0x0;
> > > > > > > > > > > +       int ret = 0x0;
> > > > > > > > > > > +
> > > > > > > > > > > +       nor->cmd_buf[2] = cr3v_addr >> 16;
> > > > > > > > > > > +       nor->cmd_buf[1] = cr3v_addr >> 8;
> > > > > > > > > > > +       nor->cmd_buf[0] = cr3v_addr >> 0;
> > > > > > > > > > > +
> > > > > > > > > > > +       ret = nor->read_reg(nor,
> > > > > > > > > > > + SPINOR_OP_SPANSION_RDAR,
> > > > > > &cr3v, 1);
> > > > > > > > > > > +       if (ret)
> > > > > > > > > > > +               return ret;
> > > > > > > > > > > +       if (cr3v & CR3V_4KB_ERASE_UNABLE)
> > > > > > > > > > > +               return 0;
> > > > > > > > > > > +       ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
> > > > > > > > > > > +       if (ret)
> > > > > > > > > > > +               return ret;
> > > > > > > > > > > +       cr3v = CR3V_4KB_ERASE_UNABLE;
> > > > > > > > > > > +       nor->program_opcode =
> > SPINOR_OP_SPANSION_WRAR;
> > > > > > > > > > > +       nor->write(nor, cr3v_addr, 1, &cr3v);
> > > > > > > > > > > +
> > > > > > > > > > > +       ret = nor->read_reg(nor,
> > > > > > > > > > > + SPINOR_OP_SPANSION_RDAR,
> > > > > > &cr3v, 1);
> > > > > > > > > > > +       if (ret)
> > > > > > > > > > > +               return ret;
> > > > > > > > > > > +       if (!(cr3v & CR3V_4KB_ERASE_UNABLE))
> > > > > > > > > > > +               return -EPERM;
> > > > > > > > > > > +
> > > > > > > > > > > +       return 0;
> > > > > > > > > > > +}
> > > > > > > > > > > +
> > > > > > > > > > >  static int spi_nor_read(struct mtd_info *mtd,
> > > > > > > > > > > loff_t from, size_t
> > > > > > len,
> > > > > > > > > > >                         size_t *retlen, u_char *buf)
> > > > > > > > > > > { @@
> > > > > > > > > > > -1361,6
> > > > > > > > > > > +1411,12 @@ int spi_nor_scan(struct spi_nor *nor,
> > > > > > > > > > > +const char *name,
> > > > > > > > > > enum read_mode mode)
> > > > > > > > > > >                 spi_nor_wait_till_ready(nor);
> > > > > > > > > > >         }
> > > > > > > > > > >
> > > > > > > > > > > +       if (EXT_JEDEC(info) ==
> > > > > > > > > > > + SPINOR_S25FS_FAMILY_EXT_JEDEC)
> > > > {
> > > > > > > > > > > +               ret = spansion_s25fs_disable_4kb_erase(nor);
> > > > > > > > > > > +               if (ret)
> > > > > > > > > > > +                       return ret;
> > > > > > > > > > > +       }
> > > > > > > > > > > +
> > > > > > > > > > >         if (!mtd->name)
> > > > > > > > > > >                 mtd->name = dev_name(dev);
> > > > > > > > > > >         mtd->priv = nor;
> > > > > > > > > > > --
> > > > > > > > > > > 2.1.0.27.g96db324
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > Hi Brian, I will ack this change but still feel it's
> > > > > > > > > > kind of hacking
> > code.
> > > > > > > > > >
> > > > > > > > > > Acked-by: Han xu <han.xu@nxp.com>
> > > > > > > > >
> > > > > > > > > I am new on the list so I am not sure if this topic has
> > > > > > > > > been
> > discussed.
> > > > > > > > > Generally our product functionality relay on those 4KiB sectors.
> > > > > > > > > I know that this hack is already in u-boot, but if you
> > > > > > > > > mainstream this you will force users of those 4KiB
> > > > > > > > > sectors to do hack the
> > > > > hack...
> > > > > > > > > I believe the proper solution here is to use erase
> > > > > > > > > regions functionality, I send and RFS about that some time ago.
> > > > > > > >
> > > > > > > > Do you mind to send me a link for reference?
> > > > > > > >
> > > > > > > Han,
> > > > > > >
> > > > > > > Sorry, It seem I have not posted erase region changes (only
> > > > > > > those regarding DUAL/QUAD I/O).
> > > > > > > Generally, in this flash you need to create 3 erase regions
> > > > > > > (because in FS-S family support only  4KiB erase on
> > > > > > > parameters sector -
> > > > eg.
> > > > > > > 1.2.2.4 in
> > > > > > S25FS512S).
> > > > > > > In my case regions are:
> > > > > > > 1. 0-32KiB (8*4KiB) - 4K_ERASE (0x20/0x21) 2. 32 - 256 -
> > > > > > > SE_CMD
> > > > > > (0xd8/0xdc) 3.
> > > > > > > Rest of the flash SE_CMD (0xd8/0xdc)
> > > > > > >
> > > > > > > To erase whole flash you can also use CHIP_ERASE_CMD
> > > > > > > (0x60/0xC7) command, you just need to add one more mtd
> > > > > > > partition that will cover
> > > > > > whole flash.
> > > > > > >
> > > > > >
> > > > > > Hi Krzeminski,
> > > > > >
> > > > > > Do you think is there any great advantages for enable 4KB?
> > > > > > Because for NXP(Freescale) QSPI controller, there is only
> > > > > > support max to 16 groups command.
> > > > > >
> > > > > > So It's hard to give 3 groups command just for erase
> > > > > > (0x21,0xdc and
> > 0xc7).
> > > > > > So we have to disable the 4kb erase and only use 256kbytes in
> > > > > > this
> > patch.
> > > > > >
> > > > > Yes, if you disable parameters sector in spi-nor framework you
> > > > > will disable it for all spi-nor clients not only for NXP QSPI controller.
> > > > > There are users (at least me) that relay on parameters sector
> > functionality.
> > > > This patch will brake it.
> > > > >
> > > > > Thanks,
> > > >
> > > > Hi Krzeminski,
> > > >
> > > > Get it.
> > > > So do you think how about that I add a flag in dts to select it?
> > > > The user want's disable 4kb, he can add the flag.
> > > >
> > > > In spi-nor.c:
> > > > if (of_property_read_bool(np, "spi-nor, disable-4kb")) {
> > > > 	spansion_s25fs_disable_4kb_erase();
> > > > }
> > > >                 else
> > > > ...
> > > >
> > > > In dts:
> > > >
> > > > &qspi {
> > > >         num-cs = <2>;
> > > >         bus-num = <0>;
> > > >         status = "okay";
> > > >
> > > >         qflash0: s25fs512s at 0 {
> > > >                 compatible = "spansion, s25fs512s";
> > > > 	 spi-nor, disable-4kb
> > > >                 #address-cells = <1>;
> > > >                 #size-cells = <1>;
> > > >                 spi-max-frequency = <20000000>;
> > > >                 reg = <0>;
> > > >         };
> > > >
> > > > I think it should be a better way.
> > > >
> > > > How about your think?
> > >
> > > This looks much better - at least for me.
> > > There are some parameters in JESD216 standard regarding parameters
> > > sector, but unfortunately I have not investigated that. You can take
> > > a look at Cyrille series, that adds support for JESD216  standard.
> > >
> >
> > Ok, I will resend v4 for add this.
> >
> > BTW, the 4-kytes block for S25FS is just only the first 8 blocks, the
> > other block is 256kytes.
> > Do out SPI-NOR support erase those specific combination?
> >
> > If not, do you have any plan for add it?
> > It seems I can't fine the support in spi-nor.
> >
> Those erase regions are solution for such flash, current upstream version does
> not have this. My solution is not universal, so probably I will not add it.
> 

Ok, Get it.
We will not use the specific 4kb combination mode for S25FS also.
So I will add the patch to disable 4kb for S25FS. But I will add a flag in dts that
the user can do the choice.

Thanks.

^ permalink raw reply

* [kvm-unit-tests PATCH v9 2/3] arm: pmu: Check cycle count increases
From: Andrew Jones @ 2016-11-21  9:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479528942-21866-3-git-send-email-wei@redhat.com>

On Fri, Nov 18, 2016 at 10:15:41PM -0600, Wei Huang wrote:
> From: Christopher Covington <cov@codeaurora.org>
> 
> Ensure that reads of the PMCCNTR_EL0 are monotonically increasing,
> even for the smallest delta of two subsequent reads.
> 
> Signed-off-by: Christopher Covington <cov@codeaurora.org>
> Signed-off-by: Wei Huang <wei@redhat.com>
> ---
>  arm/pmu.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 156 insertions(+)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index 9d9c53b..fa87de4 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -15,6 +15,9 @@
>  #include "libcflat.h"
>  #include "asm/barrier.h"
>  
> +#define PMU_PMCR_E         (1 << 0)
> +#define PMU_PMCR_C         (1 << 2)
> +#define PMU_PMCR_LC        (1 << 6)
>  #define PMU_PMCR_N_SHIFT   11
>  #define PMU_PMCR_N_MASK    0x1f
>  #define PMU_PMCR_ID_SHIFT  16
> @@ -22,6 +25,14 @@
>  #define PMU_PMCR_IMP_SHIFT 24
>  #define PMU_PMCR_IMP_MASK  0xff
>  
> +#define ID_DFR0_PERFMON_SHIFT 24
> +#define ID_DFR0_PERFMON_MASK  0xf
> +
> +#define PMU_CYCLE_IDX         31
> +
> +#define NR_SAMPLES 10
> +
> +static unsigned int pmu_version;
>  #if defined(__arm__)
>  static inline uint32_t pmcr_read(void)
>  {
> @@ -30,6 +41,69 @@ static inline uint32_t pmcr_read(void)
>  	asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (ret));
>  	return ret;
>  }
> +
> +static inline void pmcr_write(uint32_t value)
> +{
> + 	asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (value));
> +	isb();
> +}
> +
> +static inline void pmselr_write(uint32_t value)
> +{
> +	asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (value));
> +	isb();
> +}
> +
> +static inline void pmxevtyper_write(uint32_t value)
> +{
> +	asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (value));
> +}
> +
> +static inline uint64_t pmccntr_read(void)
> +{
> +	uint32_t lo, hi = 0;
> +
> +	if (pmu_version == 0x3)
> +		asm volatile("mrrc p15, 0, %0, %1, c9" : "=r" (lo), "=r" (hi));
> +	else
> +		asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (lo));

This is fine for this single test, but I was actually thinking we'd
implement both the 32-bit and 64-bit accessors separately, allowing
us to add an additional test that tries both on AArch32 (PMUv3). I.e.

 report_prefix_push("pmccntr");

 report("32-bit read", pmccntr_read() != 0); /* test mrc access */

 if (pmu_version == 0x3) {
     u64 cntr64 = pmccntr_read64(); /* test mrrc access */
     report("64-bit read", (cntr64 >> 32) == 0 && (u32)cntr64 != 0);
 } else {
     report_skip("64-bit read, PMUv3 required");
 }

We can refactor when we add that test later though.

> +
> +	return ((uint64_t)hi << 32) | lo;
> +}
> +
> +static inline void pmccntr_write(uint64_t value)
> +{
> +	uint32_t lo, hi;
> +
> +	lo = value & 0xffffffff;
> +	hi = (value >> 32) & 0xffffffff;
> +
> +	if (pmu_version == 0x3)
> +		asm volatile("mcrr p15, 0, %0, %1, c9" : : "r" (lo), "r" (hi));
> +	else
> +		asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (lo));
> +}
> +
> +static inline void pmcntenset_write(uint32_t value)
> +{
> +	asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (value));
> +}
> +
> +/* PMCCFILTR is an obsolete name for PMXEVTYPER31 in ARMv7 */
> +static inline void pmccfiltr_write(uint32_t value)
> +{
> +	pmselr_write(PMU_CYCLE_IDX);
> +	pmxevtyper_write(value);
> +	isb();
> +}
> +
> +static inline uint32_t id_dfr0_read(void)
> +{
> +	uint32_t val;
> +
> +	asm volatile("mrc p15, 0, %0, c0, c1, 2" : "=r" (val));
> +	return val;
> +}
>  #elif defined(__aarch64__)
>  static inline uint32_t pmcr_read(void)
>  {
> @@ -38,6 +112,44 @@ static inline uint32_t pmcr_read(void)
>  	asm volatile("mrs %0, pmcr_el0" : "=r" (ret));
>  	return ret;
>  }
> +
> +static inline void pmcr_write(uint32_t value)
> +{
> +	asm volatile("msr pmcr_el0, %0" : : "r" (value));
> +	isb();
> +}
> +
> +static inline uint64_t pmccntr_read(void)
> +{
> +	uint64_t cycles;
> +
> +	asm volatile("mrs %0, pmccntr_el0" : "=r" (cycles));
> +	return cycles;
> +}
> +
> +static inline void pmccntr_write(uint64_t value)
> +{
> +	asm volatile("msr pmccntr_el0, %0" : : "r" (value));
> +}
> +
> +static inline void pmcntenset_write(uint32_t value)
> +{
> +	asm volatile("msr pmcntenset_el0, %0" : : "r" (value));
> +}
> +
> +static inline void pmccfiltr_write(uint32_t value)
> +{
> +	asm volatile("msr pmccfiltr_el0, %0" : : "r" (value));
> +	isb();
> +}
> +
> +static inline uint32_t id_dfr0_read(void)
> +{
> +	uint32_t id;
> +
> +	asm volatile("mrs %0, id_dfr0_el1" : "=r" (id));
> +	return id;
> +}
>  #endif
>  
>  /*
> @@ -64,11 +176,55 @@ static bool check_pmcr(void)
>  	return ((pmcr >> PMU_PMCR_IMP_SHIFT) & PMU_PMCR_IMP_MASK) != 0;
>  }
>  
> +/*
> + * Ensure that the cycle counter progresses between back-to-back reads.
> + */
> +static bool check_cycles_increase(void)
> +{
> +	bool success = true;
> +
> +	pmccntr_write(0);
> +	pmcr_write(pmcr_read() | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_E);
> +
> +	for (int i = 0; i < NR_SAMPLES; i++) {
> +		uint64_t a, b;
> +
> +		a = pmccntr_read();
> +		b = pmccntr_read();
> +
> +		if (a >= b) {
> +			printf("Read %"PRId64" then %"PRId64".\n", a, b);
> +			success = false;
> +			break;
> +		}
> +	}
> +
> +	pmcr_write(pmcr_read() & ~PMU_PMCR_E);
> +
> +	return success;
> +}
> +
> +void pmu_init(void)
> +{
> +	uint32_t dfr0;
> +
> +	/* probe pmu version */
> +	dfr0 = id_dfr0_read();
> +	pmu_version = (dfr0 >> ID_DFR0_PERFMON_SHIFT) & ID_DFR0_PERFMON_MASK;
> +	printf("PMU version: %d\n", pmu_version);
> +	
> +	/* init for PMU event access, right now only care about cycle count */
> +	pmcntenset_write(1 << PMU_CYCLE_IDX);
> +	pmccfiltr_write(0); /* count cycles in EL0, EL1, but not EL2 */

These last two register writes are specific to the cycle count test, so
I don't think they belong in a common pmu_init function. I'd keep them
at the top of check_cycles_increase.

> +}
> +
>  int main(void)
>  {
>  	report_prefix_push("pmu");
>  
> +	pmu_init();
>  	report("Control register", check_pmcr());
> +	report("Monotonically increasing cycle count", check_cycles_increase());
>  
>  	return report_summary();
>  }
> -- 
> 1.8.3.1
>

Thanks,
drew 

^ permalink raw reply

* [PATCH v2] ARM: Drop fixed 200 Hz timer requirement from Samsung platforms
From: Russell King - ARM Linux @ 2016-11-21  9:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d67d8100-c8bf-d353-2225-e3b869a1c90d@codethink.co.uk>

On Mon, Nov 21, 2016 at 08:59:06AM +0000, Ben Dooks wrote:
> On 21/11/16 06:01, Tomasz Figa wrote:
> >2016-11-18 17:46 GMT+09:00 Arnd Bergmann <arnd@arndb.de>:
> >>Maybe add a paragraph about the specific problem:
> >>
> >>"On s3c24xx, the PWM counter is only 16 bit wide, and with the
> >>typical 12MHz input clock that overflows every 5.5ms. This works
> >>with HZ=200 or higher but not with HZ=100 which needs a 10ms
> >>interval between ticks. On Later chips (S3C64xx, S5P and EXYNOS),
> >>the counter is 32 bits and does not have this problem.
> >>The new samsung_pwm_timer driver solves the problem by scaling
> >>the input clock by a factor of 50 on s3c24xx, which makes it
> >>less accurate but allows HZ=100 as well as CONFIG_NO_HZ with
> >>fewer wakeups".
> >
> >One thing to correct here is that the typical clock is PCLK, which is
> >derived from one of the PLLs and AFAIR is between 33-66 MHz on
> >s3c24xx. Technically you can drive the PWM block from an external
> >clock (12 MHz for some board-file based boards), but for simplicity
> >this functionality was omitted in the new PWM timer driver used for DT
> >boards (which worked fine with the PWM driven by PCLK).
> 
> Given it was a clock mux option, that would not have been difficult to
> acheive. However these platforms are now so old people don't care, I
> think all my pre-armv7 stuff is now in a box.

However, there are still s3c2410 machines running out there... so we
should do our best not to break them.

> The use of the 12MHz input was to give something to run PWM timers from
> that wasn't interrupted by cpu frequency scaling as PCLK generally is
> half HCLK which is divided down from the core CPU clock.
...
> The original implementation was to go for the best accuracy from the
> timer at the expense of 200 irqs per second instead of the usual 100.

This sounds like a good enough reason not to switch away from using 200Hz
and the 12MHz input.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* [PATCH] mtd: nand: tango: Use nand_to_mtd() instead of directly accessing chip->mtd
From: Boris Brezillon @ 2016-11-21  9:03 UTC (permalink / raw)
  To: linux-arm-kernel

The nand_to_mtd() helper is here to hide internal mtd_info <-> nand_chip
association and ease future refactors.

Make use of this helper instead of directly accessing chip->mtd.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/tango_nand.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
index 7ed35348993e..ec87516b87f5 100644
--- a/drivers/mtd/nand/tango_nand.c
+++ b/drivers/mtd/nand/tango_nand.c
@@ -171,6 +171,7 @@ static void tango_select_chip(struct mtd_info *mtd, int idx)
  */
 static int check_erased_page(struct nand_chip *chip, u8 *buf)
 {
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	u8 *meta = chip->oob_poi + BBM_SIZE;
 	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
 	const int ecc_size = chip->ecc.bytes;
@@ -183,7 +184,7 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf)
 						  meta, meta_len,
 						  chip->ecc.strength);
 		if (res < 0)
-			chip->mtd.ecc_stats.failed++;
+			mtd->ecc_stats.failed++;
 
 		bitflips = max(res, bitflips);
 		buf += pkt_size;
@@ -300,26 +301,30 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
 {
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
 	*pos += len;
 
 	if (!*buf) {
 		/* skip over "len" bytes */
-		chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1);
+		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
 	} else {
-		tango_read_buf(&chip->mtd, *buf, len);
+		tango_read_buf(mtd, *buf, len);
 		*buf += len;
 	}
 }
 
 static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
 {
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
 	*pos += len;
 
 	if (!*buf) {
 		/* skip over "len" bytes */
-		chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1);
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
 	} else {
-		tango_write_buf(&chip->mtd, *buf, len);
+		tango_write_buf(mtd, *buf, len);
 		*buf += len;
 	}
 }
@@ -345,8 +350,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
  */
 static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
 {
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	u8 *oob_orig = oob;
-	const int page_size = chip->mtd.writesize;
+	const int page_size = mtd->writesize;
 	const int ecc_size = chip->ecc.bytes;
 	const int pkt_size = chip->ecc.size;
 	int pos = 0; /* position within physical page */
@@ -371,8 +377,9 @@ static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
 
 static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
 {
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	const u8 *oob_orig = oob;
-	const int page_size = chip->mtd.writesize;
+	const int page_size = mtd->writesize;
 	const int ecc_size = chip->ecc.bytes;
 	const int pkt_size = chip->ecc.size;
 	int pos = 0; /* position within physical page */
@@ -522,7 +529,7 @@ static int chip_init(struct device *dev, struct device_node *np)
 
 	chip = &tchip->nand_chip;
 	ecc = &chip->ecc;
-	mtd = &chip->mtd;
+	mtd = nand_to_mtd(chip);
 
 	chip->read_byte = tango_read_byte;
 	chip->write_buf = tango_write_buf;
@@ -584,7 +591,7 @@ static int tango_nand_remove(struct platform_device *pdev)
 
 	for (cs = 0; cs < MAX_CS; ++cs) {
 		if (nfc->chips[cs])
-			nand_release(&nfc->chips[cs]->nand_chip.mtd);
+			nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
 	}
 
 	return 0;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2] ARM: Drop fixed 200 Hz timer requirement from Samsung platforms
From: Ben Dooks @ 2016-11-21  8:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+Ln22GyRwywcxdO4Gp67d8TfpjfNzaE0z25=WW9GWibjGkDuQ@mail.gmail.com>

On 21/11/16 06:01, Tomasz Figa wrote:
> 2016-11-18 17:46 GMT+09:00 Arnd Bergmann <arnd@arndb.de>:
>> Maybe add a paragraph about the specific problem:
>>
>> "On s3c24xx, the PWM counter is only 16 bit wide, and with the
>> typical 12MHz input clock that overflows every 5.5ms. This works
>> with HZ=200 or higher but not with HZ=100 which needs a 10ms
>> interval between ticks. On Later chips (S3C64xx, S5P and EXYNOS),
>> the counter is 32 bits and does not have this problem.
>> The new samsung_pwm_timer driver solves the problem by scaling
>> the input clock by a factor of 50 on s3c24xx, which makes it
>> less accurate but allows HZ=100 as well as CONFIG_NO_HZ with
>> fewer wakeups".
>
> One thing to correct here is that the typical clock is PCLK, which is
> derived from one of the PLLs and AFAIR is between 33-66 MHz on
> s3c24xx. Technically you can drive the PWM block from an external
> clock (12 MHz for some board-file based boards), but for simplicity
> this functionality was omitted in the new PWM timer driver used for DT
> boards (which worked fine with the PWM driven by PCLK).

Given it was a clock mux option, that would not have been difficult to
acheive. However these platforms are now so old people don't care, I
think all my pre-armv7 stuff is now in a box.

The use of the 12MHz input was to give something to run PWM timers from
that wasn't interrupted by cpu frequency scaling as PCLK generally is
half HCLK which is divided down from the core CPU clock.

(Later devices had multiple PLL sources so you didn't have to have the
  CPU fed from the same clock as the peripherals)

> Also I'm wondering if the divisor we use right now for 16-bit timers
> isn't too small, since it gives us a really short wraparound time,
> which means getting more timer interrupts for longer intervals, kind
> of defeating the benefit of tickless mode. However, AFAICT it doesn't
> affect the HZ problem.

The original implementation was to go for the best accuracy from the
timer at the expense of 200 irqs per second instead of the usual 100.



> Best regards.
> Tomasz
>


-- 
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius

^ permalink raw reply

* [PATCH v3 2/6] iio: adc: Add support for STM32 ADC core
From: Fabrice Gasnier @ 2016-11-21  8:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <09b63f8e-20c8-532e-2d97-2faa6dfe7538@kernel.org>

On 11/19/2016 01:17 PM, Jonathan Cameron wrote:
> On 15/11/16 15:30, Fabrice Gasnier wrote:
>> Add core driver for STMicroelectronics STM32 ADC (Analog to Digital
>> Converter). STM32 ADC can be composed of up to 3 ADCs with shared
>> resources like clock prescaler, common interrupt line and analog
>> reference voltage.
>> This core driver basically manages shared resources.
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> There is nothing in here that demands selecting a fixed regulator.
> I've also switched the select regulator over to depends on inline with
> other drivers in IIO that have a hard dependency on regulators.
> Other than that which showed up during build tests, looks good to me.
> Shout if I've broken anything with this change.

Hi Jonathan, All,

First many thanks.
This is not a big deal. Only thing is: I think patch 4 of this series 
(on stm32_defconfig) need to be updated
to accommodate this change. E.g. :
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y

Shall I send a new version of this series (all patches), including your 
changes, with updated defconfig as well ?
Or only updated patch on defconfig is enough ?

Please advise,
Fabrice
>
> Applied to the togreg branch of iio.git and pushed out as testing for
> the autobuilders to play with it.
>
> Thanks,
>
> Jonathan
>> ---
>>   drivers/iio/adc/Kconfig          |  13 ++
>>   drivers/iio/adc/Makefile         |   1 +
>>   drivers/iio/adc/stm32-adc-core.c | 303 +++++++++++++++++++++++++++++++++++++++
>>   drivers/iio/adc/stm32-adc-core.h |  52 +++++++
>>   4 files changed, 369 insertions(+)
>>   create mode 100644 drivers/iio/adc/stm32-adc-core.c
>>   create mode 100644 drivers/iio/adc/stm32-adc-core.h
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 7edcf32..ff30239 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -419,6 +419,19 @@ config ROCKCHIP_SARADC
>>   	  To compile this driver as a module, choose M here: the
>>   	  module will be called rockchip_saradc.
>>   
>> +config STM32_ADC_CORE
>> +	tristate "STMicroelectronics STM32 adc core"
>> +	depends on ARCH_STM32 || COMPILE_TEST
>> +	depends on OF
>> +	select REGULATOR
>> +	select REGULATOR_FIXED_VOLTAGE
>> +	help
>> +	  Select this option to enable the core driver for STMicroelectronics
>> +	  STM32 analog-to-digital converter (ADC).
>> +
>> +	  This driver can also be built as a module.  If so, the module
>> +	  will be called stm32-adc-core.
>> +
>>   config STX104
>>   	tristate "Apex Embedded Systems STX104 driver"
>>   	depends on X86 && ISA_BUS_API
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 7a40c04..a1e8f44 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -41,6 +41,7 @@ obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
>>   obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
>>   obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
>>   obj-$(CONFIG_STX104) += stx104.o
>> +obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
>>   obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
>>   obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
>>   obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
>> diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
>> new file mode 100644
>> index 0000000..4214b0c
>> --- /dev/null
>> +++ b/drivers/iio/adc/stm32-adc-core.c
>> @@ -0,0 +1,303 @@
>> +/*
>> + * This file is part of STM32 ADC driver
>> + *
>> + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
>> + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
>> + *
>> + * Inspired from: fsl-imx25-tsadc
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/irqdesc.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/slab.h>
>> +
>> +#include "stm32-adc-core.h"
>> +
>> +/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */
>> +#define STM32F4_ADC_CSR			(STM32_ADCX_COMN_OFFSET + 0x00)
>> +#define STM32F4_ADC_CCR			(STM32_ADCX_COMN_OFFSET + 0x04)
>> +
>> +/* STM32F4_ADC_CSR - bit fields */
>> +#define STM32F4_EOC3			BIT(17)
>> +#define STM32F4_EOC2			BIT(9)
>> +#define STM32F4_EOC1			BIT(1)
>> +
>> +/* STM32F4_ADC_CCR - bit fields */
>> +#define STM32F4_ADC_ADCPRE_SHIFT	16
>> +#define STM32F4_ADC_ADCPRE_MASK		GENMASK(17, 16)
>> +
>> +/* STM32 F4 maximum analog clock rate (from datasheet) */
>> +#define STM32F4_ADC_MAX_CLK_RATE	36000000
>> +
>> +/**
>> + * struct stm32_adc_priv - stm32 ADC core private data
>> + * @irq:		irq for ADC block
>> + * @domain:		irq domain reference
>> + * @aclk:		clock reference for the analog circuitry
>> + * @vref:		regulator reference
>> + * @common:		common data for all ADC instances
>> + */
>> +struct stm32_adc_priv {
>> +	int				irq;
>> +	struct irq_domain		*domain;
>> +	struct clk			*aclk;
>> +	struct regulator		*vref;
>> +	struct stm32_adc_common		common;
>> +};
>> +
>> +static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
>> +{
>> +	return container_of(com, struct stm32_adc_priv, common);
>> +}
>> +
>> +/* STM32F4 ADC internal common clock prescaler division ratios */
>> +static int stm32f4_pclk_div[] = {2, 4, 6, 8};
>> +
>> +/**
>> + * stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler
>> + * @priv: stm32 ADC core private data
>> + * Select clock prescaler used for analog conversions, before using ADC.
>> + */
>> +static int stm32f4_adc_clk_sel(struct platform_device *pdev,
>> +			       struct stm32_adc_priv *priv)
>> +{
>> +	unsigned long rate;
>> +	u32 val;
>> +	int i;
>> +
>> +	rate = clk_get_rate(priv->aclk);
>> +	for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) {
>> +		if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE)
>> +			break;
>> +	}
>> +	if (i >= ARRAY_SIZE(stm32f4_pclk_div))
>> +		return -EINVAL;
>> +
>> +	val = readl_relaxed(priv->common.base + STM32F4_ADC_CCR);
>> +	val &= ~STM32F4_ADC_ADCPRE_MASK;
>> +	val |= i << STM32F4_ADC_ADCPRE_SHIFT;
>> +	writel_relaxed(val, priv->common.base + STM32F4_ADC_CCR);
>> +
>> +	dev_dbg(&pdev->dev, "Using analog clock source at %ld kHz\n",
>> +		rate / (stm32f4_pclk_div[i] * 1000));
>> +
>> +	return 0;
>> +}
>> +
>> +/* ADC common interrupt for all instances */
>> +static void stm32_adc_irq_handler(struct irq_desc *desc)
>> +{
>> +	struct stm32_adc_priv *priv = irq_desc_get_handler_data(desc);
>> +	struct irq_chip *chip = irq_desc_get_chip(desc);
>> +	u32 status;
>> +
>> +	chained_irq_enter(chip, desc);
>> +	status = readl_relaxed(priv->common.base + STM32F4_ADC_CSR);
>> +
>> +	if (status & STM32F4_EOC1)
>> +		generic_handle_irq(irq_find_mapping(priv->domain, 0));
>> +
>> +	if (status & STM32F4_EOC2)
>> +		generic_handle_irq(irq_find_mapping(priv->domain, 1));
>> +
>> +	if (status & STM32F4_EOC3)
>> +		generic_handle_irq(irq_find_mapping(priv->domain, 2));
>> +
>> +	chained_irq_exit(chip, desc);
>> +};
>> +
>> +static int stm32_adc_domain_map(struct irq_domain *d, unsigned int irq,
>> +				irq_hw_number_t hwirq)
>> +{
>> +	irq_set_chip_data(irq, d->host_data);
>> +	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_level_irq);
>> +
>> +	return 0;
>> +}
>> +
>> +static void stm32_adc_domain_unmap(struct irq_domain *d, unsigned int irq)
>> +{
>> +	irq_set_chip_and_handler(irq, NULL, NULL);
>> +	irq_set_chip_data(irq, NULL);
>> +}
>> +
>> +static const struct irq_domain_ops stm32_adc_domain_ops = {
>> +	.map = stm32_adc_domain_map,
>> +	.unmap  = stm32_adc_domain_unmap,
>> +	.xlate = irq_domain_xlate_onecell,
>> +};
>> +
>> +static int stm32_adc_irq_probe(struct platform_device *pdev,
>> +			       struct stm32_adc_priv *priv)
>> +{
>> +	struct device_node *np = pdev->dev.of_node;
>> +
>> +	priv->irq = platform_get_irq(pdev, 0);
>> +	if (priv->irq < 0) {
>> +		dev_err(&pdev->dev, "failed to get irq\n");
>> +		return priv->irq;
>> +	}
>> +
>> +	priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0,
>> +					     &stm32_adc_domain_ops,
>> +					     priv);
>> +	if (!priv->domain) {
>> +		dev_err(&pdev->dev, "Failed to add irq domain\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	irq_set_chained_handler(priv->irq, stm32_adc_irq_handler);
>> +	irq_set_handler_data(priv->irq, priv);
>> +
>> +	return 0;
>> +}
>> +
>> +static void stm32_adc_irq_remove(struct platform_device *pdev,
>> +				 struct stm32_adc_priv *priv)
>> +{
>> +	int hwirq;
>> +
>> +	for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++)
>> +		irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
>> +	irq_domain_remove(priv->domain);
>> +	irq_set_chained_handler(priv->irq, NULL);
>> +}
>> +
>> +static int stm32_adc_probe(struct platform_device *pdev)
>> +{
>> +	struct stm32_adc_priv *priv;
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct resource *res;
>> +	int ret;
>> +
>> +	if (!pdev->dev.of_node)
>> +		return -ENODEV;
>> +
>> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	priv->common.base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(priv->common.base))
>> +		return PTR_ERR(priv->common.base);
>> +
>> +	priv->vref = devm_regulator_get(&pdev->dev, "vref");
>> +	if (IS_ERR(priv->vref)) {
>> +		ret = PTR_ERR(priv->vref);
>> +		dev_err(&pdev->dev, "vref get failed, %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_enable(priv->vref);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "vref enable failed\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_get_voltage(priv->vref);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
>> +		goto err_regulator_disable;
>> +	}
>> +	priv->common.vref_mv = ret / 1000;
>> +	dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
>> +
>> +	priv->aclk = devm_clk_get(&pdev->dev, "adc");
>> +	if (IS_ERR(priv->aclk)) {
>> +		ret = PTR_ERR(priv->aclk);
>> +		dev_err(&pdev->dev, "Can't get 'adc' clock\n");
>> +		goto err_regulator_disable;
>> +	}
>> +
>> +	ret = clk_prepare_enable(priv->aclk);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "adc clk enable failed\n");
>> +		goto err_regulator_disable;
>> +	}
>> +
>> +	ret = stm32f4_adc_clk_sel(pdev, priv);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "adc clk selection failed\n");
>> +		goto err_clk_disable;
>> +	}
>> +
>> +	ret = stm32_adc_irq_probe(pdev, priv);
>> +	if (ret < 0)
>> +		goto err_clk_disable;
>> +
>> +	platform_set_drvdata(pdev, &priv->common);
>> +
>> +	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to populate DT children\n");
>> +		goto err_irq_remove;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_irq_remove:
>> +	stm32_adc_irq_remove(pdev, priv);
>> +
>> +err_clk_disable:
>> +	clk_disable_unprepare(priv->aclk);
>> +
>> +err_regulator_disable:
>> +	regulator_disable(priv->vref);
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_adc_remove(struct platform_device *pdev)
>> +{
>> +	struct stm32_adc_common *common = platform_get_drvdata(pdev);
>> +	struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
>> +
>> +	of_platform_depopulate(&pdev->dev);
>> +	stm32_adc_irq_remove(pdev, priv);
>> +	clk_disable_unprepare(priv->aclk);
>> +	regulator_disable(priv->vref);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id stm32_adc_of_match[] = {
>> +	{ .compatible = "st,stm32f4-adc-core" },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
>> +
>> +static struct platform_driver stm32_adc_driver = {
>> +	.probe = stm32_adc_probe,
>> +	.remove = stm32_adc_remove,
>> +	.driver = {
>> +		.name = "stm32-adc-core",
>> +		.of_match_table = stm32_adc_of_match,
>> +	},
>> +};
>> +module_platform_driver(stm32_adc_driver);
>> +
>> +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
>> +MODULE_DESCRIPTION("STMicroelectronics STM32 ADC core driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("platform:stm32-adc-core");
>> diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
>> new file mode 100644
>> index 0000000..081fa5f
>> --- /dev/null
>> +++ b/drivers/iio/adc/stm32-adc-core.h
>> @@ -0,0 +1,52 @@
>> +/*
>> + * This file is part of STM32 ADC driver
>> + *
>> + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
>> + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef __STM32_ADC_H
>> +#define __STM32_ADC_H
>> +
>> +/*
>> + * STM32 - ADC global register map
>> + * ________________________________________________________
>> + * | Offset |                 Register                    |
>> + * --------------------------------------------------------
>> + * | 0x000  |                Master ADC1                  |
>> + * --------------------------------------------------------
>> + * | 0x100  |                Slave ADC2                   |
>> + * --------------------------------------------------------
>> + * | 0x200  |                Slave ADC3                   |
>> + * --------------------------------------------------------
>> + * | 0x300  |         Master & Slave common regs          |
>> + * --------------------------------------------------------
>> + */
>> +#define STM32_ADC_MAX_ADCS		3
>> +#define STM32_ADCX_COMN_OFFSET		0x300
>> +
>> +/**
>> + * struct stm32_adc_common - stm32 ADC driver common data (for all instances)
>> + * @base:		control registers base cpu addr
>> + * @vref_mv:		vref voltage (mv)
>> + */
>> +struct stm32_adc_common {
>> +	void __iomem			*base;
>> +	int				vref_mv;
>> +};
>> +
>> +#endif
>>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox