Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v17 12/15] clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

The patch update arm_arch_timer driver to use the function
provided by the new GTDT driver of ACPI.
By this way, arm_arch_timer.c can be simplified, and separate
all the ACPI GTDT knowledge from this timer driver.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
 drivers/clocksource/arm_arch_timer.c | 47 +++++++++++-------------------------
 1 file changed, 14 insertions(+), 33 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index bcdceca..7f059f9 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1053,58 +1053,36 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
 CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
 		       arch_timer_mem_of_init);
 
-#ifdef CONFIG_ACPI
-static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
-{
-	int trigger, polarity;
-
-	if (!interrupt)
-		return 0;
-
-	trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
-			: ACPI_LEVEL_SENSITIVE;
-
-	polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
-			: ACPI_ACTIVE_HIGH;
-
-	return acpi_register_gsi(NULL, interrupt, trigger, polarity);
-}
-
+#ifdef CONFIG_ACPI_GTDT
 /* Initialize per-processor generic timer */
 static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 {
-	struct acpi_table_gtdt *gtdt;
+	int ret;
 
 	if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
 		pr_warn("already initialized, skipping\n");
 		return -EINVAL;
 	}
 
-	gtdt = container_of(table, struct acpi_table_gtdt, header);
-
 	arch_timers_present |= ARCH_TIMER_TYPE_CP15;
 
-	arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] =
-		map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
-		gtdt->secure_el1_flags);
+	ret = acpi_gtdt_init(table, NULL);
+	if (ret) {
+		pr_err("Failed to init GTDT table.\n");
+		return ret;
+	}
 
 	arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
-		map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
-		gtdt->non_secure_el1_flags);
+		acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI);
 
 	arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
-		map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
-		gtdt->virtual_timer_flags);
+		acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI);
 
 	arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
-		map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
-		gtdt->non_secure_el2_flags);
+		acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI);
 
 	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
 
-	/* Get the frequency from CNTFRQ */
-	arch_timer_detect_rate();
-
 	arch_timer_uses_ppi = arch_timer_select_ppi();
 	if (!arch_timer_ppi[arch_timer_uses_ppi]) {
 		pr_err("No interrupt available, giving up\n");
@@ -1112,7 +1090,10 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 	}
 
 	/* Always-on capability */
-	arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+	arch_timer_c3stop = acpi_gtdt_c3stop(arch_timer_uses_ppi);
+
+	/* Get the frequency from CNTFRQ */
+	arch_timer_detect_rate();
 
 	ret = arch_timer_register();
 	if (ret)
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 11/15] acpi/arm64: Add GTDT table parse driver
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

This patch adds support for parsing arch timer info in GTDT,
provides some kernel APIs to parse all the PPIs and
always-on info in GTDT and export them.

By this driver, we can simplify arm_arch_timer drivers, and
separate the ACPI GTDT knowledge from it.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 arch/arm64/Kconfig          |   1 +
 drivers/acpi/arm64/Kconfig  |   3 +
 drivers/acpi/arm64/Makefile |   1 +
 drivers/acpi/arm64/gtdt.c   | 157 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi.h        |   6 ++
 5 files changed, 168 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 969ef88..4277a21 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2,6 +2,7 @@ config ARM64
 	def_bool y
 	select ACPI_CCA_REQUIRED if ACPI
 	select ACPI_GENERIC_GSI if ACPI
+	select ACPI_GTDT if ACPI
 	select ACPI_REDUCED_HARDWARE_ONLY if ACPI
 	select ACPI_MCFG if ACPI
 	select ACPI_SPCR_TABLE if ACPI
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
index 4616da4..5a6f80f 100644
--- a/drivers/acpi/arm64/Kconfig
+++ b/drivers/acpi/arm64/Kconfig
@@ -4,3 +4,6 @@
 
 config ACPI_IORT
 	bool
+
+config ACPI_GTDT
+	bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 72331f2..1017def 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_ACPI_IORT) 	+= iort.o
+obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
new file mode 100644
index 0000000..d93a790
--- /dev/null
+++ b/drivers/acpi/arm64/gtdt.c
@@ -0,0 +1,157 @@
+/*
+ * ARM Specific GTDT table Support
+ *
+ * Copyright (C) 2016, Linaro Ltd.
+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
+ *         Fu Wei <fu.wei@linaro.org>
+ *         Hanjun Guo <hanjun.guo@linaro.org>
+ *
+ * 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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI GTDT: " fmt
+
+/**
+ * struct acpi_gtdt_descriptor - Store the key info of GTDT for all functions
+ * @gtdt:	The pointer to the struct acpi_table_gtdt of GTDT table.
+ * @gtdt_end:	The pointer to the end of GTDT table.
+ * @platform_timer:	The pointer to the start of Platform Timer Structure
+ *
+ * The struct store the key info of GTDT table, it should be initialized by
+ * acpi_gtdt_init.
+ */
+struct acpi_gtdt_descriptor {
+	struct acpi_table_gtdt *gtdt;
+	void *gtdt_end;
+	void *platform_timer;
+};
+
+static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+
+static int __init map_gt_gsi(u32 interrupt, u32 flags)
+{
+	int trigger, polarity;
+
+	trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
+			: ACPI_LEVEL_SENSITIVE;
+
+	polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
+			: ACPI_ACTIVE_HIGH;
+
+	return acpi_register_gsi(NULL, interrupt, trigger, polarity);
+}
+
+/**
+ * acpi_gtdt_map_ppi() - Map the PPIs of per-cpu arch_timer.
+ * @type:	the type of PPI.
+ *
+ * Note: Linux on arm64 isn't supported on the secure side.
+ * So we only handle the non-secure timer PPIs,
+ * ARCH_TIMER_PHYS_SECURE_PPI is treated as invalid type.
+ *
+ * Return: the mapped PPI value, 0 if error.
+ */
+int __init acpi_gtdt_map_ppi(int type)
+{
+	struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
+
+	switch (type) {
+	case ARCH_TIMER_PHYS_NONSECURE_PPI:
+		return map_gt_gsi(gtdt->non_secure_el1_interrupt,
+				  gtdt->non_secure_el1_flags);
+	case ARCH_TIMER_VIRT_PPI:
+		return map_gt_gsi(gtdt->virtual_timer_interrupt,
+				  gtdt->virtual_timer_flags);
+
+	case ARCH_TIMER_HYP_PPI:
+		return map_gt_gsi(gtdt->non_secure_el2_interrupt,
+				  gtdt->non_secure_el2_flags);
+	default:
+		pr_err("Failed to map timer interrupt: invalid type.\n");
+	}
+
+	return 0;
+}
+
+/**
+ * acpi_gtdt_c3stop() - Got c3stop info from GTDT according to the type of PPI.
+ * @type:	the type of PPI.
+ *
+ * Return: 1 if the timer can be in deep idle state, 0 otherwise.
+ */
+bool __init acpi_gtdt_c3stop(int type)
+{
+	struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
+
+	switch (type) {
+	case ARCH_TIMER_PHYS_NONSECURE_PPI:
+		return !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+
+	case ARCH_TIMER_VIRT_PPI:
+		return !(gtdt->virtual_timer_flags & ACPI_GTDT_ALWAYS_ON);
+
+	case ARCH_TIMER_HYP_PPI:
+		return !(gtdt->non_secure_el2_flags & ACPI_GTDT_ALWAYS_ON);
+
+	default:
+		pr_err("Failed to get c3stop info: invalid type.\n");
+	}
+
+	return 0;
+}
+
+/**
+ * acpi_gtdt_init() - Get the info of GTDT table to prepare for further init.
+ * @table:	The pointer to GTDT table.
+ * @platform_timer_count:	The pointer of int variate for returning the
+ *				number of platform timers. It can be NULL, if
+ *				driver don't need this info.
+ *
+ * Return: 0 if success, -EINVAL if error.
+ */
+int __init acpi_gtdt_init(struct acpi_table_header *table,
+			  int *platform_timer_count)
+{
+	int ret = 0;
+	int timer_count = 0;
+	void *platform_timer = NULL;
+	struct acpi_table_gtdt *gtdt;
+
+	gtdt = container_of(table, struct acpi_table_gtdt, header);
+	acpi_gtdt_desc.gtdt = gtdt;
+	acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
+
+	if (table->revision < 2)
+		pr_debug("Revision:%d doesn't support Platform Timers.\n",
+			 table->revision);
+	else if (!gtdt->platform_timer_count)
+		pr_debug("No Platform Timer.\n");
+	else
+		timer_count = gtdt->platform_timer_count;
+
+	if (timer_count) {
+		platform_timer = (void *)gtdt + gtdt->platform_timer_offset;
+		if (platform_timer < (void *)table +
+				     sizeof(struct acpi_table_gtdt)) {
+			pr_err(FW_BUG "invalid timer data.\n");
+			timer_count = 0;
+			platform_timer = NULL;
+			ret = -EINVAL;
+		}
+	}
+
+	acpi_gtdt_desc.platform_timer = platform_timer;
+	if (platform_timer_count)
+		*platform_timer_count = timer_count;
+
+	return ret;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 61a3d90..d201ce4 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -577,6 +577,12 @@ enum acpi_reconfig_event  {
 int acpi_reconfig_notifier_register(struct notifier_block *nb);
 int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
 
+#ifdef CONFIG_ACPI_GTDT
+int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count);
+int acpi_gtdt_map_ppi(int type);
+bool acpi_gtdt_c3stop(int type);
+#endif
+
 #else	/* !CONFIG_ACPI */
 
 #define acpi_disabled 1
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 10/15] clocksource/drivers/arm_arch_timer: Refactor the timer init code to prepare for GTDT
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

The patch refactor original memory-mapped timer init code:
    (1) Refactor "arch_timer_mem_init", make it become a common code for
        memory-mapped timer init.
    (2) Add a new function "arch_timer_mem_of_init" for DT init.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
 drivers/clocksource/arm_arch_timer.c | 130 ++++++++++++++++++++++++-----------
 1 file changed, 88 insertions(+), 42 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 4549008..bcdceca 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -915,17 +915,17 @@ static int __init arch_timer_of_init(struct device_node *np)
 CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
 CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
 
-static int __init arch_timer_mem_init(struct device_node *np)
+static int __init arch_timer_mem_init(struct arch_timer_mem *timer_mem)
 {
-	struct device_node *frame, *best_frame = NULL;
 	void __iomem *cntctlbase, *base;
-	unsigned int irq, ret = -EINVAL;
+	struct arch_timer_mem_frame *best_frame = NULL;
+	unsigned int irq;
 	u32 cnttidr;
+	int i, ret;
 
-	arch_timers_present |= ARCH_TIMER_TYPE_MEM;
-	cntctlbase = of_iomap(np, 0);
+	cntctlbase = ioremap(timer_mem->cntctlbase, timer_mem->size);
 	if (!cntctlbase) {
-		pr_err("Can't find CNTCTLBase\n");
+		pr_err("Can't map CNTCTLBase.\n");
 		return -ENXIO;
 	}
 
@@ -935,26 +935,18 @@ static int __init arch_timer_mem_init(struct device_node *np)
 	 * Try to find a virtual capable frame. Otherwise fall back to a
 	 * physical capable frame.
 	 */
-	for_each_available_child_of_node(np, frame) {
-		int n;
-		u32 cntacr;
-
-		if (of_property_read_u32(frame, "frame-number", &n)) {
-			pr_err("Missing frame-number\n");
-			of_node_put(frame);
-			goto out;
-		}
+	for (i = 0; i < timer_mem->num_frames; i++) {
+		u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
+			     CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
+		int n = timer_mem->frame[i].frame_nr;
 
 		/* Try enabling everything, and see what sticks */
-		cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
-			 CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
 		writel_relaxed(cntacr, cntctlbase + CNTACR(n));
 		cntacr = readl_relaxed(cntctlbase + CNTACR(n));
 
 		if ((cnttidr & CNTTIDR_VIRT(n)) &&
 		    !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
-			of_node_put(best_frame);
-			best_frame = frame;
+			best_frame = &timer_mem->frame[i];
 			arch_timer_mem_use_virtual = true;
 			break;
 		}
@@ -962,50 +954,104 @@ static int __init arch_timer_mem_init(struct device_node *np)
 		if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
 			continue;
 
-		of_node_put(best_frame);
-		best_frame = of_node_get(frame);
+		best_frame = &timer_mem->frame[i];
 	}
+	iounmap(cntctlbase);
 
-	ret= -ENXIO;
-	base = arch_counter_base = of_iomap(best_frame, 0);
-	if (!base) {
-		pr_err("Can't map frame's registers\n");
-		goto out;
+	if (!best_frame) {
+		pr_err("Can't find frame for register\n");
+		return -EINVAL;
 	}
 
 	if (arch_timer_mem_use_virtual)
-		irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_VIRT_SPI);
+		irq = best_frame->virt_irq;
 	else
-		irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_PHYS_SPI);
+		irq = best_frame->phys_irq;
 
-	ret = -EINVAL;
 	if (!irq) {
 		pr_err("Frame missing %s irq",
 		       arch_timer_mem_use_virtual ? "virt" : "phys");
-		goto out;
+		return -EINVAL;
 	}
 
-	/*
-	 * Try to determine the frequency from the device tree,
-	 * if fail, get the frequency from CNTFRQ.
-	 */
-	if (!arch_timer_rate &&
-	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
-		arch_timer_mem_detect_rate(base);
+	base = ioremap(best_frame->cntbase, best_frame->size);
+	if (!base) {
+		pr_err("Can't map frame's registers\n");
+		return -ENXIO;
+	}
+
+	arch_timer_mem_detect_rate(base);
 
 	ret = arch_timer_mem_register(base, irq);
-	if (ret)
+	if (ret) {
+		iounmap(base);
+		return ret;
+	}
+
+	arch_counter_base = base;
+	arch_timers_present |= ARCH_TIMER_TYPE_MEM;
+
+	return 0;
+}
+
+static int __init arch_timer_mem_of_init(struct device_node *np)
+{
+	struct arch_timer_mem *timer_mem;
+	struct device_node *frame_node;
+	struct resource res;
+	int i, ret = -EINVAL;
+
+	timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL);
+	if (!timer_mem)
+		return -ENOMEM;
+
+	if (of_address_to_resource(np, 0, &res))
 		goto out;
+	timer_mem->cntctlbase = res.start;
+	timer_mem->size = resource_size(&res);
+
+	i = 0;
+	for_each_available_child_of_node(np, frame_node) {
+		int n;
+		struct arch_timer_mem_frame *frame = &timer_mem->frame[i];
+
+		if (of_property_read_u32(frame_node, "frame-number", &n)) {
+			pr_err("Missing frame-number\n");
+			of_node_put(frame_node);
+			goto out;
+		}
+		frame->frame_nr = n;
+
+		if (of_address_to_resource(frame_node, 0, &res)) {
+			of_node_put(frame_node);
+			goto out;
+		}
+		frame->cntbase = res.start;
+		frame->size = resource_size(&res);
+
+		frame->virt_irq = irq_of_parse_and_map(frame_node,
+						       ARCH_TIMER_VIRT_SPI);
+		frame->phys_irq = irq_of_parse_and_map(frame_node,
+						       ARCH_TIMER_PHYS_SPI);
 
-	if (!arch_timer_needs_of_probing())
+		if (++i >= ARCH_TIMER_MEM_MAX_FRAMES)
+			break;
+	}
+	timer_mem->num_frames = i;
+
+	/* Try to determine the frequency from the device tree */
+	if (!arch_timer_rate)
+		of_property_read_u32(np, "clock-frequency", &arch_timer_rate);
+
+	ret = arch_timer_mem_init(timer_mem);
+	if (!ret && !arch_timer_needs_of_probing())
 		ret = arch_timer_common_init();
 out:
-	iounmap(cntctlbase);
-	of_node_put(best_frame);
+	kfree(timer_mem);
 	return ret;
 }
 CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
-		       arch_timer_mem_init);
+		       arch_timer_mem_of_init);
 
 #ifdef CONFIG_ACPI
 static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 09/15] clocksource/drivers/arm_arch_timer: Introduce some new structs to prepare for GTDT
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

The patch introduce two new structs: arch_timer_mem, arch_timer_mem_frame.
And also introduce a new define: ARCH_TIMER_MEM_MAX_FRAMES

These will be used for refactoring the memory-mapped timer init code to
prepare for GTDT

Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
 include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 48376a5..3403247 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -57,6 +57,8 @@ enum arch_timer_spi_nr {
 #define ARCH_TIMER_MEM_PHYS_ACCESS	2
 #define ARCH_TIMER_MEM_VIRT_ACCESS	3
 
+#define ARCH_TIMER_MEM_MAX_FRAMES	8
+
 #define ARCH_TIMER_USR_PCT_ACCESS_EN	(1 << 0) /* physical counter */
 #define ARCH_TIMER_USR_VCT_ACCESS_EN	(1 << 1) /* virtual counter */
 #define ARCH_TIMER_VIRT_EVT_EN		(1 << 2)
@@ -72,6 +74,21 @@ struct arch_timer_kvm_info {
 	int virtual_irq;
 };
 
+struct arch_timer_mem_frame {
+	int frame_nr;
+	phys_addr_t cntbase;
+	size_t size;
+	int phys_irq;
+	int virt_irq;
+};
+
+struct arch_timer_mem {
+	phys_addr_t cntctlbase;
+	size_t size;
+	int num_frames;
+	struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES];
+};
+
 #ifdef CONFIG_ARM_ARCH_TIMER
 
 extern u32 arch_timer_get_rate(void);
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 08/15] clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing into DT init call
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

Because arch_timer_needs_of_probing is only for booting with device-tree,
but arch_timer_common_init is a generic init call which shouldn't include
the FW-specific code. It's better to put arch_timer_needs_of_probing into
DT init function.

But for per-cpu timer, the arch_timer_common_init is called from
arch_timer_init. For reaching the goal above, this patch disassemble
arch_timer_init and use arch_timer_register and arch_timer_common_init
directly, just like arch_timer_mem init code is doing.
By this way, all the DT relevant code are only called from DT init call.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
 drivers/clocksource/arm_arch_timer.c | 45 ++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2c9085a..4549008 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -821,9 +821,6 @@ static bool __init arch_timer_needs_of_probing(void)
 
 static int __init arch_timer_common_init(void)
 {
-	if (acpi_disabled && arch_timer_needs_of_probing())
-		return 0;
-
 	arch_timer_banner(arch_timers_present);
 	arch_counter_register(arch_timers_present);
 	return arch_timer_arch_init();
@@ -861,26 +858,9 @@ static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
 	return ARCH_TIMER_PHYS_SECURE_PPI;
 }
 
-static int __init arch_timer_init(void)
-{
-	int ret;
-
-	ret = arch_timer_register();
-	if (ret)
-		return ret;
-
-	ret = arch_timer_common_init();
-	if (ret)
-		return ret;
-
-	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
-
-	return 0;
-}
-
 static int __init arch_timer_of_init(struct device_node *np)
 {
-	int i;
+	int i, ret;
 
 	if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
 		pr_warn("multiple nodes in dt, skipping\n");
@@ -891,6 +871,8 @@ static int __init arch_timer_of_init(struct device_node *np)
 	for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
 		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
 
+	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
+
 	if (!arch_timer_rate &&
 	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
 		arch_timer_detect_rate();
@@ -921,7 +903,14 @@ static int __init arch_timer_of_init(struct device_node *np)
 		return -EINVAL;
 	}
 
-	return arch_timer_init();
+	ret = arch_timer_register();
+	if (ret)
+		return ret;
+
+	if (arch_timer_needs_of_probing())
+		return 0;
+
+	return arch_timer_common_init();
 }
 CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
 CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
@@ -1008,7 +997,8 @@ static int __init arch_timer_mem_init(struct device_node *np)
 	if (ret)
 		goto out;
 
-	return arch_timer_common_init();
+	if (!arch_timer_needs_of_probing())
+		ret = arch_timer_common_init();
 out:
 	iounmap(cntctlbase);
 	of_node_put(best_frame);
@@ -1064,6 +1054,8 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 		map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
 		gtdt->non_secure_el2_flags);
 
+	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
+
 	/* Get the frequency from CNTFRQ */
 	arch_timer_detect_rate();
 
@@ -1076,8 +1068,11 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 	/* Always-on capability */
 	arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
 
-	arch_timer_init();
-	return 0;
+	ret = arch_timer_register();
+	if (ret)
+		return ret;
+
+	return arch_timer_common_init();
 }
 CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
 #endif
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 07/15] clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

When system init with device-tree, we don't know which node will be
initialized first. And the code in arch_timer_common_init should wait
until per-cpu timer and MMIO timer are both initialized. So we need
arch_timer_needs_probing to detect the init status of system.

But currently the code is dispersed in arch_timer_needs_probing and
arch_timer_common_init. And the function name doesn't specify that
it's only for device-tree. This is somewhat confusing.

This patch move all related code from arch_timer_common_init to
arch_timer_needs_probing, refactor it, and rename it to
arch_timer_needs_of_probing. And make sure that it will be called
only if acpi is disabled.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
 drivers/clocksource/arm_arch_timer.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e554081..2c9085a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -792,15 +792,28 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = {
 	{},
 };
 
-static bool __init
-arch_timer_needs_probing(int type, const struct of_device_id *matches)
+static bool __init arch_timer_needs_of_probing(void)
 {
 	struct device_node *dn;
 	bool needs_probing = false;
+	unsigned int mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
 
-	dn = of_find_matching_node(NULL, matches);
-	if (dn && of_device_is_available(dn) && !(arch_timers_present & type))
+	/* We have two timers, and both device-tree nodes are probed. */
+	if ((arch_timers_present & mask) == mask)
+		return false;
+
+	/*
+	 * Only one type of timer is probed,
+	 * check if we have another type of timer node in device-tree.
+	 */
+	if (arch_timers_present & ARCH_TIMER_TYPE_CP15)
+		dn = of_find_matching_node(NULL, arch_timer_mem_of_match);
+	else
+		dn = of_find_matching_node(NULL, arch_timer_of_match);
+
+	if (dn && of_device_is_available(dn))
 		needs_probing = true;
+
 	of_node_put(dn);
 
 	return needs_probing;
@@ -808,17 +821,8 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
 
 static int __init arch_timer_common_init(void)
 {
-	unsigned mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
-
-	/* Wait until both nodes are probed if we have two timers */
-	if ((arch_timers_present & mask) != mask) {
-		if (arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,
-					     arch_timer_mem_of_match))
-			return 0;
-		if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,
-					     arch_timer_of_match))
-			return 0;
-	}
+	if (acpi_disabled && arch_timer_needs_of_probing())
+		return 0;
 
 	arch_timer_banner(arch_timers_present);
 	arch_counter_register(arch_timers_present);
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 06/15] clocksource/drivers/arm_arch_timer: Rework counter frequency detection.
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

Currently, the counter frequency detection call(arch_timer_detect_rate)
combines all the ways to get counter frequency: device-tree property,
system coprocessor register, MMIO timer. But in the most of use cases,
we don't need all the ways to try:
For example, reading device-tree property will be needed only when
system boot with device-tree, getting frequency from MMIO timer register
will beneeded only when we init MMIO timer.

This patch separates paths to determine frequency:
Separate out device-tree code, keep them in device-tree init function.
Separate out the MMIO frequency and the sysreg frequency detection call,
and use the appropriate one for the counter.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
 drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e43be0a..e554081 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -487,27 +487,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)
 	return 0;
 }
 
-static void
-arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
+static void arch_timer_detect_rate(void)
 {
-	/* Who has more than one independent system counter? */
-	if (arch_timer_rate)
-		return;
+	/*
+	 * Try to get the timer frequency from
+	 * cntfrq_el0(system coprocessor register).
+	 */
+	if (!arch_timer_rate)
+		arch_timer_rate = arch_timer_get_cntfrq();
+
+	/* Check the timer frequency. */
+	if (!arch_timer_rate)
+		pr_warn("frequency not available\n");
+}
 
+static void arch_timer_mem_detect_rate(void __iomem *cntbase)
+{
 	/*
-	 * Try to determine the frequency from the device tree or CNTFRQ,
-	 * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
+	 * Try to determine the frequency from
+	 * CNTFRQ in memory-mapped timer.
 	 */
-	if (!acpi_disabled ||
-	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
-		if (cntbase)
-			arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
-		else
-			arch_timer_rate = arch_timer_get_cntfrq();
-	}
+	if (!arch_timer_rate)
+		arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
 
 	/* Check the timer frequency. */
-	if (arch_timer_rate == 0)
+	if (!arch_timer_rate)
 		pr_warn("frequency not available\n");
 }
 
@@ -883,7 +887,9 @@ static int __init arch_timer_of_init(struct device_node *np)
 	for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
 		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
 
-	arch_timer_detect_rate(NULL, np);
+	if (!arch_timer_rate &&
+	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+		arch_timer_detect_rate();
 
 	arch_timer_c3stop = !of_property_read_bool(np, "always-on");
 
@@ -986,7 +992,14 @@ static int __init arch_timer_mem_init(struct device_node *np)
 		goto out;
 	}
 
-	arch_timer_detect_rate(base, np);
+	/*
+	 * Try to determine the frequency from the device tree,
+	 * if fail, get the frequency from CNTFRQ.
+	 */
+	if (!arch_timer_rate &&
+	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+		arch_timer_mem_detect_rate(base);
+
 	ret = arch_timer_mem_register(base, irq);
 	if (ret)
 		goto out;
@@ -1048,7 +1061,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 		gtdt->non_secure_el2_flags);
 
 	/* Get the frequency from CNTFRQ */
-	arch_timer_detect_rate(NULL, NULL);
+	arch_timer_detect_rate();
 
 	arch_timer_uses_ppi = arch_timer_select_ppi();
 	if (!arch_timer_ppi[arch_timer_uses_ppi]) {
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 05/15] clocksource/drivers/arm_arch_timer: rework PPI determination
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

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 named arch_timer_select_ppi, and then reworks it
so that we can handle having only a non-secure PPI.

This patch also moves arch_timer_ppi verification out to caller,
because we can verify the configuration from device-tree for ARM by this
way.

Meanwhile, because we will select ARCH_TIMER_PHYS_NONSECURE_PPI for ARM64,
the logic in arch_timer_register also need to be updated.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
 drivers/clocksource/arm_arch_timer.c | 77 +++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 31 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 231175b..e43be0a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -699,7 +699,7 @@ static int __init arch_timer_register(void)
 	case ARCH_TIMER_PHYS_NONSECURE_PPI:
 		err = request_percpu_irq(ppi, arch_timer_handler_phys,
 					 "arch_timer", arch_timer_evt);
-		if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) {
+		if (!err && arch_timer_has_nonsecure_ppi()) {
 			ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
 			err = request_percpu_irq(ppi, arch_timer_handler_phys,
 						 "arch_timer", arch_timer_evt);
@@ -821,39 +821,41 @@ static int __init arch_timer_common_init(void)
 	return arch_timer_arch_init();
 }
 
-static int __init arch_timer_init(void)
+/**
+ * arch_timer_select_ppi() - Select suitable PPI for the current system.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * If no interrupt provided for virtual timer, we'll have to
+ * stick to the physical timer. It'd better be accessible...
+ * For arm64 we never use the secure interrupt.
+ *
+ * Return: a suitable PPI type for the current system.
+ */
+static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
 {
-	int ret;
-	/*
-	 * 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 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.
-	 */
-	if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
-		bool has_ppi;
+	if (is_hyp_mode_available() && is_kernel_in_hyp_mode())
+		return ARCH_TIMER_HYP_PPI;
 
-		if (is_kernel_in_hyp_mode()) {
-			arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
-			has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
-		} else {
-			arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
-			has_ppi = (!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] ||
-				   !!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
-		}
+	if (arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
+		return ARCH_TIMER_VIRT_PPI;
 
-		if (!has_ppi) {
-			pr_warn("No interrupt available, giving up\n");
-			return -EINVAL;
-		}
-	}
+	if (IS_ENABLED(CONFIG_ARM64))
+		return ARCH_TIMER_PHYS_NONSECURE_PPI;
+
+	return ARCH_TIMER_PHYS_SECURE_PPI;
+}
+
+static int __init arch_timer_init(void)
+{
+	int ret;
 
 	ret = arch_timer_register();
 	if (ret)
@@ -901,6 +903,13 @@ static int __init arch_timer_of_init(struct device_node *np)
 	if (IS_ENABLED(CONFIG_ARM) &&
 	    of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
 		arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+	else
+		arch_timer_uses_ppi = arch_timer_select_ppi();
+
+	if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+		pr_err("No interrupt available, giving up\n");
+		return -EINVAL;
+	}
 
 	return arch_timer_init();
 }
@@ -1041,6 +1050,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 	/* Get the frequency from CNTFRQ */
 	arch_timer_detect_rate(NULL, NULL);
 
+	arch_timer_uses_ppi = arch_timer_select_ppi();
+	if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+		pr_err("No interrupt available, giving up\n");
+		return -EINVAL;
+	}
+
 	/* Always-on capability */
 	arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 04/15] clocksource/drivers/arm_arch_timer: rename some enums and defines.
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

Rename some enums and defines, to unify the format of enums and defines
in arm_arch_timer.h, also update all the users of these enums and defines:
    drivers/clocksource/arm_arch_timer.c
    virt/kvm/arm/hyp/timer-sr.c

No functional change.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
 drivers/clocksource/arm_arch_timer.c | 111 ++++++++++++++++++-----------------
 include/clocksource/arm_arch_timer.h |  24 ++++----
 virt/kvm/arm/hyp/timer-sr.c          |   6 +-
 3 files changed, 73 insertions(+), 68 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 15341cf..231175b 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -66,11 +66,11 @@ struct arch_timer {
 #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
 
 static u32 arch_timer_rate;
-static int arch_timer_ppi[MAX_TIMER_PPI];
+static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
 
 static struct clock_event_device __percpu *arch_timer_evt;
 
-static enum arch_timer_ppi_nr arch_timer_uses_ppi = VIRT_PPI;
+static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI;
 static bool arch_timer_c3stop;
 static bool arch_timer_mem_use_virtual;
 
@@ -340,7 +340,7 @@ static void fsl_a008585_set_sne(struct clock_event_device *clk)
 	if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
 		return;
 
-	if (arch_timer_uses_ppi == VIRT_PPI)
+	if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
 		clk->set_next_event = fsl_a008585_set_next_event_virt;
 	else
 		clk->set_next_event = fsl_a008585_set_next_event_phys;
@@ -352,7 +352,7 @@ static void __arch_timer_setup(unsigned type,
 {
 	clk->features = CLOCK_EVT_FEAT_ONESHOT;
 
-	if (type == ARCH_CP15_TIMER) {
+	if (type == ARCH_TIMER_TYPE_CP15) {
 		if (arch_timer_c3stop)
 			clk->features |= CLOCK_EVT_FEAT_C3STOP;
 		clk->name = "arch_sys_timer";
@@ -360,14 +360,14 @@ static void __arch_timer_setup(unsigned type,
 		clk->cpumask = cpumask_of(smp_processor_id());
 		clk->irq = arch_timer_ppi[arch_timer_uses_ppi];
 		switch (arch_timer_uses_ppi) {
-		case VIRT_PPI:
+		case ARCH_TIMER_VIRT_PPI:
 			clk->set_state_shutdown = arch_timer_shutdown_virt;
 			clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
 			clk->set_next_event = arch_timer_set_next_event_virt;
 			break;
-		case PHYS_SECURE_PPI:
-		case PHYS_NONSECURE_PPI:
-		case HYP_PPI:
+		case ARCH_TIMER_PHYS_SECURE_PPI:
+		case ARCH_TIMER_PHYS_NONSECURE_PPI:
+		case ARCH_TIMER_HYP_PPI:
 			clk->set_state_shutdown = arch_timer_shutdown_phys;
 			clk->set_state_oneshot_stopped = arch_timer_shutdown_phys;
 			clk->set_next_event = arch_timer_set_next_event_phys;
@@ -447,8 +447,8 @@ static void arch_counter_set_user_access(void)
 
 static bool arch_timer_has_nonsecure_ppi(void)
 {
-	return (arch_timer_uses_ppi == PHYS_SECURE_PPI &&
-		arch_timer_ppi[PHYS_NONSECURE_PPI]);
+	return (arch_timer_uses_ppi == ARCH_TIMER_PHYS_SECURE_PPI &&
+		arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
 }
 
 static u32 check_ppi_trigger(int irq)
@@ -469,14 +469,15 @@ static int arch_timer_starting_cpu(unsigned int cpu)
 	struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);
 	u32 flags;
 
-	__arch_timer_setup(ARCH_CP15_TIMER, clk);
+	__arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk);
 
 	flags = check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]);
 	enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags);
 
 	if (arch_timer_has_nonsecure_ppi()) {
-		flags = check_ppi_trigger(arch_timer_ppi[PHYS_NONSECURE_PPI]);
-		enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], flags);
+		flags = check_ppi_trigger(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
+		enable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],
+				  flags);
 	}
 
 	arch_counter_set_user_access();
@@ -513,16 +514,17 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
 static void arch_timer_banner(unsigned type)
 {
 	pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
-		type & ARCH_CP15_TIMER ? "cp15" : "",
-		type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  " and " : "",
-		type & ARCH_MEM_TIMER ? "mmio" : "",
+		type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "",
+		type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ?
+			" and " : "",
+		type & ARCH_TIMER_TYPE_MEM ? "mmio" : "",
 		(unsigned long)arch_timer_rate / 1000000,
 		(unsigned long)(arch_timer_rate / 10000) % 100,
-		type & ARCH_CP15_TIMER ?
-			(arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
+		type & ARCH_TIMER_TYPE_CP15 ?
+			(arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" :
 			"",
-		type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  "/" : "",
-		type & ARCH_MEM_TIMER ?
+		type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "",
+		type & ARCH_TIMER_TYPE_MEM ?
 			arch_timer_mem_use_virtual ? "virt" : "phys" :
 			"");
 }
@@ -588,8 +590,9 @@ static void __init arch_counter_register(unsigned type)
 	u64 start_count;
 
 	/* Register the CP15 based counter if we have one */
-	if (type & ARCH_CP15_TIMER) {
-		if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI)
+	if (type & ARCH_TIMER_TYPE_CP15) {
+		if (IS_ENABLED(CONFIG_ARM64) ||
+		    arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
 			arch_timer_read_counter = arch_counter_get_cntvct;
 		else
 			arch_timer_read_counter = arch_counter_get_cntpct;
@@ -625,7 +628,7 @@ static void arch_timer_stop(struct clock_event_device *clk)
 
 	disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
 	if (arch_timer_has_nonsecure_ppi())
-		disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
+		disable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
 
 	clk->set_state_shutdown(clk);
 }
@@ -688,24 +691,24 @@ static int __init arch_timer_register(void)
 
 	ppi = arch_timer_ppi[arch_timer_uses_ppi];
 	switch (arch_timer_uses_ppi) {
-	case VIRT_PPI:
+	case ARCH_TIMER_VIRT_PPI:
 		err = request_percpu_irq(ppi, arch_timer_handler_virt,
 					 "arch_timer", arch_timer_evt);
 		break;
-	case PHYS_SECURE_PPI:
-	case PHYS_NONSECURE_PPI:
+	case ARCH_TIMER_PHYS_SECURE_PPI:
+	case ARCH_TIMER_PHYS_NONSECURE_PPI:
 		err = request_percpu_irq(ppi, arch_timer_handler_phys,
 					 "arch_timer", arch_timer_evt);
-		if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
-			ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
+		if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) {
+			ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
 			err = request_percpu_irq(ppi, arch_timer_handler_phys,
 						 "arch_timer", arch_timer_evt);
 			if (err)
-				free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+				free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI],
 						arch_timer_evt);
 		}
 		break;
-	case HYP_PPI:
+	case ARCH_TIMER_HYP_PPI:
 		err = request_percpu_irq(ppi, arch_timer_handler_phys,
 					 "arch_timer", arch_timer_evt);
 		break;
@@ -737,7 +740,7 @@ static int __init arch_timer_register(void)
 out_unreg_notify:
 	free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], arch_timer_evt);
 	if (arch_timer_has_nonsecure_ppi())
-		free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
+		free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],
 				arch_timer_evt);
 
 out_free:
@@ -758,7 +761,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
 
 	t->base = base;
 	t->evt.irq = irq;
-	__arch_timer_setup(ARCH_MEM_TIMER, &t->evt);
+	__arch_timer_setup(ARCH_TIMER_TYPE_MEM, &t->evt);
 
 	if (arch_timer_mem_use_virtual)
 		func = arch_timer_handler_virt_mem;
@@ -801,13 +804,15 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
 
 static int __init arch_timer_common_init(void)
 {
-	unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER;
+	unsigned mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
 
 	/* Wait until both nodes are probed if we have two timers */
 	if ((arch_timers_present & mask) != mask) {
-		if (arch_timer_needs_probing(ARCH_MEM_TIMER, arch_timer_mem_of_match))
+		if (arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,
+					     arch_timer_mem_of_match))
 			return 0;
-		if (arch_timer_needs_probing(ARCH_CP15_TIMER, arch_timer_of_match))
+		if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,
+					     arch_timer_of_match))
 			return 0;
 	}
 
@@ -832,16 +837,16 @@ static int __init arch_timer_init(void)
 	 * their CNTHP_*_EL2 counterparts, and use a different PPI
 	 * number.
 	 */
-	if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
+	if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
 		bool has_ppi;
 
 		if (is_kernel_in_hyp_mode()) {
-			arch_timer_uses_ppi = HYP_PPI;
-			has_ppi = !!arch_timer_ppi[HYP_PPI];
+			arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
+			has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
 		} else {
-			arch_timer_uses_ppi = PHYS_SECURE_PPI;
-			has_ppi = (!!arch_timer_ppi[PHYS_SECURE_PPI] ||
-				   !!arch_timer_ppi[PHYS_NONSECURE_PPI]);
+			arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+			has_ppi = (!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] ||
+				   !!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
 		}
 
 		if (!has_ppi) {
@@ -858,7 +863,7 @@ static int __init arch_timer_init(void)
 	if (ret)
 		return ret;
 
-	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
+	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
 
 	return 0;
 }
@@ -867,13 +872,13 @@ static int __init arch_timer_of_init(struct device_node *np)
 {
 	int i;
 
-	if (arch_timers_present & ARCH_CP15_TIMER) {
+	if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
 		pr_warn("multiple nodes in dt, skipping\n");
 		return 0;
 	}
 
-	arch_timers_present |= ARCH_CP15_TIMER;
-	for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+	arch_timers_present |= ARCH_TIMER_TYPE_CP15;
+	for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
 		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
 
 	arch_timer_detect_rate(NULL, np);
@@ -895,7 +900,7 @@ static int __init arch_timer_of_init(struct device_node *np)
 	 */
 	if (IS_ENABLED(CONFIG_ARM) &&
 	    of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
-		arch_timer_uses_ppi = PHYS_SECURE_PPI;
+		arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
 
 	return arch_timer_init();
 }
@@ -909,7 +914,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
 	unsigned int irq, ret = -EINVAL;
 	u32 cnttidr;
 
-	arch_timers_present |= ARCH_MEM_TIMER;
+	arch_timers_present |= ARCH_TIMER_TYPE_MEM;
 	cntctlbase = of_iomap(np, 0);
 	if (!cntctlbase) {
 		pr_err("Can't find CNTCTLBase\n");
@@ -1008,28 +1013,28 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 {
 	struct acpi_table_gtdt *gtdt;
 
-	if (arch_timers_present & ARCH_CP15_TIMER) {
+	if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
 		pr_warn("already initialized, skipping\n");
 		return -EINVAL;
 	}
 
 	gtdt = container_of(table, struct acpi_table_gtdt, header);
 
-	arch_timers_present |= ARCH_CP15_TIMER;
+	arch_timers_present |= ARCH_TIMER_TYPE_CP15;
 
-	arch_timer_ppi[PHYS_SECURE_PPI] =
+	arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] =
 		map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
 		gtdt->secure_el1_flags);
 
-	arch_timer_ppi[PHYS_NONSECURE_PPI] =
+	arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
 		map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
 		gtdt->non_secure_el1_flags);
 
-	arch_timer_ppi[VIRT_PPI] =
+	arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
 		map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
 		gtdt->virtual_timer_flags);
 
-	arch_timer_ppi[HYP_PPI] =
+	arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
 		map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
 		gtdt->non_secure_el2_flags);
 
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index d23c381..48376a5 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -20,18 +20,18 @@
 #include <linux/timecounter.h>
 #include <linux/types.h>
 
-#define ARCH_CP15_TIMER			BIT(0)
-#define ARCH_MEM_TIMER			BIT(1)
+#define ARCH_TIMER_TYPE_CP15		BIT(0)
+#define ARCH_TIMER_TYPE_MEM		BIT(1)
 
 #define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
 #define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
 #define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
 
-#define CNTHCTL_EL1PCTEN		(1 << 0)
-#define CNTHCTL_EL1PCEN			(1 << 1)
-#define CNTHCTL_EVNTEN			(1 << 2)
-#define CNTHCTL_EVNTDIR			(1 << 3)
-#define CNTHCTL_EVNTI			(0xF << 4)
+#define ARCH_TIMER_CNTHCTL_EL1PCTEN	(1 << 0)
+#define ARCH_TIMER_CNTHCTL_EL1PCEN	(1 << 1)
+#define ARCH_TIMER_CNTHCTL_EVNTEN	(1 << 2)
+#define ARCH_TIMER_CNTHCTL_EVNTDIR	(1 << 3)
+#define ARCH_TIMER_CNTHCTL_EVNTI	(0xF << 4)
 
 enum arch_timer_reg {
 	ARCH_TIMER_REG_CTRL,
@@ -39,11 +39,11 @@ enum arch_timer_reg {
 };
 
 enum arch_timer_ppi_nr {
-	PHYS_SECURE_PPI,
-	PHYS_NONSECURE_PPI,
-	VIRT_PPI,
-	HYP_PPI,
-	MAX_TIMER_PPI
+	ARCH_TIMER_PHYS_SECURE_PPI,
+	ARCH_TIMER_PHYS_NONSECURE_PPI,
+	ARCH_TIMER_VIRT_PPI,
+	ARCH_TIMER_HYP_PPI,
+	ARCH_TIMER_MAX_TIMER_PPI
 };
 
 enum arch_timer_spi_nr {
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index 798866a..695b9d9 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -37,7 +37,7 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
 
 	/* Allow physical timer/counter access for the host */
 	val = read_sysreg(cnthctl_el2);
-	val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+	val |= ARCH_TIMER_CNTHCTL_EL1PCTEN | ARCH_TIMER_CNTHCTL_EL1PCEN;
 	write_sysreg(val, cnthctl_el2);
 
 	/* Clear cntvoff for the host */
@@ -55,8 +55,8 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
 	 * Physical counter access is allowed
 	 */
 	val = read_sysreg(cnthctl_el2);
-	val &= ~CNTHCTL_EL1PCEN;
-	val |= CNTHCTL_EL1PCTEN;
+	val &= ~ARCH_TIMER_CNTHCTL_EL1PCEN;
+	val |= ARCH_TIMER_CNTHCTL_EL1PCTEN;
 	write_sysreg(val, cnthctl_el2);
 
 	if (timer->enabled) {
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 03/15] clocksource/drivers/arm_arch_timer: Improve printk relevant code
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

This patch defines pr_fmt(fmt) for all pr_* functions,
then the pr_* doesn't need to add "arch_timer:" everytime.

According to the suggestion from checkpatch.pl:
(1) delete some Blank Spaces in arch_timer_banner;
(2) delete a redundant Tab in a bland line of arch_timer_init(void)

No functional change.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
 drivers/clocksource/arm_arch_timer.c | 49 ++++++++++++++++++------------------
 1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 63bb532..15341cf 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -32,6 +32,9 @@
 
 #include <clocksource/arm_arch_timer.h>
 
+#undef pr_fmt
+#define pr_fmt(fmt) "arch_timer: " fmt
+
 #define CNTTIDR		0x08
 #define CNTTIDR_VIRT(n)	(BIT(1) << ((n) * 4))
 
@@ -504,22 +507,22 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
 
 	/* Check the timer frequency. */
 	if (arch_timer_rate == 0)
-		pr_warn("Architected timer frequency not available\n");
+		pr_warn("frequency not available\n");
 }
 
 static void arch_timer_banner(unsigned type)
 {
-	pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
-		     type & ARCH_CP15_TIMER ? "cp15" : "",
-		     type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  " and " : "",
-		     type & ARCH_MEM_TIMER ? "mmio" : "",
-		     (unsigned long)arch_timer_rate / 1000000,
-		     (unsigned long)(arch_timer_rate / 10000) % 100,
-		     type & ARCH_CP15_TIMER ?
-		     (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
+	pr_info("%s%s%s timer(s) running@%lu.%02luMHz (%s%s%s).\n",
+		type & ARCH_CP15_TIMER ? "cp15" : "",
+		type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  " and " : "",
+		type & ARCH_MEM_TIMER ? "mmio" : "",
+		(unsigned long)arch_timer_rate / 1000000,
+		(unsigned long)(arch_timer_rate / 10000) % 100,
+		type & ARCH_CP15_TIMER ?
+			(arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
 			"",
-		     type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  "/" : "",
-		     type & ARCH_MEM_TIMER ?
+		type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  "/" : "",
+		type & ARCH_MEM_TIMER ?
 			arch_timer_mem_use_virtual ? "virt" : "phys" :
 			"");
 }
@@ -618,8 +621,7 @@ static void __init arch_counter_register(unsigned type)
 
 static void arch_timer_stop(struct clock_event_device *clk)
 {
-	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
-		 clk->irq, smp_processor_id());
+	pr_debug("disable IRQ%d cpu #%d\n", clk->irq, smp_processor_id());
 
 	disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
 	if (arch_timer_has_nonsecure_ppi())
@@ -712,8 +714,7 @@ static int __init arch_timer_register(void)
 	}
 
 	if (err) {
-		pr_err("arch_timer: can't register interrupt %d (%d)\n",
-		       ppi, err);
+		pr_err("can't register interrupt %d (%d)\n", ppi, err);
 		goto out_free;
 	}
 
@@ -766,7 +767,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
 
 	ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt);
 	if (ret) {
-		pr_err("arch_timer: Failed to request mem timer irq\n");
+		pr_err("Failed to request mem timer irq\n");
 		kfree(t);
 	}
 
@@ -844,7 +845,7 @@ static int __init arch_timer_init(void)
 		}
 
 		if (!has_ppi) {
-			pr_warn("arch_timer: No interrupt available, giving up\n");
+			pr_warn("No interrupt available, giving up\n");
 			return -EINVAL;
 		}
 	}
@@ -858,7 +859,7 @@ static int __init arch_timer_init(void)
 		return ret;
 
 	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
-	
+
 	return 0;
 }
 
@@ -867,7 +868,7 @@ static int __init arch_timer_of_init(struct device_node *np)
 	int i;
 
 	if (arch_timers_present & ARCH_CP15_TIMER) {
-		pr_warn("arch_timer: multiple nodes in dt, skipping\n");
+		pr_warn("multiple nodes in dt, skipping\n");
 		return 0;
 	}
 
@@ -911,7 +912,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
 	arch_timers_present |= ARCH_MEM_TIMER;
 	cntctlbase = of_iomap(np, 0);
 	if (!cntctlbase) {
-		pr_err("arch_timer: Can't find CNTCTLBase\n");
+		pr_err("Can't find CNTCTLBase\n");
 		return -ENXIO;
 	}
 
@@ -926,7 +927,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
 		u32 cntacr;
 
 		if (of_property_read_u32(frame, "frame-number", &n)) {
-			pr_err("arch_timer: Missing frame-number\n");
+			pr_err("Missing frame-number\n");
 			of_node_put(frame);
 			goto out;
 		}
@@ -955,7 +956,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
 	ret= -ENXIO;
 	base = arch_counter_base = of_iomap(best_frame, 0);
 	if (!base) {
-		pr_err("arch_timer: Can't map frame's registers\n");
+		pr_err("Can't map frame's registers\n");
 		goto out;
 	}
 
@@ -966,7 +967,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
 
 	ret = -EINVAL;
 	if (!irq) {
-		pr_err("arch_timer: Frame missing %s irq",
+		pr_err("Frame missing %s irq",
 		       arch_timer_mem_use_virtual ? "virt" : "phys");
 		goto out;
 	}
@@ -1008,7 +1009,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
 	struct acpi_table_gtdt *gtdt;
 
 	if (arch_timers_present & ARCH_CP15_TIMER) {
-		pr_warn("arch_timer: already initialized, skipping\n");
+		pr_warn("already initialized, skipping\n");
 		return -EINVAL;
 	}
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: Gabriele Paoloni @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4675465.4Qhqy6WU4X@wuerfel>

Hi Arnd

Many thanks for your contribution, much appreciated

I have some comments...see inline below 

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: 23 November 2016 23:23
> To: linux-arm-kernel at lists.infradead.org
> Cc: Gabriele Paoloni; mark.rutland at arm.com; catalin.marinas at arm.com;
> linux-pci at vger.kernel.org; liviu.dudau at arm.com; Linuxarm;
> lorenzo.pieralisi at arm.com; xuwei (O); Jason Gunthorpe; T homas
> Petazzoni; linux-serial at vger.kernel.org; benh at kernel.crashing.org;
> devicetree at vger.kernel.org; minyard at acm.org; will.deacon at arm.com; John
> Garry; olof at lixom.net; robh+dt at kernel.org; bhelgaas at go og le.com;
> kantyzc at 163.com; zhichang.yuan02 at gmail.com; linux-
> kernel at vger.kernel.org; Yuanzhichang; zourongrong at gmail.com
> Subject: Re: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on
> Hip06
> 
> On Wednesday, November 23, 2016 6:07:11 PM CET Arnd Bergmann wrote:
> > On Wednesday, November 23, 2016 3:22:33 PM CET Gabriele Paoloni
> wrote:
> > > From: Arnd Bergmann [mailto:arnd at arndb.de]
> > > > On Friday, November 18, 2016 5:03:11 PM CET Gabriele Paoloni
> wrote:
> >
> > Please don't proliferate the use of
> > pci_pio_to_address/pci_address_to_pio here, computing the physical
> > address from the logical address is trivial, you just need to
> > subtract the start of the range that you already use when matching
> > the port number range.
> >
> > The only thing we need here is to make of_address_to_resource()
> > return the correct logical port number that was registered for
> > a given host device when asked to translate an address that
> > does not have a CPU address associated with it.
> 
> Ok, I admit this was a little harder than I expected, but see below
> for a rough outline of how I think it can be done.
> 
> This makes it possible to translate bus specific I/O port numbers
> from device nodes into Linux port numbers, and gives a way to register
> them. We could take this further and completely remove
> pci_pio_to_address
> and pci_address_to_pio if we make the I/O port translation always
> go through the io_range list, looking up up the hostbridge by fwnode,
> but we don't have to do that now.
> 
> The patch is completely untested and probably buggy, it just seemed
> easier to put out a prototype than to keep going in circles with the
> discussion.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> 
> diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
> index bf601d4df8cf..6cadf0501bb0 100644
> --- a/drivers/acpi/pci_root.c
> +++ b/drivers/acpi/pci_root.c
> @@ -730,7 +730,8 @@ static void acpi_pci_root_validate_resources(struct
> device *dev,
>  	}
>  }
> 
> -static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
> +static void acpi_pci_root_remap_iospace(struct fwnode_handle *node,
> +					struct resource_entry *entry)
>  {
>  #ifdef PCI_IOBASE
>  	struct resource *res = entry->res;
> @@ -739,11 +740,7 @@ static void acpi_pci_root_remap_iospace(struct
> resource_entry *entry)
>  	resource_size_t length = resource_size(res);
>  	unsigned long port;
> 
> -	if (pci_register_io_range(cpu_addr, length))
> -		goto err;
> -
> -	port = pci_address_to_pio(cpu_addr);
> -	if (port == (unsigned long)-1)
> +	if (pci_register_io_range(node, cpu_addr, length, &port))
>  		goto err;
> 
>  	res->start = port;
> @@ -781,7 +778,8 @@ int acpi_pci_probe_root_resources(struct
> acpi_pci_root_info *info)
>  	else {
>  		resource_list_for_each_entry_safe(entry, tmp, list) {
>  			if (entry->res->flags & IORESOURCE_IO)
> -				acpi_pci_root_remap_iospace(entry);
> +				acpi_pci_root_remap_iospace(&device->fwnode,
> +							    entry);
> 
>  			if (entry->res->flags & IORESOURCE_DISABLED)
>  				resource_list_destroy_entry(entry);
> diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
> index a50025a3777f..df96955a43f8 100644
> --- a/drivers/block/nbd.c
> +++ b/drivers/block/nbd.c
> @@ -760,8 +760,10 @@ static int __nbd_ioctl(struct block_device *bdev,
> struct nbd_device *nbd,
>  		set_bit(NBD_RUNNING, &nbd->runtime_flags);
>  		blk_mq_update_nr_hw_queues(&nbd->tag_set, nbd-
> >num_connections);
>  		args = kcalloc(num_connections, sizeof(*args), GFP_KERNEL);
> -		if (!args)
> +		if (!args) {
> +			error = -ENOMEM;
>  			goto out_err;
> +		}
>  		nbd->task_recv = current;
>  		mutex_unlock(&nbd->config_lock);
> 
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 02b2903fe9d2..5decaba96eed 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -2,6 +2,7 @@
>  #define pr_fmt(fmt)	"OF: " fmt
> 
>  #include <linux/device.h>
> +#include <linux/fwnode.h>
>  #include <linux/io.h>
>  #include <linux/ioport.h>
>  #include <linux/module.h>
> @@ -323,14 +324,9 @@ int of_pci_range_to_resource(struct of_pci_range
> *range,
> 
>  	if (res->flags & IORESOURCE_IO) {
>  		unsigned long port;
> -		err = pci_register_io_range(range->cpu_addr, range->size);
> +		err = pci_register_io_range(&np->fwnode, range->cpu_addr,
> range->size, &port);
>  		if (err)
>  			goto invalid_range;
> -		port = pci_address_to_pio(range->cpu_addr);
> -		if (port == (unsigned long)-1) {
> -			err = -EINVAL;
> -			goto invalid_range;
> -		}
>  		res->start = port;
>  	} else {
>  		if ((sizeof(resource_size_t) < 8) &&
> @@ -479,7 +475,7 @@ static int of_empty_ranges_quirk(struct device_node
> *np)
>  	return false;
>  }
> 
> -static int of_translate_one(struct device_node *parent, struct of_bus
> *bus,
> +static u64 of_translate_one(struct device_node *parent, struct of_bus
> *bus,
>  			    struct of_bus *pbus, __be32 *addr,
>  			    int na, int ns, int pna, const char *rprop)
>  {
> @@ -507,7 +503,7 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
>  	ranges = of_get_property(parent, rprop, &rlen);
>  	if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
>  		pr_debug("no ranges; cannot translate\n");
> -		return 1;
> +		return OF_BAD_ADDR;
>  	}
>  	if (ranges == NULL || rlen == 0) {
>  		offset = of_read_number(addr, na);
> @@ -528,7 +524,7 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
>  	}
>  	if (offset == OF_BAD_ADDR) {
>  		pr_debug("not found !\n");
> -		return 1;
> +		return offset;
>  	}
>  	memcpy(addr, ranges + na, 4 * pna);
> 
> @@ -537,7 +533,10 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
>  	pr_debug("with offset: %llx\n", (unsigned long long)offset);
> 
>  	/* Translate it into parent bus space */
> -	return pbus->translate(addr, offset, pna);
> +	if (pbus->translate(addr, offset, pna))
> +		return OF_BAD_ADDR;
> +
> +	return offset;
>  }
> 
>  /*
> @@ -549,9 +548,14 @@ static int of_translate_one(struct device_node
> *parent, struct of_bus *bus,
>   * that translation is impossible (that is we are not dealing with a
> value
>   * that can be mapped to a cpu physical address). This is not really
> specified
>   * that way, but this is traditionally the way IBM at least do things
> + *
> + * Whenever the translation fails, the *host pointer will be set to
> the
> + * device that lacks a tranlation, and the return code is relative to
> + * that node.

This seems to be wrong to me. We are abusing of the error conditions.
So effectively if there is a buggy DT for an IO resource we end up
assuming that we are using a special IO device with unmapped addresses.

The patch at the bottom apply on top of this one and I think is a more
reasonable approach


>   */
>  static u64 __of_translate_address(struct device_node *dev,
> -				  const __be32 *in_addr, const char *rprop)
> +				  const __be32 *in_addr, const char *rprop,
> +				  struct device_node **host)
>  {
>  	struct device_node *parent = NULL;
>  	struct of_bus *bus, *pbus;
> @@ -564,6 +568,7 @@ static u64 __of_translate_address(struct
> device_node *dev,
>  	/* Increase refcount at current level */
>  	of_node_get(dev);
> 
> +	*host = NULL;
>  	/* Get parent & match bus type */
>  	parent = of_get_parent(dev);
>  	if (parent == NULL)
> @@ -600,8 +605,9 @@ static u64 __of_translate_address(struct
> device_node *dev,
>  		pbus = of_match_bus(parent);
>  		pbus->count_cells(dev, &pna, &pns);
>  		if (!OF_CHECK_COUNTS(pna, pns)) {
> -			pr_err("Bad cell count for %s\n",
> -			       of_node_full_name(dev));
> +			pr_debug("Bad cell count for %s\n",
> +				 of_node_full_name(dev));
> +			*host = of_node_get(parent);
>  			break;
>  		}
> 
> @@ -609,7 +615,9 @@ static u64 __of_translate_address(struct
> device_node *dev,
>  		    pbus->name, pna, pns, of_node_full_name(parent));
> 
>  		/* Apply bus translation */
> -		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna,
> rprop))
> +		result = of_translate_one(dev, bus, pbus, addr, na, ns,
> +					  pna, rprop);
> +		if (result == OF_BAD_ADDR)

It seems to me that here you missed "*host = of_node_get(parent);"..?

>  			break;
> 
>  		/* Complete the move up one level */
> @@ -628,13 +636,32 @@ static u64 __of_translate_address(struct
> device_node *dev,
> 
>  u64 of_translate_address(struct device_node *dev, const __be32
> *in_addr)
>  {
> -	return __of_translate_address(dev, in_addr, "ranges");
> +	struct device_node *host;
> +	u64 ret;
> +
> +	ret =  __of_translate_address(dev, in_addr, "ranges", &host);
> +	if (host) {
> +		of_node_put(host);
> +		return OF_BAD_ADDR;
> +	}
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(of_translate_address);
> 
>  u64 of_translate_dma_address(struct device_node *dev, const __be32
> *in_addr)
>  {
> -	return __of_translate_address(dev, in_addr, "dma-ranges");
> +	struct device_node *host;
> +	u64 ret;
> +
> +	ret = __of_translate_address(dev, in_addr, "dma-ranges", &host);
> +
> +	if (host) {
> +		of_node_put(host);
> +		return OF_BAD_ADDR;
> +	}
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(of_translate_dma_address);
> 
> @@ -676,29 +703,48 @@ const __be32 *of_get_address(struct device_node
> *dev, int index, u64 *size,
>  }
>  EXPORT_SYMBOL(of_get_address);
> 
> +extern unsigned long extio_translate(struct fwnode_handle *node,
> unsigned long offset);
> +
> +u64 of_translate_ioport(struct device_node *dev, const __be32
> *in_addr)
> +{
> +	u64 taddr;
> +	unsigned long port;
> +	struct device_node *host;
> +
> +	taddr = __of_translate_address(dev, in_addr, "ranges", &host);
> +	if (host) {
> +		/* host specific port access */
> +		port = extio_translate(&host->fwnode, taddr);
> +		of_node_put(host);
> +	} else {
> +		/* memory mapped I/O range */
> +		port = pci_address_to_pio(taddr);
> +		if (port == (unsigned long)-1)
> +			return OF_BAD_ADDR;
> +	}
> +
> +	return port;
> +}
> +
>  static int __of_address_to_resource(struct device_node *dev,
>  		const __be32 *addrp, u64 size, unsigned int flags,
>  		const char *name, struct resource *r)
>  {
>  	u64 taddr;
> 
> -	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
> +	if (flags & IORESOURCE_MEM)
> +		taddr = of_translate_address(dev, addrp);
> +	else if (flags & IORESOURCE_IO)
> +		taddr = of_translate_ioport(dev, addrp);
> +	else
>  		return -EINVAL;
> -	taddr = of_translate_address(dev, addrp);
> +
>  	if (taddr == OF_BAD_ADDR)
>  		return -EINVAL;
>  	memset(r, 0, sizeof(struct resource));
> -	if (flags & IORESOURCE_IO) {
> -		unsigned long port;
> -		port = pci_address_to_pio(taddr);
> -		if (port == (unsigned long)-1)
> -			return -EINVAL;
> -		r->start = port;
> -		r->end = port + size - 1;
> -	} else {
> -		r->start = taddr;
> -		r->end = taddr + size - 1;
> -	}
> +
> +	r->start = taddr;
> +	r->end = taddr + size - 1;
>  	r->flags = flags;
>  	r->name = name ? name : dev->full_name;
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index eda6a7cf0e54..320ab9fbf6af 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3249,6 +3249,7 @@ EXPORT_SYMBOL(pci_request_regions_exclusive);
>  #ifdef PCI_IOBASE
>  struct io_range {
>  	struct list_head list;
> +	struct fwnode_handle *node;
>  	phys_addr_t start;
>  	resource_size_t size;
>  };
> @@ -3257,11 +3258,14 @@ static LIST_HEAD(io_range_list);
>  static DEFINE_SPINLOCK(io_range_lock);
>  #endif
> 
> +#define IO_RANGE_IOEXT (resource_size_t)(-1ull)
> +
>  /*
>   * Record the PCI IO range (expressed as CPU physical address + size).
>   * Return a negative value if an error has occured, zero otherwise
>   */
> -int __weak pci_register_io_range(phys_addr_t addr, resource_size_t
> size)
> +int __weak pci_register_io_range(struct fwnode_handle *node,
> phys_addr_t addr,
> +				 resource_size_t size, unsigned long *port)
>  {
>  	int err = 0;
> 
> @@ -3272,7 +3276,12 @@ int __weak pci_register_io_range(phys_addr_t
> addr, resource_size_t size)
>  	/* check if the range hasn't been previously recorded */
>  	spin_lock(&io_range_lock);
>  	list_for_each_entry(range, &io_range_list, list) {
> -		if (addr >= range->start && addr + size <= range->start +
> size) {
> +		if (node == range->node)
> +			goto end_register;
> +

It seems to me that the condition above is sufficient; i.e.
we can remove the one here below...?

> +		if (addr != IO_RANGE_IOEXT &&
> +		    addr >= range->start &&
> +		    addr + size <= range->start + size) {
>  			/* range already registered, bail out */
>  			goto end_register;
>  		}
> @@ -3298,6 +3307,7 @@ int __weak pci_register_io_range(phys_addr_t
> addr, resource_size_t size)
>  		goto end_register;
>  	}
> 
> +	range->node = node;
>  	range->start = addr;
>  	range->size = size;
> 
> @@ -3305,11 +3315,26 @@ int __weak pci_register_io_range(phys_addr_t
> addr, resource_size_t size)
> 
>  end_register:
>  	spin_unlock(&io_range_lock);
> +
> +	*port = allocated_size;
> +#else
> +	/*
> +	 * powerpc and microblaze have their own registration,
> +	 * just look up the value here
> +	 */
> +	*port = pci_address_to_pio(addr);
>  #endif
> 
>  	return err;
>  }
> 
> +#ifdef CONFIG_IOEXT
> +int ioext_register_io_range
> +{
> +	return pci_register_io_range(node, IO_RANGE_IOEXT, size, port);
> +}
> +#endif
> +
>  phys_addr_t pci_pio_to_address(unsigned long pio)
>  {
>  	phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 6bd94a803e8f..b7a8fa3da3ca 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1192,7 +1192,8 @@ int __must_check pci_bus_alloc_resource(struct
> pci_bus *bus,
>  			void *alignf_data);
> 
> 
> -int pci_register_io_range(phys_addr_t addr, resource_size_t size);
> +int pci_register_io_range(struct fwnode_handle *node, phys_addr_t
> addr,
> +			  resource_size_t size, unsigned long *port);
>  unsigned long pci_address_to_pio(phys_addr_t addr);
>  phys_addr_t pci_pio_to_address(unsigned long pio);
>  int pci_remap_iospace(const struct resource *res, phys_addr_t
> phys_addr);

I think the patch below is a more reasonable approach to identify
a host that does not support address translation and it should 
guarantee safety against broken DTs...

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 5decaba..9bfc526 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -540,6 +540,49 @@ static u64 of_translate_one(struct device_node *parent, struct of_bus *bus,
 }
 

Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>

 /*
+ * of_isa_indirect_io - get the IO address from some isa reg property value.
+ *	For some isa/lpc devices, no ranges property in ancestor node.
+ *	The device addresses are described directly in their regs property.
+ *	This fixup function will be called to get the IO address of isa/lpc
+ *	devices when the normal of_translation failed.
+ *
+ * @parent:	points to the parent dts node;
+ * @bus:		points to the of_bus which can be used to parse address;
+ * @addr:	the address from reg property;
+ * @na:		the address cell counter of @addr;
+ * @presult:	store the address paresed from @addr;
+ *
+ * return 1 when successfully get the I/O address;
+ * 0 will return for some failures.
+ */
+static int of_get_isa_indirect_io(struct device_node *parent,
+				struct of_bus *bus, __be32 *addr,
+				int na, u64 *presult)
+{
+	unsigned int flags;
+	unsigned int rlen;
+
+	/* whether support indirectIO */
+	if (!indirect_io_enabled())
+		return 0;
+
+	if (!of_bus_isa_match(parent))
+		return 0;
+
+	flags = bus->get_flags(addr);
+	if (!(flags & IORESOURCE_IO))
+		return 0;
+
+	/* there is ranges property, apply the normal translation directly. */
+	if (of_get_property(parent, "ranges", &rlen))
+		return 0;
+
+	*presult = of_read_number(addr + 1, na - 1);
+	/* this fixup is only valid for specific I/O range. */
+	return addr_is_indirect_io(*presult);
+}
+
+/*
  * Translate an address from the device-tree into a CPU physical address,
  * this walks up the tree and applies the various bus mappings on the
  * way.
@@ -600,14 +643,23 @@ static u64 __of_translate_address(struct device_node *dev,
 			result = of_read_number(addr, na);
 			break;
 		}
+		/*
+		 * For indirectIO device which has no ranges property, get
+		 * the address from reg directly.
+		 */
+		if (of_get_isa_indirect_io(dev, bus, addr, na, &result)) {
+			pr_debug("isa indirectIO matched(%s)..addr = 0x%llx\n",
+				of_node_full_name(dev), result);
+			*host = of_node_get(parent);
+			break;
+		}
 
 		/* Get new parent bus and counts */
 		pbus = of_match_bus(parent);
 		pbus->count_cells(dev, &pna, &pns);
 		if (!OF_CHECK_COUNTS(pna, pns)) {
-			pr_debug("Bad cell count for %s\n",
+			pr_err("Bad cell count for %s\n",
 				 of_node_full_name(dev));
-			*host = of_node_get(parent);
 			break;
 		}
 
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3786473..14848d8 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -24,6 +24,23 @@ struct of_pci_range {
 #define for_each_of_pci_range(parser, range) \
 	for (; of_pci_range_parser_one(parser, range);)
 
+#ifndef indirect_io_enabled
+#define indirect_io_enabled indirect_io_enabled
+static inline bool indirect_io_enabled(void)
+{
+	return false;
+}
+#endif
+
+#ifndef addr_is_indirect_io
+#define addr_is_indirect_io addr_is_indirect_io
+static inline int addr_is_indirect_io(u64 taddr)
+{
+	return 0;
+}
+#endif
+
+
 /* Translate a DMA address from device space to CPU space */
 extern u64 of_translate_dma_address(struct device_node *dev,
 				    const __be32 *in_addr);
-- 
2.7.4

^ permalink raw reply related

* [PATCH v17 02/15] clocksource/drivers/arm_arch_timer: Add a new enum for spi type
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

This patch add a new enum "arch_timer_spi_nr" and use it in the driver.
Just for code's readability, no functional change.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
---
 drivers/clocksource/arm_arch_timer.c | 4 ++--
 include/clocksource/arm_arch_timer.h | 6 ++++++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 21068be..63bb532 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -960,9 +960,9 @@ static int __init arch_timer_mem_init(struct device_node *np)
 	}
 
 	if (arch_timer_mem_use_virtual)
-		irq = irq_of_parse_and_map(best_frame, 1);
+		irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_VIRT_SPI);
 	else
-		irq = irq_of_parse_and_map(best_frame, 0);
+		irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_PHYS_SPI);
 
 	ret = -EINVAL;
 	if (!irq) {
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 557f869..d23c381 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -46,6 +46,12 @@ enum arch_timer_ppi_nr {
 	MAX_TIMER_PPI
 };
 
+enum arch_timer_spi_nr {
+	ARCH_TIMER_PHYS_SPI,
+	ARCH_TIMER_VIRT_SPI,
+	ARCH_TIMER_MAX_TIMER_SPI
+};
+
 #define ARCH_TIMER_PHYS_ACCESS		0
 #define ARCH_TIMER_VIRT_ACCESS		1
 #define ARCH_TIMER_MEM_PHYS_ACCESS	2
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 01/15] clocksource/drivers/arm_arch_timer: Move enums and defines to header file
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125084623.22515-1-fu.wei@linaro.org>

From: Fu Wei <fu.wei@linaro.org>

To support the arm_arch_timer via ACPI we need to share defines and enums
between the driver and the ACPI parser code.

Split out the relevant defines and enums into arm_arch_timer.h, and
change "enum ppi_nr" to "enum arch_timer_ppi_nr" to avoid the potential
name clashes.
Also switch "enum ppi_nr" to "enum arch_timer_ppi_nr" in
arm_arch_timer.c.
No functional change.

Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
 drivers/clocksource/arm_arch_timer.c | 13 +------------
 include/clocksource/arm_arch_timer.h | 12 ++++++++++++
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 73c487d..21068be 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -51,8 +51,6 @@
 #define CNTV_TVAL	0x38
 #define CNTV_CTL	0x3c
 
-#define ARCH_CP15_TIMER	BIT(0)
-#define ARCH_MEM_TIMER	BIT(1)
 static unsigned arch_timers_present __initdata;
 
 static void __iomem *arch_counter_base;
@@ -65,20 +63,11 @@ struct arch_timer {
 #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
 
 static u32 arch_timer_rate;
-
-enum ppi_nr {
-	PHYS_SECURE_PPI,
-	PHYS_NONSECURE_PPI,
-	VIRT_PPI,
-	HYP_PPI,
-	MAX_TIMER_PPI
-};
-
 static int arch_timer_ppi[MAX_TIMER_PPI];
 
 static struct clock_event_device __percpu *arch_timer_evt;
 
-static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI;
+static enum arch_timer_ppi_nr arch_timer_uses_ppi = VIRT_PPI;
 static bool arch_timer_c3stop;
 static bool arch_timer_mem_use_virtual;
 
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index caedb74..557f869 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -16,9 +16,13 @@
 #ifndef __CLKSOURCE_ARM_ARCH_TIMER_H
 #define __CLKSOURCE_ARM_ARCH_TIMER_H
 
+#include <linux/bitops.h>
 #include <linux/timecounter.h>
 #include <linux/types.h>
 
+#define ARCH_CP15_TIMER			BIT(0)
+#define ARCH_MEM_TIMER			BIT(1)
+
 #define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
 #define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
 #define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
@@ -34,6 +38,14 @@ enum arch_timer_reg {
 	ARCH_TIMER_REG_TVAL,
 };
 
+enum arch_timer_ppi_nr {
+	PHYS_SECURE_PPI,
+	PHYS_NONSECURE_PPI,
+	VIRT_PPI,
+	HYP_PPI,
+	MAX_TIMER_PPI
+};
+
 #define ARCH_TIMER_PHYS_ACCESS		0
 #define ARCH_TIMER_VIRT_ACCESS		1
 #define ARCH_TIMER_MEM_PHYS_ACCESS	2
-- 
2.9.3

^ permalink raw reply related

* [PATCH v17 00/15] acpi, clocksource: add GTDT driver and GTDT support in arm_arch_timer
From: fu.wei at linaro.org @ 2016-11-25  8:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Fu Wei <fu.wei@linaro.org>

This patchset:
    (1)Preparation for adding GTDT support in arm_arch_timer:
        1. Move some enums and marcos to header file;
        2. Add a new enum for spi type;
        3. Improve printk relevant code;
        4. Rename some enums and defines;
        5. Rework PPI determination;
        6. Rework counter frequency detection;
        7. Refactor arch_timer_needs_probing, move it into DT init call
        8. Introduce some new structs and refactor the MMIO timer init code
        for reusing some common code.

    (2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
    Parse all kinds of timer in GTDT table of ACPI:arch timer,
    memory-mapped timer and SBSA Generic Watchdog timer.
    This driver can help to simplify all the relevant timer drivers,
    and separate all the ACPI GTDT knowledge from them.

    (3)Simplify ACPI code for arm_arch_timer

    (4)Add GTDT support for ARM memory-mapped timer.

This patchset has been tested on the following platforms with ACPI enabled:
    (1)ARM Foundation v8 model

Changelog:
v17: https://lkml.org/lkml/2016/11/25/
     Take out some cleanups from 4/15.
     Merge 5/15 and 6/15, improve PPI determination code,
     improve commit message.
     Rework counter frequency detection.
     Move arch_timer_needs_of_probing into DT init call.
     Move Platform Timer scan loop back to timer init call to avoid allocating
     and free memory.
     Improve all the exported functions' comment.

v16: https://lkml.org/lkml/2016/11/16/268
     Fix patchset problem about static enum ppi_nr of 01/13 in v15.
     Refactor arch_timer_detect_rate.
     Refactor arch_timer_needs_probing.

v15: https://lkml.org/lkml/2016/11/15/366
     Re-order patches
     Add arm_arch_timer refactoring patches to prepare for GTDT:
         1. rename some  enums and defines, and some cleanups
         2. separate out arch_timer_uses_ppi init code and fix a potential bug
         3. Improve some new structs, refactor the timer init code.
     Since the some structs have been changed, GTDT parser for memory-mapped
     timer and SBSA Generic Watchdog timer have been update.

v14: https://lkml.org/lkml/2016/9/28/573
     Separate memory-mapped timer GTDT support into two patches
         1. Refactor the timer init code to prepare for GTDT
         2. Add GTDT support for memory-mapped timer

v13: http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1231717.html
     Improve arm_arch_timer code for memory-mapped
     timer GTDT support, refactor original memory-mapped timer
     dt support for reusing some common code.

v12: https://lkml.org/lkml/2016/9/13/250
     Rebase to latest Linux 4.8-rc6
     Delete the confusing "skipping" in the error message.

V11: https://lkml.org/lkml/2016/9/6/354
     Rebase to latest Linux 4.8-rc5
     Delete typedef (suggested by checkpatch.pl)

V10: https://lkml.org/lkml/2016/7/26/215
     Drop the "readq" patch.
     Rebase to latest Linux 4.7.

V9: https://lkml.org/lkml/2016/7/25/345
    Improve pr_err message in acpi gtdt driver.
    Update Commit message for 7/9
    shorten the irq mapping function name
    Improve GTDT driver for memory-mapped timer

v8: https://lkml.org/lkml/2016/7/19/660
    Improve "pr_fmt(fmt)" definition: add "ACPI" in front of "GTDT",
    and also improve printk message.
    Simplify is_timer_block and is_watchdog.
    Merge acpi_gtdt_desc_init and gtdt_arch_timer_init into acpi_gtdt_init();
    Delete __init in include/linux/acpi.h for GTDT API
    Make ARM64 select GTDT.
    Delete "#include <linux/module.h>" from acpi_gtdt.c
    Simplify GT block parse code.

v7: https://lkml.org/lkml/2016/7/13/769
    Move the GTDT driver to drivers/acpi/arm64
    Add add the ARM64-specific ACPI Support maintainers in MAINTAINERS
    Merge 3 patches of GTDT parser driver.
    Fix the for_each_platform_timer bug.

v6: https://lkml.org/lkml/2016/6/29/580
    split the GTDT driver to 4 parts: basic, arch_timer, memory-mapped timer,
    and SBSA Generic Watchdog timer
    Improve driver by suggestions and example code from Daniel Lezcano

v5: https://lkml.org/lkml/2016/5/24/356
    Sorting out all patches, simplify the API of GTDT driver:
    GTDT driver just fills the data struct for arm_arch_timer driver.

v4: https://lists.linaro.org/pipermail/linaro-acpi/2016-March/006667.html
    Delete the kvm relevant patches
    Separate two patches for sorting out the code for arm_arch_timer.
    Improve irq info export code to allow missing irq info in GTDT table.

v3: https://lkml.org/lkml/2016/2/1/658
    Improve GTDT driver code:
      (1)improve pr_* by defining pr_fmt(fmt)
      (2)simplify gtdt_sbsa_gwdt_init
      (3)improve gtdt_arch_timer_data_init, if table is NULL, it will try
      to get GTDT table.
    Move enum ppi_nr to arm_arch_timer.h, and add enum spi_nr.
    Add arm_arch_timer get ppi from DT and GTDT support for kvm.

v2: https://lkml.org/lkml/2015/12/2/10
    Rebase to latest kernel version(4.4-rc3).
    Fix the bug about the config problem,
    use CONFIG_ACPI_GTDT instead of CONFIG_ACPI in arm_arch_timer.c

v1: The first upstreaming version: https://lkml.org/lkml/2015/10/28/553
Fu Wei (15):
  clocksource/drivers/arm_arch_timer: Move enums and defines to header
    file
  clocksource/drivers/arm_arch_timer: Add a new enum for spi type
  clocksource/drivers/arm_arch_timer: Improve printk relevant code
  clocksource/drivers/arm_arch_timer: rename some enums and defines.
  clocksource/drivers/arm_arch_timer: rework PPI determination
  clocksource/drivers/arm_arch_timer: Rework counter frequency
    detection.
  clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing
  clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing
    into DT init call
  clocksource/drivers/arm_arch_timer: Introduce some new structs to
    prepare for GTDT
  clocksource/drivers/arm_arch_timer: Refactor the timer init code to
    prepare for GTDT
  acpi/arm64: Add GTDT table parse driver
  clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
  acpi/arm64: Add memory-mapped timer support in GTDT driver
  clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped
    timer
  acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver

 arch/arm64/Kconfig                   |   1 +
 drivers/acpi/arm64/Kconfig           |   3 +
 drivers/acpi/arm64/Makefile          |   1 +
 drivers/acpi/arm64/gtdt.c            | 374 +++++++++++++++++++++++++++
 drivers/clocksource/arm_arch_timer.c | 478 ++++++++++++++++++++---------------
 drivers/watchdog/Kconfig             |   1 +
 include/clocksource/arm_arch_timer.h |  45 +++-
 include/linux/acpi.h                 |   7 +
 virt/kvm/arm/hyp/timer-sr.c          |   6 +-
 9 files changed, 708 insertions(+), 208 deletions(-)
 create mode 100644 drivers/acpi/arm64/gtdt.c

-- 
2.9.3

^ permalink raw reply

* [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Ziji Hu @ 2016-11-25  8:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <76ce72f8-4b86-3b83-544f-b9a7ef871393@marvell.com>

Hi Ulf,

On 2016/11/24 23:00, Ziji Hu wrote:
> Hi Ulf,
> 
> On 2016/11/24 21:34, Ulf Hansson wrote:
<snip>
>>>>> +
>>>>> +       /*
>>>>> +        * Xenon Specific property:
>>>>> +        * emmc: explicitly indicate whether this slot is for eMMC
>>>>> +        * slotno: the index of slot. Refer to SDHC_SYS_CFG_INFO register
>>>>> +        * tun-count: the interval between re-tuning
>>>>> +        * PHY type: "sdhc phy", "emmc phy 5.0" or "emmc phy 5.1"
>>>>> +        */
>>>>> +       if (of_property_read_bool(np, "marvell,xenon-emmc"))
>>>>> +               priv->emmc_slot = true;
>>>>
>>>> So, you need this because of the eMMC voltage switch behaviour, right?
>>>>
>>>> Then I would rather like to describe this a generic DT bindings for
>>>> the eMMC voltage level support. There have acutally been some earlier
>>>> discussions for this, but we haven't yet made some changes.
>>>>
>>>> I think what is missing is a mmc-ddr-3_3v DT binding, which when set,
>>>> allows the host driver to accept I/O voltage switches to 3.3V. If not
>>>> supported the  ->start_signal_voltage_switch() ops may return -EINVAL.
>>>> This would inform the mmc core to move on to the next supported
>>>> voltage level. There might be some minor additional changes to the mmc
>>>> card initialization sequence, but those should be simple.
>>>>
>>>> I can help out to look into this, unless you want to do it yourself of course!?
>>>>
>>>    Yes. One of the reasons is to provide eMMC specific voltage setting.
>>>    But in my very own opinion, it should be irrelevant to voltage level.
>>>    The eMMC voltage setting on our SDHC is different from SD/SDIO voltage switch.
>>>    It will become more complex with different SOC implementation details.
>>
>> Got it. Although I think we can cope with that fine just by using the
>> different SD/eMMC speed modes settings defined in DT (or from the
>> SDHCI caps register)
>>
>     In my very opinion, I'm not sure if there is any corner case that driver cannot
>     determine the eMMC card type from DT and SDHC caps.
> 
>>>    Unfortunately, MMC driver cannot determine the card type yet when eMMC voltage
>>>    setting should be executed.
>>>    Thus an flag is required here to tell driver to execute eMMC voltage setting.
>>>
>>>    Besides, additional eMMC specific settings might be implemented in future, besides
>>>    voltage setting. Most of them should be completed before MMC driver recognizes the
>>>    card type. Thus I have to keep this flag to indicate current SDHC is for eMMC.
>>
>> I doubt you will need a generic "eMMC" flag, but let's see when we go forward.
>>
>> Currently it's clear you don't need such a flag, so I will submit a
>> change adding a DT binding for "mmc-ddr-3_3v" then we can take it from
>> there, to see if it suits your needs.
>>

    Another reason for a special "xenon-emmc" property is that our host IP usually can
    support both eMMC and SD. Whether a host is used as eMMC or SD depends on the
    final implementation of the actual product.
    Thus our host driver needs to know whether current SDHC is fixed as eMMC or SD.
    So far, It can only get the information from DT.

    After out host driver get the card type information from DT, it can prepare eMMC
    specific voltage, set eMMC specific mmc->caps/caps2 flags and do other
    vendor specific init, before card init procedure.
    Otherwise, our host driver has to wait until card type is determined in mmc_rescan().

    A generic "eMMC" flag is unnecessary. I just require a private property,
    which is only used in our host driver and DT.

    Thank you.

Best regards,
Hu Ziji

> 
>     Actually, our eMMC is usually fixed as 1.8V.
> 
>     The pair "no-sd" + "no-sdio" can provide the similar information.
>     But I'm not sure if it is proper to use those two property in such a way.
> 
>     Thank you.
> 
> Best regards
> Hu Ziji
> 
>> [...]
>>
>> Kind regards
>> Uffe
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* [PATCH v3 0/3] modversions: Fix CRC mangling under CONFIG_RELOCATABLE=y
From: Ard Biesheuvel @ 2016-11-25  8:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_Ej5j8MTQkzhw3Kyzkk4mENuBm12NoLU-aaw_R_OW_yQ@mail.gmail.com>

On 15 November 2016 at 09:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 10 November 2016 at 05:22, Michael Ellerman <mpe@ellerman.id.au> wrote:
>> Ard Biesheuvel <ard.biesheuvel@linaro.org> writes:
>>
>>> On 27 October 2016 at 17:27, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>>>> This series is a followup to the single patch 'modversions: treat symbol
>>>> CRCs as 32 bit quantities on 64 bit archs', of which two versions have
>>>> been sent out so far [0][1]
>>>>
>>>> As pointed out by Michael, GNU ld behaves a bit differently between arm64
>>>> and PowerPC64, and where the former gets rid of all runtime relocations
>>>> related to CRCs, the latter is not as easily convinced.
>>>>
>>>> Patch #1 fixes the issue where CRCs are corrupted by the runtime relocation
>>>> routines for 32-bit PowerPC, for which the original fix was effectively
>>>> reverted by commit 0e0ed6406e61 ("powerpc/modules: Module CRC relocation fix
>>>> causes perf issues")
>>>>
>>>> Patch #2 adds handling of R_PPC64_ADDR32 relocations against the NULL .dynsym
>>>> symbol entry to the PPC64 runtime relocation routines, so it is prepared to
>>>> deal with CRCs being emitted as 32-bit quantities.
>>>>
>>>> Patch #3 is the original patch from the v1 and v2 submissions.
>>>>
>>>> Changes since v2:
>>>> - added #1 and #2
>>>> - updated #3 to deal with CRC entries being emitted from assembler
>>>> - added Rusty's ack (#3)
>>>>
>>>> Branch can be found here:
>>>> https://git.kernel.org/cgit/linux/kernel/git/ardb/linux.git/log/?h=kcrctab-reloc
>>>>
>>>> [0] http://marc.info/?l=linux-kernel&m=147652300207369&w=2
>>>> [1] http://marc.info/?l=linux-kernel&m=147695629614409&w=2
>>>
>>> Ping?
>>
>> Sorry, you didn't cc linuxppc-dev, so it's not in my patchwork list
>> which tends to mean I miss it.
>>
>
> Ah, my mistake. Apologies.
>
>> Will try and test and get back to you.
>>
>

Ping?

^ permalink raw reply

* RPI3 doesn't boot in ARM64 mode on linux-next
From: Ard Biesheuvel @ 2016-11-25  8:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480041098.1504.1.camel@crowfest.net>

On 25 November 2016 at 02:31, Michael Zoran <mzoran@crowfest.net> wrote:
> Last night I did a build of linux-next and I'm finding that I can no
> longer get my RPI 3 to boot in arm64 mode anymore.  It seems to be
> hanging very early in the boot process.
>
> I know linux-next is going through a very large number of changes now,
> so does anybody know if arm64(not just the RPI 3) is just broken in
> general at this point? 4.9rc6 is working fine.
>
> I don't have a JTAG debugger, so it's a bit hard for me to debug.  I've
> actually been looking for a decent cheap JTAG debugger for awhile now,
> so if anybody knows of one in the < $300.00 range it might be a good
> self Christmas present.
>

Are you using earlycon?

^ permalink raw reply

* [PATCH resend v3] ASoC: sun4i-codec: Add "Right Mixer" to "Line Out Mono Diff." route
From: Maxime Ripard @ 2016-11-25  8:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161124114649.5188-1-wens@csie.org>

On Thu, Nov 24, 2016 at 07:46:49PM +0800, Chen-Yu Tsai wrote:
> The mono differential output for "Line Out" downmixes the stereo audio
> from the mixer, instead of just taking the left channel.
> 
> Add a route from the "Right Mixer" to "Line Out Source Playback Route"
> through the "Mono Differential" path, so DAPM doesn't shut down
> everything if the left channel is muted.
> 
> Fixes: 0f909f98d7cb ("ASoC: sun4i-codec: Add support for A31 Line Out
> 		      playback")
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161125/9e1a3418/attachment.sig>

^ permalink raw reply

* [PATCH v3 2/6] iio: adc: Add support for STM32 ADC core
From: Fabrice Gasnier @ 2016-11-25  8:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cd958ae5-90e4-b6c5-8a23-84c49011e8e3@kernel.org>

On 11/24/2016 09:40 PM, Jonathan Cameron wrote:
> On 21/11/16 08:54, Fabrice Gasnier wrote:
>> 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 ?
> Just update those that haven't already been applied.
Hi,

I'll update these only.
Thanks,
Fabrice

>
> Thanks,
>
> Jonathan
>> 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
>>>>
>> -- 
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] reset: hisilicon: add a polarity cell for reset line specifier
From: Jiancheng Xue @ 2016-11-25  8:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <2281ff0d-2883-a78c-6106-f913da24581f@hisilicon.com>



On 2016/11/25 11:45, Jiancheng Xue wrote:
> 
> On 2016/11/21 10:58, Jiancheng Xue wrote:
>> Hi Philipp,
>>
>>> On 2016/11/15 18:43, Philipp Zabel wrote:
>>>> Hi Jiancheng,
>>>>
>>>> Am Dienstag, den 15.11.2016, 15:09 +0800 schrieb Jiancheng Xue:
>>>>> Add a polarity cell for reset line specifier. If the reset line
>>>>> is asserted when the register bit is 1, the polarity is
>>>>> normal. Otherwise, it is inverted.
>>>>>
>>>>> Signed-off-by: Jiancheng Xue <xuejiancheng@hisilicon.com>
>>>>> ---
>>> Thank you very much for replying so soon.
>>>
>>> Please allow me to decribe the reason why this patch exists first.
>>> All bits in the reset controller were designed to be active-high.
>>> But in a recent chip only one bit was implemented to be active-low :(
>>>
>>>>>  .../devicetree/bindings/clock/hisi-crg.txt         | 11 ++++---
>>>>>  arch/arm/boot/dts/hi3519.dtsi                      |  2 +-
>>>>>  drivers/clk/hisilicon/reset.c                      | 36 ++++++++++++++++------
>>>>>  3 files changed, 33 insertions(+), 16 deletions(-)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>>> index e3919b6..fcbb4f3 100644
>>>>> --- a/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>>> @@ -25,19 +25,20 @@ to specify the clock which they consume.
>>>>>  
>>>>>  All these identifier could be found in <dt-bindings/clock/hi3519-clock.h>.
>>>>>  
>>>>> -- #reset-cells: should be 2.
>>>>> +- #reset-cells: should be 3.
>>>>>  
>>>>>  A reset signal can be controlled by writing a bit register in the CRG module.
>>>>> -The reset specifier consists of two cells. The first cell represents the
>>>>> +The reset specifier consists of three cells. The first cell represents the
>>>>>  register offset relative to the base address. The second cell represents the
>>>>> -bit index in the register.
>>>>> +bit index in the register. The third cell represents the polarity of the reset
>>>>> +line (0 for normal, 1 for inverted).
>>>>
>> #reset-cells: Should be 2 if compatilbe string is "hisilicon,hi3519-crg". Should be 3 otherwise.
>> 	      A reset signal can be controlled by writing a bit register in the CRG module.
>> 	      The reset specifier consists of two or three cells. The first cell represents the
>> 	      register offset relative to the base address. The second cell represents the
>> 	      bit index in the register.The third cell represents the polarity of the reset
>> 	      line (0 for active-high, 1 for active-low).
>>
>> If I change the binding like this, can it be accepted?
>>
> Hi Philipp,
> 
> Could you give me more suggestions about this?  If you really don't like changing the
> reset-cells like this, I can modify the patch according to your suggestions.
> Thank you.
> 

I'll drop this patch and use "ti,syscon-reset" instead to resolve the polarity issue. Thanks.

Regards,
Jiancheng

^ permalink raw reply

* [PATCH v2 0/3] arm64: dts: r8a7796: Add CAN/CAN FD support
From: Simon Horman @ 2016-11-25  7:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480004021-4037-1-git-send-email-chris.paterson2@renesas.com>

On Thu, Nov 24, 2016 at 04:13:38PM +0000, Chris Paterson wrote:
> This series adds CAN and CAN FD support to the r8a7796.
> 
> Changes since v1:
> - Split device tree changes from bindings documentation.
> - Rebased on renesas-devel-20161123v2-v4.9-rc6.
> 
> 
> Chris Paterson (3):
>   arm64: dts: r8a7796: Add CAN external clock support
>   arm64: dts: r8a7796: Add CAN support
>   arm64: dts: r8a7796: Add CAN FD support

Thanks Chris,

I have queued these up for v4.11 in the devel branch of the renesas tree.

^ permalink raw reply

* [linux-sunxi] [PATCH v6 3/5] ARM: dts: sun8i-h3: add HDMI video nodes
From: Jean-François Moine @ 2016-11-25  6:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6896101480051640@web28h.yandex.ru>

On Fri, 25 Nov 2016 13:27:20 +0800
Icenowy Zheng <icenowy@aosc.xyz> wrote:

> > + assigned-clocks = <&ccu CLK_PLL_DE>,
> 
> Cannot get the patch built on 4.9-rc, as CLK_PLL_DE is not an exported clock.

Hi,

Sorry, I forgot it. The symbol goes to
include/dt-bindings/clock/sun8i-h3-ccu.h
as:

#define CLK_PLL_DE		13

-- 
Ken ar c'henta?	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/

^ permalink raw reply

* [PATCH] clk: sunxi-ng: fix PLL_CPUX adjusting on H3
From: Maxime Ripard @ 2016-11-25  6:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161125002852.18097-1-megous@megous.com>

On Fri, Nov 25, 2016 at 01:28:47AM +0100, megous at megous.com wrote:
> From: Ondrej Jirman <megous@megous.com>
> 
> When adjusting PLL_CPUX on H3, the PLL is temporarily driven
> too high, and the system becomes unstable (oopses or hangs).
> 
> Add a notifier to avoid this situation by temporarily switching
> to a known stable 24 MHz oscillator.
> 
> Signed-off-by: Ondrej Jirman <megous@megous.com>
> Tested-by: Lutz Sammer <johns98@gmx.net>

Applied, thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161125/8ebd4b9a/attachment.sig>

^ permalink raw reply

* [PATCH 02/10] ASoC: sunxi: Add support for A23/A33/H3 codec's analog path controls
From: Icenowy Zheng @ 2016-11-25  5:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGb2v66Zb9-UdimKDn5tq9UPRY7wBZNNCCn-52bf=evP914sPg@mail.gmail.com>



25.11.2016, 13:46, "Chen-Yu Tsai" <wens@csie.org>:
> On Fri, Nov 25, 2016 at 1:43 PM, Icenowy Zheng <icenowy@aosc.xyz> wrote:
>> ?12.11.2016, 14:57, "Chen-Yu Tsai" <wens@csie.org>:
>>> ?The internal codec on A23/A33/H3 is split into 2 parts. The
>>> ?analog path controls are routed through an embedded custom register
>>> ?bus accessed through the PRCM block.
>>>
>>> ?The SoCs share a common set of inputs, outputs, and audio paths.
>>> ?The following table lists the differences.
>>>
>>> ?????----------------------------------------
>>> ?????| Feature \ SoC | A23 | A33 | H3 |
>>> ?????----------------------------------------
>>> ?????| Headphone | v | v | |
>>> ?????----------------------------------------
>>> ?????| Line Out | | | v |
>>> ?????----------------------------------------
>>> ?????| Phone In/Out | v | v | |
>>> ?????----------------------------------------
>>>
>>> ?Add an ASoC component driver for it. This should be tied to the codec
>>> ?audio card as an auxiliary device. This patch adds the commont paths
>>> ?and controls, and variant specific headphone out and line out.
>>>
>>> ?Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>> ?---
>>> ??sound/soc/sunxi/Kconfig | 8 +
>>> ??sound/soc/sunxi/Makefile | 1 +
>>> ??sound/soc/sunxi/sun8i-codec-analog.c | 665 +++++++++++++++++++++++++++++++++++
>>> ??3 files changed, 674 insertions(+)
>>> ??create mode 100644 sound/soc/sunxi/sun8i-codec-analog.c
>>>
>>> ?diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
>>> ?index dd2368297fd3..6c344e16aca4 100644
>>> ?--- a/sound/soc/sunxi/Kconfig
>>> ?+++ b/sound/soc/sunxi/Kconfig
>>> ?@@ -9,6 +9,14 @@ config SND_SUN4I_CODEC
>>> ????????????Select Y or M to add support for the Codec embedded in the Allwinner
>>> ????????????A10 and affiliated SoCs.
>>>
>>> ?+config SND_SUN8I_CODEC_ANALOG
>>> ?+ tristate "Allwinner sun8i Codec Analog Controls Support"
>>> ?+ depends on MACH_SUN8I || COMPILE_TEST
>>
>> ?sun50i-a64 has a similar (or the same?) codec to A33.
>
> I think the register offsets/fields were moved around again.
> Why does Allwinner always do that... :/

Yes, moved around :-(

Or maybe I should say "there's more registers on A64".

>
> ChenYu
>
>>> ?+ select REGMAP
>>> ?+ help
>>> ?+ Say Y or M if you want to add support for the analog controls for
>>> ?+ the codec embedded in newer Allwinner SoCs.
>>> ?+
>>> ??config SND_SUN4I_I2S
>>> ??????????tristate "Allwinner A10 I2S Support"
>>> ??????????select SND_SOC_GENERIC_DMAENGINE_PCM
>>> ?diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
>>> ?index 604c7b842837..241c0df9ca0c 100644
>>> ?--- a/sound/soc/sunxi/Makefile
>>> ?+++ b/sound/soc/sunxi/Makefile
>>> ?@@ -1,3 +1,4 @@
>>> ??obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
>>> ??obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
>>> ??obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
>>> ?+obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
>>> ?diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
>>> ?new file mode 100644
>>> ?index 000000000000..222bbd440b1e
>>> ?--- /dev/null
>>> ?+++ b/sound/soc/sunxi/sun8i-codec-analog.c
>>> ?@@ -0,0 +1,665 @@
>>> ?+/*
>>> ?+ * This driver supports the analog controls for the internal codec
>>> ?+ * found in Allwinner's A31s, A23, A33 and H3 SoCs.
>>> ?+ *
>>> ?+ * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
>>> ?+ *
>>> ?+ * This program is free software; you can redistribute it and/or modify
>>> ?+ * it under the terms of the GNU General Public License as published by
>>> ?+ * the Free Software Foundation; either version 2 of the License, or
>>> ?+ * (at your option) any later version.
>>> ?+ *
>>> ?+ * This program is distributed in the hope that it will be useful,
>>> ?+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> ?+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> ?+ * GNU General Public License for more details.
>>> ?+ */
>>> ?+
>>> ?+#include <linux/io.h>
>>> ?+#include <linux/kernel.h>
>>> ?+#include <linux/module.h>
>>> ?+#include <linux/of.h>
>>> ?+#include <linux/of_device.h>
>>> ?+#include <linux/platform_device.h>
>>> ?+#include <linux/regmap.h>
>>> ?+
>>> ?+#include <sound/soc.h>
>>> ?+#include <sound/soc-dapm.h>
>>> ?+#include <sound/tlv.h>
>>> ?+
>>> ?+/* Codec analog control register offsets and bit fields */
>>> ?+#define SUN8I_ADDA_HP_VOLC 0x00
>>> ?+#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7
>>> ?+#define SUN8I_ADDA_HP_VOLC_HP_VOL 0
>>> ?+#define SUN8I_ADDA_LOMIXSC 0x01
>>> ?+#define SUN8I_ADDA_LOMIXSC_MIC1 6
>>> ?+#define SUN8I_ADDA_LOMIXSC_MIC2 5
>>> ?+#define SUN8I_ADDA_LOMIXSC_PHONE 4
>>> ?+#define SUN8I_ADDA_LOMIXSC_PHONEN 3
>>> ?+#define SUN8I_ADDA_LOMIXSC_LINEINL 2
>>> ?+#define SUN8I_ADDA_LOMIXSC_DACL 1
>>> ?+#define SUN8I_ADDA_LOMIXSC_DACR 0
>>> ?+#define SUN8I_ADDA_ROMIXSC 0x02
>>> ?+#define SUN8I_ADDA_ROMIXSC_MIC1 6
>>> ?+#define SUN8I_ADDA_ROMIXSC_MIC2 5
>>> ?+#define SUN8I_ADDA_ROMIXSC_PHONE 4
>>> ?+#define SUN8I_ADDA_ROMIXSC_PHONEP 3
>>> ?+#define SUN8I_ADDA_ROMIXSC_LINEINR 2
>>> ?+#define SUN8I_ADDA_ROMIXSC_DACR 1
>>> ?+#define SUN8I_ADDA_ROMIXSC_DACL 0
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC 0x03
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1
>>> ?+#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0
>>> ?+#define SUN8I_ADDA_PHONEIN_GCTRL 0x04
>>> ?+#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4
>>> ?+#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0
>>> ?+#define SUN8I_ADDA_LINEIN_GCTRL 0x05
>>> ?+#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4
>>> ?+#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0
>>> ?+#define SUN8I_ADDA_MICIN_GCTRL 0x06
>>> ?+#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4
>>> ?+#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL 0x07
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1
>>> ?+#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL 0x08
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1
>>> ?+#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0
>>> ?+#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09
>>> ?+#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3
>>> ?+#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL 0x0a
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1
>>> ?+#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0
>>> ?+#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b
>>> ?+#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7
>>> ?+#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6
>>> ?+#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5
>>> ?+#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3
>>> ?+#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0
>>> ?+#define SUN8I_ADDA_LADCMIXSC 0x0c
>>> ?+#define SUN8I_ADDA_LADCMIXSC_MIC1 6
>>> ?+#define SUN8I_ADDA_LADCMIXSC_MIC2 5
>>> ?+#define SUN8I_ADDA_LADCMIXSC_PHONE 4
>>> ?+#define SUN8I_ADDA_LADCMIXSC_PHONEN 3
>>> ?+#define SUN8I_ADDA_LADCMIXSC_LINEINL 2
>>> ?+#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1
>>> ?+#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0
>>> ?+#define SUN8I_ADDA_RADCMIXSC 0x0d
>>> ?+#define SUN8I_ADDA_RADCMIXSC_MIC1 6
>>> ?+#define SUN8I_ADDA_RADCMIXSC_MIC2 5
>>> ?+#define SUN8I_ADDA_RADCMIXSC_PHONE 4
>>> ?+#define SUN8I_ADDA_RADCMIXSC_PHONEP 3
>>> ?+#define SUN8I_ADDA_RADCMIXSC_LINEINR 2
>>> ?+#define SUN8I_ADDA_RADCMIXSC_OMIXR 1
>>> ?+#define SUN8I_ADDA_RADCMIXSC_OMIXL 0
>>> ?+#define SUN8I_ADDA_RES 0x0e
>>> ?+#define SUN8I_ADDA_RES_MMICBIAS_SEL 4
>>> ?+#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0
>>> ?+#define SUN8I_ADDA_ADC_AP_EN 0x0f
>>> ?+#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7
>>> ?+#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
>>> ?+#define SUN8I_ADDA_ADC_AP_EN_ADCG 0
>>> ?+
>>> ?+/* Analog control register access bits */
>>> ?+#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
>>> ?+#define ADDA_PR_RESET BIT(28)
>>> ?+#define ADDA_PR_WRITE BIT(24)
>>> ?+#define ADDA_PR_ADDR_SHIFT 16
>>> ?+#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
>>> ?+#define ADDA_PR_DATA_IN_SHIFT 8
>>> ?+#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
>>> ?+#define ADDA_PR_DATA_OUT_SHIFT 0
>>> ?+#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
>>> ?+
>>> ?+/* regmap access bits */
>>> ?+static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
>>> ?+{
>>> ?+ void __iomem *base = (void __iomem *)context;
>>> ?+ u32 tmp;
>>> ?+
>>> ?+ /* De-assert reset */
>>> ?+ writel(readl(base) | ADDA_PR_RESET, base);
>>> ?+
>>> ?+ /* Clear write bit */
>>> ?+ writel(readl(base) & ~ADDA_PR_WRITE, base);
>>> ?+
>>> ?+ /* Set register address */
>>> ?+ tmp = readl(base);
>>> ?+ tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
>>> ?+ tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
>>> ?+ writel(tmp, base);
>>> ?+
>>> ?+ /* Read back value */
>>> ?+ *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
>>> ?+
>>> ?+ return 0;
>>> ?+}
>>> ?+
>>> ?+static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
>>> ?+{
>>> ?+ void __iomem *base = (void __iomem *)context;
>>> ?+ u32 tmp;
>>> ?+
>>> ?+ /* De-assert reset */
>>> ?+ writel(readl(base) | ADDA_PR_RESET, base);
>>> ?+
>>> ?+ /* Set register address */
>>> ?+ tmp = readl(base);
>>> ?+ tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
>>> ?+ tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
>>> ?+ writel(tmp, base);
>>> ?+
>>> ?+ /* Set data to write */
>>> ?+ tmp = readl(base);
>>> ?+ tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
>>> ?+ tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
>>> ?+ writel(tmp, base);
>>> ?+
>>> ?+ /* Set write bit to signal a write */
>>> ?+ writel(readl(base) | ADDA_PR_WRITE, base);
>>> ?+
>>> ?+ /* Clear write bit */
>>> ?+ writel(readl(base) & ~ADDA_PR_WRITE, base);
>>> ?+
>>> ?+ return 0;
>>> ?+}
>>> ?+
>>> ?+static const struct regmap_config adda_pr_regmap_cfg = {
>>> ?+ .name = "adda-pr",
>>> ?+ .reg_bits = 5,
>>> ?+ .reg_stride = 1,
>>> ?+ .val_bits = 8,
>>> ?+ .reg_read = adda_reg_read,
>>> ?+ .reg_write = adda_reg_write,
>>> ?+ .fast_io = true,
>>> ?+ .max_register = 24,
>>> ?+};
>>> ?+
>>> ?+/* mixer controls */
>>> ?+static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
>>> ?+ SOC_DAPM_DOUBLE_R("DAC Playback Switch",
>>> ?+ SUN8I_ADDA_LOMIXSC,
>>> ?+ SUN8I_ADDA_ROMIXSC,
>>> ?+ SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
>>> ?+ SUN8I_ADDA_LOMIXSC,
>>> ?+ SUN8I_ADDA_ROMIXSC,
>>> ?+ SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Line In Playback Switch",
>>> ?+ SUN8I_ADDA_LOMIXSC,
>>> ?+ SUN8I_ADDA_ROMIXSC,
>>> ?+ SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
>>> ?+ SUN8I_ADDA_LOMIXSC,
>>> ?+ SUN8I_ADDA_ROMIXSC,
>>> ?+ SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
>>> ?+ SUN8I_ADDA_LOMIXSC,
>>> ?+ SUN8I_ADDA_ROMIXSC,
>>> ?+ SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
>>> ?+};
>>> ?+
>>> ?+/* ADC mixer controls */
>>> ?+static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
>>> ?+ SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
>>> ?+ SUN8I_ADDA_LADCMIXSC,
>>> ?+ SUN8I_ADDA_RADCMIXSC,
>>> ?+ SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
>>> ?+ SUN8I_ADDA_LADCMIXSC,
>>> ?+ SUN8I_ADDA_RADCMIXSC,
>>> ?+ SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Line In Capture Switch",
>>> ?+ SUN8I_ADDA_LADCMIXSC,
>>> ?+ SUN8I_ADDA_RADCMIXSC,
>>> ?+ SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
>>> ?+ SUN8I_ADDA_LADCMIXSC,
>>> ?+ SUN8I_ADDA_RADCMIXSC,
>>> ?+ SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
>>> ?+ SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
>>> ?+ SUN8I_ADDA_LADCMIXSC,
>>> ?+ SUN8I_ADDA_RADCMIXSC,
>>> ?+ SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
>>> ?+};
>>> ?+
>>> ?+/* volume / mute controls */
>>> ?+static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
>>> ?+ -450, 150, 0);
>>> ?+static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale,
>>> ?+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
>>> ?+ 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
>>> ?+);
>>> ?+
>>> ?+static const struct snd_kcontrol_new sun8i_codec_common_controls[] = {
>>> ?+ /* Mixer pre-gains */
>>> ?+ SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL,
>>> ?+ SUN8I_ADDA_LINEIN_GCTRL_LINEING,
>>> ?+ 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>>> ?+ SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL,
>>> ?+ SUN8I_ADDA_MICIN_GCTRL_MIC1G,
>>> ?+ 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>>> ?+ SOC_SINGLE_TLV("Mic2 Playback Volume",
>>> ?+ SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G,
>>> ?+ 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
>>> ?+
>>> ?+ /* Microphone Amp boost gains */
>>> ?+ SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> ?+ SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0,
>>> ?+ sun8i_codec_mic_gain_scale),
>>> ?+ SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0,
>>> ?+ sun8i_codec_mic_gain_scale),
>>> ?+
>>> ?+ /* ADC */
>>> ?+ SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN,
>>> ?+ SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0,
>>> ?+ sun8i_codec_out_mixer_pregain_scale),
>>> ?+};
>>> ?+
>>> ?+static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
>>> ?+ /* ADC */
>>> ?+ SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
>>> ?+ SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
>>> ?+ SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
>>> ?+ SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
>>> ?+
>>> ?+ /* DAC */
>>> ?+ SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
>>> ?+ SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
>>> ?+ /*
>>> ?+ * Due to this component and the codec belonging to separate DAPM
>>> ?+ * contexts, we need to manually link the above widgets to their
>>> ?+ * stream widgets at the card level.
>>> ?+ */
>>> ?+
>>> ?+ /* Line In */
>>> ?+ SND_SOC_DAPM_INPUT("LINEIN"),
>>> ?+
>>> ?+ /* Microphone inputs */
>>> ?+ SND_SOC_DAPM_INPUT("MIC1"),
>>> ?+ SND_SOC_DAPM_INPUT("MIC2"),
>>> ?+
>>> ?+ /* Microphone Bias */
>>> ?+ SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> ?+ SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
>>> ?+ 0, NULL, 0),
>>> ?+
>>> ?+ /* Mic input path */
>>> ?+ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> ?+ SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
>>> ?+ SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
>>> ?+
>>> ?+ /* Mixers */
>>> ?+ SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
>>> ?+ sun8i_codec_mixer_controls,
>>> ?+ ARRAY_SIZE(sun8i_codec_mixer_controls)),
>>> ?+ SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
>>> ?+ sun8i_codec_mixer_controls,
>>> ?+ ARRAY_SIZE(sun8i_codec_mixer_controls)),
>>> ?+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
>>> ?+ SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
>>> ?+ sun8i_codec_adc_mixer_controls,
>>> ?+ ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
>>> ?+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
>>> ?+ SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
>>> ?+ sun8i_codec_adc_mixer_controls,
>>> ?+ ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
>>> ?+};
>>> ?+
>>> ?+static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
>>> ?+ /* Microphone Routes */
>>> ?+ { "Mic1 Amplifier", NULL, "MIC1"},
>>> ?+ { "Mic2 Amplifier", NULL, "MIC2"},
>>> ?+
>>> ?+ /* Left Mixer Routes */
>>> ?+ { "Left Mixer", "DAC Playback Switch", "Left DAC" },
>>> ?+ { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
>>> ?+ { "Left Mixer", "Line In Playback Switch", "LINEIN" },
>>> ?+ { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
>>> ?+ { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
>>> ?+
>>> ?+ /* Right Mixer Routes */
>>> ?+ { "Right Mixer", "DAC Playback Switch", "Right DAC" },
>>> ?+ { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
>>> ?+ { "Right Mixer", "Line In Playback Switch", "LINEIN" },
>>> ?+ { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
>>> ?+ { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
>>> ?+
>>> ?+ /* Left ADC Mixer Routes */
>>> ?+ { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
>>> ?+ { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
>>> ?+ { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
>>> ?+ { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
>>> ?+ { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
>>> ?+
>>> ?+ /* Right ADC Mixer Routes */
>>> ?+ { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
>>> ?+ { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
>>> ?+ { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
>>> ?+ { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
>>> ?+ { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
>>> ?+
>>> ?+ /* ADC Routes */
>>> ?+ { "Left ADC", NULL, "Left ADC Mixer" },
>>> ?+ { "Right ADC", NULL, "Right ADC Mixer" },
>>> ?+};
>>> ?+
>>> ?+/* headphone specific controls, widgets, and routes */
>>> ?+static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
>>> ?+static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
>>> ?+ SOC_SINGLE_TLV("Headphone Playback Volume",
>>> ?+ SUN8I_ADDA_HP_VOLC,
>>> ?+ SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
>>> ?+ sun8i_codec_hp_vol_scale),
>>> ?+ SOC_DOUBLE("Headphone Playback Switch",
>>> ?+ SUN8I_ADDA_DAC_PA_SRC,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
>>> ?+};
>>> ?+
>>> ?+static const char * const sun8i_codec_hp_src_enum_text[] = {
>>> ?+ "DAC", "Mixer",
>>> ?+};
>>> ?+
>>> ?+static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_LHPIS,
>>> ?+ SUN8I_ADDA_DAC_PA_SRC_RHPIS,
>>> ?+ sun8i_codec_hp_src_enum_text);
>>> ?+
>>> ?+static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
>>> ?+ SOC_DAPM_ENUM("Headphone Source Playback Route",
>>> ?+ sun8i_codec_hp_src_enum),
>>> ?+};
>>> ?+
>>> ?+static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
>>> ?+ SND_SOC_DAPM_MUX("Headphone Source Playback Route",
>>> ?+ SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
>>> ?+ SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
>>> ?+ SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0),
>>> ?+ SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
>>> ?+ SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
>>> ?+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
>>> ?+ SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0),
>>> ?+ SND_SOC_DAPM_OUTPUT("HP"),
>>> ?+};
>>> ?+
>>> ?+static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
>>> ?+ { "Headphone Source Playback Route", "DAC", "Left DAC" },
>>> ?+ { "Headphone Source Playback Route", "DAC", "Right DAC" },
>>> ?+ { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
>>> ?+ { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
>>> ?+ { "Headphone Amp", NULL, "Headphone Source Playback Route" },
>>> ?+ { "HPCOM", NULL, "HPCOM Protection" },
>>> ?+ { "HP", NULL, "Headphone Amp" },
>>> ?+};
>>> ?+
>>> ?+static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
>>> ?+{
>>> ?+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>>> ?+ struct device *dev = cmpnt->dev;
>>> ?+ int ret;
>>> ?+
>>> ?+ ret = snd_soc_add_component_controls(cmpnt,
>>> ?+ sun8i_codec_headphone_controls,
>>> ?+ ARRAY_SIZE(sun8i_codec_headphone_controls));
>>> ?+ if (ret) {
>>> ?+ dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
>>> ?+ ARRAY_SIZE(sun8i_codec_headphone_widgets));
>>> ?+ if (ret) {
>>> ?+ dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes,
>>> ?+ ARRAY_SIZE(sun8i_codec_headphone_routes));
>>> ?+ if (ret) {
>>> ?+ dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ return 0;
>>> ?+}
>>> ?+
>>> ?+/* hmic specific widget */
>>> ?+static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
>>> ?+ SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
>>> ?+ SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN,
>>> ?+ 0, NULL, 0),
>>> ?+};
>>> ?+
>>> ?+static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt)
>>> ?+{
>>> ?+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>>> ?+ struct device *dev = cmpnt->dev;
>>> ?+ int ret;
>>> ?+
>>> ?+ ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets,
>>> ?+ ARRAY_SIZE(sun8i_codec_hmic_widgets));
>>> ?+ if (ret)
>>> ?+ dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret);
>>> ?+
>>> ?+ return ret;
>>> ?+}
>>> ?+
>>> ?+/* line out specific controls, widgets and routes */
>>> ?+static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
>>> ?+ 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
>>> ?+ 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
>>> ?+);
>>> ?+static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
>>> ?+ SOC_SINGLE_TLV("Line Out Playback Volume",
>>> ?+ SUN8I_ADDA_PHONE_GAIN_CTRL,
>>> ?+ SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0,
>>> ?+ sun8i_codec_lineout_vol_scale),
>>> ?+ SOC_DOUBLE("Line Out Playback Switch",
>>> ?+ SUN8I_ADDA_MIC2G_CTRL,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
>>> ?+};
>>> ?+
>>> ?+static const char * const sun8i_codec_lineout_src_enum_text[] = {
>>> ?+ "Stereo", "Mono Differential",
>>> ?+};
>>> ?+
>>> ?+static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC,
>>> ?+ SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
>>> ?+ sun8i_codec_lineout_src_enum_text);
>>> ?+
>>> ?+static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
>>> ?+ SOC_DAPM_ENUM("Line Out Source Playback Route",
>>> ?+ sun8i_codec_lineout_src_enum),
>>> ?+};
>>> ?+
>>> ?+static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
>>> ?+ SND_SOC_DAPM_MUX("Line Out Source Playback Route",
>>> ?+ SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
>>> ?+ /* It is unclear if this is a buffer or gate, model it as a supply */
>>> ?+ SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL,
>>> ?+ SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0),
>>> ?+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
>>> ?+};
>>> ?+
>>> ?+static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
>>> ?+ { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
>>> ?+ { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
>>> ?+ { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
>>> ?+ { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
>>> ?+ { "LINEOUT", NULL, "Line Out Source Playback Route" },
>>> ?+ { "LINEOUT", NULL, "Line Out Enable", },
>>> ?+};
>>> ?+
>>> ?+static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
>>> ?+{
>>> ?+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
>>> ?+ struct device *dev = cmpnt->dev;
>>> ?+ int ret;
>>> ?+
>>> ?+ ret = snd_soc_add_component_controls(cmpnt,
>>> ?+ sun8i_codec_lineout_controls,
>>> ?+ ARRAY_SIZE(sun8i_codec_lineout_controls));
>>> ?+ if (ret) {
>>> ?+ dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets,
>>> ?+ ARRAY_SIZE(sun8i_codec_lineout_widgets));
>>> ?+ if (ret) {
>>> ?+ dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes,
>>> ?+ ARRAY_SIZE(sun8i_codec_lineout_routes));
>>> ?+ if (ret) {
>>> ?+ dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ return 0;
>>> ?+}
>>> ?+
>>> ?+struct sun8i_codec_analog_quirks {
>>> ?+ bool has_headphone;
>>> ?+ bool has_hmic;
>>> ?+ bool has_lineout;
>>> ?+};
>>> ?+
>>> ?+static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
>>> ?+ .has_headphone = true,
>>> ?+ .has_hmic = true,
>>> ?+};
>>> ?+
>>> ?+static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
>>> ?+ .has_lineout = true,
>>> ?+};
>>> ?+
>>> ?+static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
>>> ?+{
>>> ?+ struct device *dev = cmpnt->dev;
>>> ?+ const struct sun8i_codec_analog_quirks *quirks;
>>> ?+ int ret;
>>> ?+
>>> ?+ /*
>>> ?+ * This would never return NULL unless someone directly registers a
>>> ?+ * platform device matching this driver's name, without specifying a
>>> ?+ * device tree node.
>>> ?+ */
>>> ?+ quirks = of_device_get_match_data(dev);
>>> ?+
>>> ?+ /* Add controls, widgets, and routes for individual features */
>>> ?+
>>> ?+ if (quirks->has_headphone) {
>>> ?+ ret = sun8i_codec_add_headphone(cmpnt);
>>> ?+ if (ret)
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ if (quirks->has_hmic) {
>>> ?+ sun8i_codec_add_hmic(cmpnt);
>>> ?+ if (ret)
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ if (quirks->has_lineout) {
>>> ?+ ret = sun8i_codec_add_lineout(cmpnt);
>>> ?+ if (ret)
>>> ?+ return ret;
>>> ?+ }
>>> ?+
>>> ?+ return 0;
>>> ?+}
>>> ?+
>>> ?+static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
>>> ?+ .controls = sun8i_codec_common_controls,
>>> ?+ .num_controls = ARRAY_SIZE(sun8i_codec_common_controls),
>>> ?+ .dapm_widgets = sun8i_codec_common_widgets,
>>> ?+ .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets),
>>> ?+ .dapm_routes = sun8i_codec_common_routes,
>>> ?+ .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes),
>>> ?+ .probe = sun8i_codec_analog_cmpnt_probe,
>>> ?+};
>>> ?+
>>> ?+static const struct of_device_id sun8i_codec_analog_of_match[] = {
>>> ?+ {
>>> ?+ .compatible = "allwinner,sun8i-a23-codec-analog",
>>> ?+ .data = &sun8i_a23_quirks,
>>> ?+ },
>>> ?+ {
>>> ?+ .compatible = "allwinner,sun8i-h3-codec-analog",
>>> ?+ .data = &sun8i_h3_quirks,
>>> ?+ },
>>> ?+ {}
>>> ?+};
>>> ?+MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
>>> ?+
>>> ?+static int sun8i_codec_analog_probe(struct platform_device *pdev)
>>> ?+{
>>> ?+ struct resource *res;
>>> ?+ struct regmap *regmap;
>>> ?+ void __iomem *base;
>>> ?+
>>> ?+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> ?+ base = devm_ioremap_resource(&pdev->dev, res);
>>> ?+ if (IS_ERR(base)) {
>>> ?+ dev_err(&pdev->dev, "Failed to map the registers\n");
>>> ?+ return PTR_ERR(base);
>>> ?+ }
>>> ?+
>>> ?+ regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg);
>>> ?+ if (IS_ERR(regmap)) {
>>> ?+ dev_err(&pdev->dev, "Failed to create regmap\n");
>>> ?+ return PTR_ERR(regmap);
>>> ?+ }
>>> ?+
>>> ?+ return devm_snd_soc_register_component(&pdev->dev,
>>> ?+ &sun8i_codec_analog_cmpnt_drv,
>>> ?+ NULL, 0);
>>> ?+}
>>> ?+
>>> ?+static struct platform_driver sun8i_codec_analog_driver = {
>>> ?+ .driver = {
>>> ?+ .name = "sun8i-codec-analog",
>>> ?+ .of_match_table = sun8i_codec_analog_of_match,
>>> ?+ },
>>> ?+ .probe = sun8i_codec_analog_probe,
>>> ?+};
>>> ?+module_platform_driver(sun8i_codec_analog_driver);
>>> ?+
>>> ?+MODULE_DESCRIPTION("Allwinner internal codec analog controls driver");
>>> ?+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
>>> ?+MODULE_LICENSE("GPL");
>>> ?+MODULE_ALIAS("platform:sun8i-codec-analog");
>>> ?--
>>> ?2.10.2
>>>
>>> ?_______________________________________________
>>> ?linux-arm-kernel mailing list
>>> ?linux-arm-kernel at lists.infradead.org
>>> ?http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v2] dmaengine: mv_xor: Add support for scatter-gather DMA mode
From: Vinod Koul @ 2016-11-25  5:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161026081025.28322-1-sr@denx.de>

On Wed, Oct 26, 2016 at 10:10:25AM +0200, Stefan Roese wrote:
> This patch adds memory to memory scatter-gather support to the Marvell
> mv_or DMA driver.

Applied, thanks

-- 
~Vinod

^ 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