* Re: [RFC 3/8] cpufreq: imx6q: Set max suspend_freq to avoid changes during suspend
From: Rafael J. Wysocki @ 2017-03-28 20:50 UTC (permalink / raw)
To: Leonard Crestez
Cc: Mark Rutland, devicetree, Anson Huang, Irina Tirdea, Viresh Kumar,
linux-pm, Liam Girdwood, Rob Herring, linux-kernel, Mark Brown,
Octavian Purdila, Sascha Hauer, Fabio Estevam, Robin Gong,
Shawn Guo, linux-arm-kernel
In-Reply-To: <1490731431.15830.9.camel@nxp.com>
On Tuesday, March 28, 2017 11:03:51 PM Leonard Crestez wrote:
> On Thu, 2017-03-23 at 10:04 +0530, Viresh Kumar wrote:
> > On 22-03-17, 18:53, Leonard Crestez wrote:
> > > If the cpufreq driver tries to modify voltage/freq during suspend/resume
> > > it might need to control an external PMIC via I2C or SPI but those
> > > devices might be already suspended.
> > >
> > > To avoid this scenario we just increase cpufreq to highest setpoint
> > > before suspend. This issue can easily be triggered by ldo-bypass but in
> > > theory any regulator set_voltage call can end up having to modify
> > > external supply voltages.
> > >
> > > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > > ---
> > > drivers/cpufreq/imx6q-cpufreq.c | 2 ++
> > > 1 file changed, 2 insertions(+)
> >
> > Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
>
> The first couple of patches are obvious fixes despite being marked as
> RFC. It would be great if you could apply them to your tree separately
Why?
> from the rest of the series but I'm not sure what the process is here.
Well, you have to talk to me.
Thanks,
Rafael
^ permalink raw reply
* [PATCH 0/2] memory: Introduce ti-emif-sram driver
From: Dave Gerlach @ 2017-03-28 20:55 UTC (permalink / raw)
To: Rob Herring, Tony Lindgren, Santosh Shilimkar, Russell King
Cc: devicetree, Dave Gerlach, Keerthy J, linux-kernel, linux-omap,
linux-arm-kernel
Hi,
This series introduces a ti-emif-sram driver to be used on am335x and am437x.
These SoCs have low power modes that require that the PER power domain be shut
off. Because the EMIF (DDR Controller) resides within this power domain, it
will lose context during a suspend operation, so we must save it so we can
restore once we resume. However, we cannot execute this code from external
memory, as it is not available at this point, so the code must be executed late
in the suspend path and early in the resume path from SRAM.
Patch 2 includes several functions written in ARM ASM that can be relocated to
on-chip SRAM. It also exports a table containing the absolute addresses of the
available PM functions so that other PM code also running from SRAM can branch
to them. It must also calculate virtual addresses for the suspend path, but
physical addresses for the resume path as the MMU is not active when the code
runs.
One thing that may not be immediately clear in the driver is that we can only
get read-only exectuable memory regions from the mmio-sram driver so we also
provide a second region to the driver that is read/write to be used for data
during execution. This is the reason two sram regions are mapped and so many
offsets must be provided to the code section.
In order for structs to co-exist in C and ASM, I went ahead and extended the
generic asm-offsets.c for ARM and added a single function call for this driver
that adds all the constants needed for the ASM code to get offsets into the
struct members. I managed to do it without many direct additions to the
asm-offsets file so I do not think it is too intrusive. This was the only way I
saw to do peaceful C and ASM data structure co-existence. Due to the
dependencies of all of the code on this I did not not split ARM vs drivers/
changes into separate patches because I think it would be more confusing that
way but if needed I think it can be done.
This code is required for low-power modes to work on AM335x and AM437x and a
forthcoming PM series for those platforms will depend on this series. After
both this and the PM series are reviewed I will send the necessary device tree
changes for both, but in the meantime all remaining patches for am335x and
am437x PM can be found here [1].
Regards,
Dave
[1] https://github.com/dgerlach/linux-pm/tree/upstream/v4.11/amx3-suspend-dev
Dave Gerlach (2):
Documentation: dt: Update ti,emif bindings
memory: ti-emif-sram: introduce relocatable suspend/resume handlers
.../bindings/memory-controllers/ti/emif.txt | 18 +-
arch/arm/kernel/asm-offsets.c | 6 +
drivers/memory/Kconfig | 10 +
drivers/memory/Makefile | 4 +
drivers/memory/emif.h | 17 ++
drivers/memory/ti-emif-pm.c | 295 ++++++++++++++++++
drivers/memory/ti-emif-sram-pm.S | 334 +++++++++++++++++++++
include/linux/ti-emif-sram.h | 143 +++++++++
8 files changed, 826 insertions(+), 1 deletion(-)
create mode 100644 drivers/memory/ti-emif-pm.c
create mode 100644 drivers/memory/ti-emif-sram-pm.S
create mode 100644 include/linux/ti-emif-sram.h
--
2.11.0
^ permalink raw reply
* [PATCH 1/2] Documentation: dt: Update ti,emif bindings
From: Dave Gerlach @ 2017-03-28 20:55 UTC (permalink / raw)
To: Rob Herring, Tony Lindgren, Santosh Shilimkar, Russell King
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Dave Gerlach, Keerthy J
In-Reply-To: <20170328205511.21166-1-d-gerlach-l0cyMroinI0@public.gmane.org>
Update the Texas Instruments EMIF binding document to include the device
tree bindings for ti,emif-am3352 and ti,emif-am4372 which are used by
the ti-emif-sram driver to provide low-level PM functionality.
Signed-off-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
---
.../devicetree/bindings/memory-controllers/ti/emif.txt | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
index 0db60470ebb6..8c0214b17c2b 100644
--- a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
@@ -8,6 +8,7 @@ of the EMIF IP and memory parts attached to it.
Required properties:
- compatible : Should be of the form "ti,emif-<ip-rev>" where <ip-rev>
is the IP revision of the specific EMIF instance.
+ For am335x should be ti,emif-am3352.
For am437x should be ti,emif-am4372.
- phy-type : <u32> indicating the DDR phy type. Following are the
@@ -21,6 +22,13 @@ Required properties:
the value shall be "emif<n>" where <n> is the number of the EMIF
instance with base 1.
+Required only for "ti,emif-am3352" and "ti,emif-am4372":
+- sram : Phandles for generic sram driver nodes,
+ first should be type 'protect-exec' for the driver to use to copy
+ and run PM functions, second should be regular pool to be used for
+ data region for code. See Documentation/devicetree/bindings/sram/sram.txt
+ for more details.
+
Optional properties:
- cs1-used : Have this property if CS1 of this EMIF
instance has a memory part attached to it. If there is a memory
@@ -42,7 +50,7 @@ Optional properties:
- hw-caps-temp-alert : Have this property if the controller
has capability for generating SDRAM temperature alerts
-Example:
+-Examples:
emif1: emif@0x4c000000 {
compatible = "ti,emif-4d";
@@ -54,3 +62,11 @@ emif1: emif@0x4c000000 {
hw-caps-ll-interface;
hw-caps-temp-alert;
};
+
+/* From am33xx.dtsi */
+emif: emif@4c000000 {
+ compatible = "ti,emif-am3352";
+ reg = <0x4C000000 0x1000>;
+ sram = <&pm_sram_code
+ &pm_sram_data>;
+};
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/2] memory: ti-emif-sram: introduce relocatable suspend/resume handlers
From: Dave Gerlach @ 2017-03-28 20:55 UTC (permalink / raw)
To: Rob Herring, Tony Lindgren, Santosh Shilimkar, Russell King
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Dave Gerlach, Keerthy J
In-Reply-To: <20170328205511.21166-1-d-gerlach-l0cyMroinI0@public.gmane.org>
Certain SoCs like Texas Instruments AM335x and AM437x require parts
of the EMIF PM code to run late in the suspend sequence from SRAM,
such as saving and restoring the EMIF context and placing the memory
into self-refresh.
One requirement for these SoCs to suspend and enter its lowest power
mode, called DeepSleep0, is that the PER power domain must be shut off.
Because the EMIF (DDR Controller) resides within this power domain, it
will lose context during a suspend operation, so we must save it so we
can restore once we resume. However, we cannot execute this code from
external memory, as it is not available at this point, so the code must
be executed late in the suspend path from SRAM.
This patch introduces a ti-emif-sram driver that includes several
functions written in ARM ASM that are relocatable so the PM SRAM
code can use them. It also allocates a region of writable SRAM to
be used by the code running in the executable region of SRAM to save
and restore the EMIF context. It can export a table containing the
absolute addresses of the available PM functions so that other SRAM
code can branch to them. This code is required for suspend/resume on
AM335x and AM437x to work.
In addition to this, to be able to share data structures between C and
the ti-emif-sram-pm assembly code, we can automatically generate all of
the C struct member offsets and sizes as macros by making use of the ARM
asm-offsets file. In the same header that we define our data structures
in we also define all the macros in an inline function and by adding a
call to this in the asm_offsets file all macros are properly generated
and available to the assembly code without cluttering up the asm-offsets
file.
Signed-off-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
---
arch/arm/kernel/asm-offsets.c | 6 +
drivers/memory/Kconfig | 10 ++
drivers/memory/Makefile | 4 +
drivers/memory/emif.h | 17 ++
drivers/memory/ti-emif-pm.c | 295 ++++++++++++++++++++++++++++++++++
drivers/memory/ti-emif-sram-pm.S | 334 +++++++++++++++++++++++++++++++++++++++
include/linux/ti-emif-sram.h | 143 +++++++++++++++++
7 files changed, 809 insertions(+)
create mode 100644 drivers/memory/ti-emif-pm.c
create mode 100644 drivers/memory/ti-emif-sram-pm.S
create mode 100644 include/linux/ti-emif-sram.h
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 608008229c7d..d728b5660e36 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -28,6 +28,7 @@
#include <asm/vdso_datapage.h>
#include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h>
+#include <linux/ti-emif-sram.h>
/*
* Make sure that the compiler and target are compatible.
@@ -183,5 +184,10 @@ int main(void)
#ifdef CONFIG_VDSO
DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
#endif
+#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
+ BLANK();
+ ti_emif_offsets();
+#endif
+
return 0;
}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index ec80e35c8dfe..c29505fdb5cd 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -83,6 +83,16 @@ config OMAP_GPMC_DEBUG
bootloader or else the GPMC timings won't be identical with the
bootloader timings.
+config TI_EMIF_SRAM
+ tristate "Texas Instruments EMIF SRAM driver"
+ depends on (SOC_AM33XX || SOC_AM43XX) && SRAM
+ help
+ This driver is for the EMIF module available on Texas Instruments
+ AM33XX and AM43XX SoCs and is required for PM. Certain parts of
+ the EMIF PM code must run from on-chip SRAM late in the suspend
+ sequence so this driver provides several relocatable PM functions
+ for the SoC PM code to use.
+
config MVEBU_DEVBUS
bool "Marvell EBU Device Bus Controller"
default y
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index e88097fbc085..6194b37a4265 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -21,3 +21,7 @@ obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
obj-$(CONFIG_SAMSUNG_MC) += samsung/
obj-$(CONFIG_TEGRA_MC) += tegra/
+obj-$(CONFIG_TI_EMIF_SRAM) += ti-emif-sram.o
+ti-emif-sram-objs := ti-emif-pm.o ti-emif-sram-pm.o
+
+AFLAGS_ti-emif-sram-pm.o :=-Wa,-march=armv7-a
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
index bfe08bae961a..9e9f8037955d 100644
--- a/drivers/memory/emif.h
+++ b/drivers/memory/emif.h
@@ -555,6 +555,9 @@
#define READ_LATENCY_SHDW_SHIFT 0
#define READ_LATENCY_SHDW_MASK (0x1f << 0)
+#define EMIF_SRAM_AM33_REG_LAYOUT 0x00000000
+#define EMIF_SRAM_AM43_REG_LAYOUT 0x00000001
+
#ifndef __ASSEMBLY__
/*
* Structure containing shadow of important registers in EMIF
@@ -585,5 +588,19 @@ struct emif_regs {
u32 ext_phy_ctrl_3_shdw;
u32 ext_phy_ctrl_4_shdw;
};
+
+struct ti_emif_pm_functions;
+
+extern unsigned int ti_emif_sram;
+extern unsigned int ti_emif_sram_sz;
+extern struct ti_emif_pm_data ti_emif_pm_sram_data;
+extern struct emif_regs_amx3 ti_emif_regs_amx3;
+
+void ti_emif_save_context(void);
+void ti_emif_restore_context(void);
+void ti_emif_enter_sr(void);
+void ti_emif_exit_sr(void);
+void ti_emif_abort_sr(void);
+
#endif /* __ASSEMBLY__ */
#endif /* __EMIF_H */
diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
new file mode 100644
index 000000000000..5fbdbcc85de5
--- /dev/null
+++ b/drivers/memory/ti-emif-pm.c
@@ -0,0 +1,295 @@
+/*
+ * TI AM33XX SRAM EMIF Driver
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Inc.
+ * Dave Gerlach
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sram.h>
+#include <linux/ti-emif-sram.h>
+
+#include "emif.h"
+
+#define TI_EMIF_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
+ (unsigned long)&ti_emif_sram)
+
+#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0
+
+static phys_addr_t ti_emif_sram_phys, ti_emif_sram_data_phys;
+static unsigned long ti_emif_sram_virt, ti_emif_sram_data_virt;
+static struct gen_pool *sram_pool_code, *sram_pool_data;
+static struct ti_emif_pm_data pm_data;
+static struct ti_emif_pm_functions pm_functions;
+
+static u32 sram_suspend_address(unsigned long addr)
+{
+ return (ti_emif_sram_virt + TI_EMIF_SRAM_SYMBOL_OFFSET(addr));
+}
+
+static phys_addr_t sram_resume_address(unsigned long addr)
+{
+ return ((unsigned long)ti_emif_sram_phys +
+ TI_EMIF_SRAM_SYMBOL_OFFSET(addr));
+}
+
+static void ti_emif_free_sram(void)
+{
+ gen_pool_free(sram_pool_code, ti_emif_sram_virt, ti_emif_sram_sz);
+ gen_pool_free(sram_pool_data, ti_emif_sram_data_virt,
+ sizeof(struct emif_regs_amx3));
+}
+
+static int ti_emif_prepare_push_sram(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ sram_pool_code = of_gen_pool_get(np, "sram", 0);
+ if (!sram_pool_code) {
+ dev_err(dev, "Unable to get sram pool for ocmcram code\n");
+ return -ENODEV;
+ }
+
+ ti_emif_sram_virt = gen_pool_alloc(sram_pool_code, ti_emif_sram_sz);
+ if (!ti_emif_sram_virt) {
+ dev_err(dev, "Unable to allocate code memory from ocmcram\n");
+ return -ENOMEM;
+ }
+
+ /* Save physical address to calculate resume offset during pm init */
+ ti_emif_sram_phys = gen_pool_virt_to_phys(sram_pool_code,
+ ti_emif_sram_virt);
+
+ /* Get sram pool for data section and allocate space */
+ sram_pool_data = of_gen_pool_get(np, "sram", 1);
+ if (!sram_pool_data) {
+ dev_err(dev, "Unable to get sram pool for ocmcram data\n");
+ ret = -ENODEV;
+ goto err_free_sram_code;
+ }
+
+ ti_emif_sram_data_virt = gen_pool_alloc(sram_pool_data,
+ sizeof(struct emif_regs_amx3));
+ if (!ti_emif_sram_data_virt) {
+ dev_err(dev, "Unable to allocate data memory from ocmcram\n");
+ return -ENOMEM;
+ goto err_free_sram_code;
+ }
+
+ /* Save physical address to calculate resume offset during pm init */
+ ti_emif_sram_data_phys = gen_pool_virt_to_phys(sram_pool_data,
+ ti_emif_sram_data_virt);
+ /*
+ * These functions are called during suspend path while MMU is
+ * still on so add virtual base to offset for absolute address
+ */
+ pm_functions.save_context =
+ sram_suspend_address((unsigned long)ti_emif_save_context);
+ pm_functions.enter_sr =
+ sram_suspend_address((unsigned long)ti_emif_enter_sr);
+ pm_functions.abort_sr =
+ sram_suspend_address((unsigned long)ti_emif_abort_sr);
+
+ /*
+ * These are called during resume path when MMU is not enabled
+ * so physical address is used instead
+ */
+ pm_functions.restore_context =
+ sram_resume_address((unsigned long)ti_emif_restore_context);
+ pm_functions.exit_sr =
+ sram_resume_address((unsigned long)ti_emif_exit_sr);
+
+ pm_data.regs_virt = (struct emif_regs_amx3 *)ti_emif_sram_data_virt;
+ pm_data.regs_phys = ti_emif_sram_data_phys;
+
+ return 0;
+
+err_free_sram_code:
+ gen_pool_free(sram_pool_code, ti_emif_sram_virt, ti_emif_sram_sz);
+ return ret;
+}
+
+static int ti_emif_push_sram(struct device *dev)
+{
+ int ret;
+
+ ret = sram_exec_copy(sram_pool_code, (void *)ti_emif_sram_virt,
+ &ti_emif_sram, ti_emif_sram_sz);
+ if (ret) {
+ dev_err(dev, "Cannot copy emif code to sram\n");
+ return ret;
+ }
+
+ ret = sram_exec_copy(sram_pool_code,
+ (void *)sram_suspend_address((unsigned long)&ti_emif_pm_sram_data),
+ &pm_data, sizeof(pm_data));
+ if (ret) {
+ dev_err(dev, "Cannot copy emif data to code sram\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Due to Usage Note 3.1.2 "DDR3: JEDEC Compliance for Maximum
+ * Self-Refresh Command Limit" found in AM335x Silicon Errata
+ * (Document SPRZ360F Revised November 2013) we must configure
+ * the self refresh delay timer to 0xA (8192 cycles) to avoid
+ * generating too many refresh command from the EMIF.
+ */
+static void ti_emif_configure_sr_delay(void)
+{
+ writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
+ (pm_data.ti_emif_base_addr_virt +
+ EMIF_POWER_MANAGEMENT_CONTROL));
+
+ writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
+ (pm_data.ti_emif_base_addr_virt +
+ EMIF_POWER_MANAGEMENT_CTRL_SHDW));
+}
+
+/**
+ * ti_emif_copy_pm_function_table - copy mapping of pm funcs in sram
+ * @sram_pool: pointer to struct gen_pool where dst resides
+ * @dst: void * to address that table should be copied
+ *
+ * Returns 0 if success other error code if table is not available
+ */
+int ti_emif_copy_pm_function_table(struct gen_pool *sram_pool, void *dst)
+{
+ int ret;
+
+ if (!ti_emif_sram_virt)
+ return -EINVAL;
+
+ ret = sram_exec_copy(sram_pool, dst, &pm_functions,
+ sizeof(pm_functions));
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ti_emif_copy_pm_function_table);
+
+/**
+ * ti_emif_get_mem_type - return type for memory type in use
+ *
+ * Returns memory type value read from EMIF or error code if fails
+ */
+int ti_emif_get_mem_type(void)
+{
+ unsigned long temp;
+
+ if (!pm_data.ti_emif_base_addr_virt ||
+ IS_ERR(pm_data.ti_emif_base_addr_virt))
+ return -ENODEV;
+
+ temp = readl(pm_data.ti_emif_base_addr_virt +
+ EMIF_SDRAM_CONFIG);
+
+ temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
+ return temp;
+}
+EXPORT_SYMBOL_GPL(ti_emif_get_mem_type);
+
+static const struct of_device_id ti_emif_of_match[] = {
+ { .compatible = "ti,emif-am3352", .data =
+ (void *)EMIF_SRAM_AM33_REG_LAYOUT, },
+ { .compatible = "ti,emif-am4372", .data =
+ (void *)EMIF_SRAM_AM43_REG_LAYOUT, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ti_emif_of_match);
+
+static int ti_emif_probe(struct platform_device *pdev)
+{
+ int ret = -ENODEV;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
+
+ match = of_match_device(ti_emif_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ pm_data.ti_emif_sram_config = (u32)match->data;
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(dev, "pm_runtime_get_sync() failed\n");
+ goto fail_runtime_put;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pm_data.ti_emif_base_addr_virt = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pm_data.ti_emif_base_addr_virt)) {
+ dev_err(dev, "could not ioremap emif mem\n");
+ ret = PTR_ERR(pm_data.ti_emif_base_addr_virt);
+ goto fail_runtime_put;
+ }
+
+ pm_data.ti_emif_base_addr_phys = res->start;
+
+ ti_emif_configure_sr_delay();
+
+ ret = ti_emif_prepare_push_sram(dev);
+ if (ret)
+ goto fail_runtime_put;
+
+ ret = ti_emif_push_sram(dev);
+ if (ret)
+ goto fail_free_sram;
+
+ return 0;
+
+fail_free_sram:
+ ti_emif_free_sram();
+fail_runtime_put:
+ pm_runtime_put_sync(dev);
+ return ret;
+}
+
+static int ti_emif_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
+ ti_emif_free_sram();
+
+ return 0;
+}
+
+static struct platform_driver ti_emif_driver = {
+ .probe = ti_emif_probe,
+ .remove = ti_emif_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(ti_emif_of_match),
+ },
+};
+module_platform_driver(ti_emif_driver);
+
+MODULE_AUTHOR("Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>");
+MODULE_DESCRIPTION("Texas Instruments SRAM EMIF driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S
new file mode 100644
index 000000000000..75888a22eb7f
--- /dev/null
+++ b/drivers/memory/ti-emif-sram-pm.S
@@ -0,0 +1,334 @@
+/*
+ * Low level PM code for TI EMIF
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+#include "emif.h"
+
+#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0
+#define EMIF_POWER_MGMT_SR_TIMER_MASK 0x00f0
+#define EMIF_POWER_MGMT_SELF_REFRESH_MODE 0x0200
+#define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700
+
+#define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT
+#define EMIF_STATUS_READY 0x4
+
+#define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120
+
+#define EMIF_AM437X_REGISTERS 0x1
+
+ .data
+ .align 3
+
+ENTRY(ti_emif_sram)
+
+/*
+ * void ti_emif_save_context(void)
+ *
+ * Used during suspend to save the context of all required EMIF registers
+ * to local memory if the EMIF is going to lose context during the sleep
+ * transition. Operates on the VIRTUAL address of the EMIF.
+ */
+ENTRY(ti_emif_save_context)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
+
+ /* Save EMIF configuration */
+ ldr r1, [r0, #EMIF_SDRAM_CONFIG]
+ str r1, [r2, #EMIF_SDCFG_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+ str r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_TIMING_1]
+ str r1, [r2, #EMIF_TIMING1_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_TIMING_2]
+ str r1, [r2, #EMIF_TIMING2_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_TIMING_3]
+ str r1, [r2, #EMIF_TIMING3_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ str r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+ str r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+ str r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+ str r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET]
+
+ ldr r1, [r0, #EMIF_COS_CONFIG]
+ str r1, [r2, #EMIF_COS_CONFIG_OFFSET]
+
+ ldr r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING]
+ str r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET]
+
+ ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING]
+ str r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET]
+
+ ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING]
+ str r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET]
+
+ ldr r1, [r0, #EMIF_OCP_CONFIG]
+ str r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET]
+
+ ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET]
+ cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT
+ bne emif_skip_save_extra_regs
+
+ ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL]
+ str r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET]
+
+ ldr r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD]
+ str r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET]
+
+ ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING]
+ str r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET]
+
+ ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW]
+ str r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET]
+
+ ldr r1, [r0, #EMIF_DLL_CALIB_CTRL]
+ str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET]
+
+ ldr r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW]
+ str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET]
+
+ /* Loop and save entire block of emif phy regs */
+ mov r5, #0x0
+ add r4, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET
+ add r3, r0, #EMIF_EXT_PHY_CTRL_1
+ddr_phy_ctrl_save:
+ ldr r1, [r3, r5]
+ str r1, [r4, r5]
+ add r5, r5, #0x4
+ cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT
+ bne ddr_phy_ctrl_save
+
+emif_skip_save_extra_regs:
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(ti_emif_save_context)
+
+/*
+ * void ti_emif_restore_context(void)
+ *
+ * Used during resume to restore the context of all required EMIF registers
+ * from local memory after the EMIF has lost context during a sleep transition.
+ * Operates on the PHYSICAL address of the EMIF.
+ */
+ENTRY(ti_emif_restore_context)
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET]
+
+ /* Config EMIF Timings */
+ ldr r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET]
+ str r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+ str r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
+
+ ldr r1, [r2, #EMIF_TIMING1_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_TIMING_1]
+ str r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
+
+ ldr r1, [r2, #EMIF_TIMING2_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_TIMING_2]
+ str r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
+
+ ldr r1, [r2, #EMIF_TIMING3_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_TIMING_3]
+ str r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
+
+ ldr r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+ str r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET]
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_COS_CONFIG_OFFSET]
+ str r1, [r0, #EMIF_COS_CONFIG]
+
+ ldr r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET]
+ str r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING]
+
+ ldr r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET]
+ str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING]
+
+ ldr r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET]
+ str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING]
+
+ ldr r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET]
+ str r1, [r0, #EMIF_OCP_CONFIG]
+
+ ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET]
+ cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT
+ bne emif_skip_restore_extra_regs
+
+ ldr r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET]
+ str r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL]
+
+ ldr r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET]
+ str r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD]
+
+ ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET]
+ str r1, [r0, #EMIF_LPDDR2_NVM_TIMING]
+
+ ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET]
+ str r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW]
+
+ ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET]
+ str r1, [r0, #EMIF_DLL_CALIB_CTRL]
+
+ ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET]
+ str r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW]
+
+ ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+ /* Loop and restore entire block of emif phy regs */
+ mov r5, #0x0
+ /* Load ti_emif_regs_amx3 + EMIF_EXT_PHY_CTRL_VALS_OFFSET for address
+ * to phy register save space
+ */
+ add r3, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET
+ add r4, r0, #EMIF_EXT_PHY_CTRL_1
+ddr_phy_ctrl_restore:
+ ldr r1, [r3, r5]
+ str r1, [r4, r5]
+ add r5, r5, #0x4
+ cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT
+ bne ddr_phy_ctrl_restore
+
+emif_skip_restore_extra_regs:
+ /*
+ * Output impedence calib needed only for DDR3
+ * but since the initial state of this will be
+ * disabled for DDR2 no harm in restoring the
+ * old configuration
+ */
+ ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
+ str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+ /* Write to sdcfg last for DDR2 only */
+ ldr r1, [r2, #EMIF_SDCFG_VAL_OFFSET]
+ and r2, r1, #SDRAM_TYPE_MASK
+ cmp r2, #EMIF_SDCFG_TYPE_DDR2
+ streq r1, [r0, #EMIF_SDRAM_CONFIG]
+
+ mov pc, lr
+ENDPROC(ti_emif_restore_context)
+
+/*
+ * void ti_emif_enter_sr(void)
+ *
+ * Programs the EMIF to tell the SDRAM to enter into self-refresh
+ * mode during a sleep transition. Operates on the VIRTUAL address
+ * of the EMIF.
+ */
+ENTRY(ti_emif_enter_sr)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
+
+ ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(ti_emif_enter_sr)
+
+/*
+ * void ti_emif_exit_sr(void)
+ *
+ * Programs the EMIF to tell the SDRAM to exit self-refresh mode
+ * after a sleep transition. Operates on the PHYSICAL address of
+ * the EMIF.
+ */
+ENTRY(ti_emif_exit_sr)
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET]
+
+ /*
+ * Toggle EMIF to exit refresh mode:
+ * if EMIF lost context, PWR_MGT_CTRL is currently 0, writing disable
+ * (0x0), wont do diddly squat! so do a toggle from SR(0x2) to disable
+ * (0x0) here.
+ * *If* EMIF did not lose context, nothing broken as we write the same
+ * value(0x2) to reg before we write a disable (0x0).
+ */
+ ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ /* Wait for EMIF to become ready */
+1: ldr r1, [r0, #EMIF_STATUS]
+ tst r1, #EMIF_STATUS_READY
+ beq 1b
+
+ mov pc, lr
+ENDPROC(ti_emif_exit_sr)
+
+/*
+ * void ti_emif_abort_sr(void)
+ *
+ * Disables self-refresh after a failed transition to a low-power
+ * state so the kernel can jump back to DDR and follow abort path.
+ * Operates on the VIRTUAL address of the EMIF.
+ */
+ENTRY(ti_emif_abort_sr)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ adr r4, ti_emif_pm_sram_data
+ ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
+ ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
+
+ ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
+ bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+ /* Wait for EMIF to become ready */
+1: ldr r1, [r0, #EMIF_STATUS]
+ tst r1, #EMIF_STATUS_READY
+ beq 1b
+
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(ti_emif_abort_sr)
+
+ .align 3
+ENTRY(ti_emif_pm_sram_data)
+ .space EMIF_PM_DATA_SIZE
+ENTRY(ti_emif_sram_sz)
+ .word . - ti_emif_save_context
diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h
new file mode 100644
index 000000000000..4e15e4cc5363
--- /dev/null
+++ b/include/linux/ti-emif-sram.h
@@ -0,0 +1,143 @@
+/*
+ * TI AM33XX EMIF Routines
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Inc.
+ * Dave Gerlach
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __LINUX_TI_EMIF_H
+#define __LINUX_TI_EMIF_H
+
+#include <linux/kbuild.h>
+#ifndef __ASSEMBLY__
+
+struct emif_regs_amx3 {
+ u32 emif_sdcfg_val;
+ u32 emif_timing1_val;
+ u32 emif_timing2_val;
+ u32 emif_timing3_val;
+ u32 emif_ref_ctrl_val;
+ u32 emif_zqcfg_val;
+ u32 emif_pmcr_val;
+ u32 emif_pmcr_shdw_val;
+ u32 emif_rd_wr_level_ramp_ctrl;
+ u32 emif_rd_wr_exec_thresh;
+ u32 emif_cos_config;
+ u32 emif_priority_to_cos_mapping;
+ u32 emif_connect_id_serv_1_map;
+ u32 emif_connect_id_serv_2_map;
+ u32 emif_ocp_config_val;
+ u32 emif_lpddr2_nvm_tim;
+ u32 emif_lpddr2_nvm_tim_shdw;
+ u32 emif_dll_calib_ctrl_val;
+ u32 emif_dll_calib_ctrl_val_shdw;
+ u32 emif_ddr_phy_ctlr_1;
+ u32 emif_ext_phy_ctrl_vals[120];
+};
+
+struct ti_emif_pm_data {
+ void __iomem *ti_emif_base_addr_virt;
+ phys_addr_t ti_emif_base_addr_phys;
+ unsigned long ti_emif_sram_config;
+ struct emif_regs_amx3 *regs_virt;
+ phys_addr_t regs_phys;
+} __packed;
+
+struct ti_emif_pm_functions {
+ u32 save_context;
+ u32 restore_context;
+ u32 enter_sr;
+ u32 exit_sr;
+ u32 abort_sr;
+} __packed;
+
+extern inline void ti_emif_offsets(void)
+{
+ DEFINE(EMIF_SDCFG_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_sdcfg_val));
+ DEFINE(EMIF_TIMING1_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_timing1_val));
+ DEFINE(EMIF_TIMING2_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_timing2_val));
+ DEFINE(EMIF_TIMING3_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_timing3_val));
+ DEFINE(EMIF_REF_CTRL_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ref_ctrl_val));
+ DEFINE(EMIF_ZQCFG_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_zqcfg_val));
+ DEFINE(EMIF_PMCR_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_pmcr_val));
+ DEFINE(EMIF_PMCR_SHDW_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_pmcr_shdw_val));
+ DEFINE(EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_rd_wr_level_ramp_ctrl));
+ DEFINE(EMIF_RD_WR_EXEC_THRESH_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_rd_wr_exec_thresh));
+ DEFINE(EMIF_COS_CONFIG_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_cos_config));
+ DEFINE(EMIF_PRIORITY_TO_COS_MAPPING_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_priority_to_cos_mapping));
+ DEFINE(EMIF_CONNECT_ID_SERV_1_MAP_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_connect_id_serv_1_map));
+ DEFINE(EMIF_CONNECT_ID_SERV_2_MAP_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_connect_id_serv_2_map));
+ DEFINE(EMIF_OCP_CONFIG_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ocp_config_val));
+ DEFINE(EMIF_LPDDR2_NVM_TIM_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_lpddr2_nvm_tim));
+ DEFINE(EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_lpddr2_nvm_tim_shdw));
+ DEFINE(EMIF_DLL_CALIB_CTRL_VAL_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_dll_calib_ctrl_val));
+ DEFINE(EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_dll_calib_ctrl_val_shdw));
+ DEFINE(EMIF_DDR_PHY_CTLR_1_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ddr_phy_ctlr_1));
+ DEFINE(EMIF_EXT_PHY_CTRL_VALS_OFFSET,
+ offsetof(struct emif_regs_amx3, emif_ext_phy_ctrl_vals));
+ DEFINE(EMIF_REGS_AMX3_SIZE, sizeof(struct emif_regs_amx3));
+
+ BLANK();
+
+ DEFINE(EMIF_PM_BASE_ADDR_VIRT_OFFSET,
+ offsetof(struct ti_emif_pm_data, ti_emif_base_addr_virt));
+ DEFINE(EMIF_PM_BASE_ADDR_PHYS_OFFSET,
+ offsetof(struct ti_emif_pm_data, ti_emif_base_addr_phys));
+ DEFINE(EMIF_PM_CONFIG_OFFSET,
+ offsetof(struct ti_emif_pm_data, ti_emif_sram_config));
+ DEFINE(EMIF_PM_REGS_VIRT_OFFSET,
+ offsetof(struct ti_emif_pm_data, regs_virt));
+ DEFINE(EMIF_PM_REGS_PHYS_OFFSET,
+ offsetof(struct ti_emif_pm_data, regs_phys));
+ DEFINE(EMIF_PM_DATA_SIZE, sizeof(struct ti_emif_pm_data));
+
+ BLANK();
+
+ DEFINE(EMIF_PM_SAVE_CONTEXT_OFFSET,
+ offsetof(struct ti_emif_pm_functions, save_context));
+ DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET,
+ offsetof(struct ti_emif_pm_functions, restore_context));
+ DEFINE(EMIF_PM_ENTER_SR_OFFSET,
+ offsetof(struct ti_emif_pm_functions, enter_sr));
+ DEFINE(EMIF_PM_EXIT_SR_OFFSET,
+ offsetof(struct ti_emif_pm_functions, exit_sr));
+ DEFINE(EMIF_PM_ABORT_SR_OFFSET,
+ offsetof(struct ti_emif_pm_functions, abort_sr));
+ DEFINE(EMIF_PM_FUNCTIONS_SIZE, sizeof(struct ti_emif_pm_functions));
+}
+
+struct gen_pool;
+
+int ti_emif_copy_pm_function_table(struct gen_pool *sram_pool, void *dst);
+int ti_emif_get_mem_type(void);
+
+#endif
+#endif /* __LINUX_TI_EMIF_H */
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v2,1/3] meson_uart: expose CLKID_UARTx
From: Martin Blumenstingl @ 2017-03-28 21:24 UTC (permalink / raw)
To: Jerome Brunet
Cc: devicetree, mturquette, sboyd, linux-kernel, Helmut Klein,
linux-amlogic, linux-clk, linux-arm-kernel
In-Reply-To: <1490728490.20764.8.camel@baylibre.com>
Hi Jerome,
On Tue, Mar 28, 2017 at 9:14 PM, Jerome Brunet <jbrunet@baylibre.com> wrote:
> On Tue, 2017-03-28 at 20:18 +0200, Helmut Klein wrote:
>> i know for sure that the bluetooth chip of my system is connected to
>> uart_A. so this clock must be exposed.
>>
>> i don't know if the other 2 uarts are used on other hardware. so i will
>> remove them from my patch.
>
> What I meant is device trees "upstream".
> I would expect such patch as part of a series to add support for your board in
> device-tree, with its bluetooth chipset.
are you sure about this? Helmut is configuring the core clock of the
UART controller(s) here. we have the same thing for many other drivers
as well (MMC, SAR ADC, I2C, SPI, ethernet, you name it...) - these
clocks are not part of a device specific .dts but rather the SoC
specific dts (for example meson-gxbb.dtsi - because these clocks are
not board specific).
I guess most boards are not affected because the bootloader simply
enables the UART0 core/gate clock and keeps it enabled when booting
the kernel. additionally our clock gates are marked with
CLK_IGNORE_UNUSED so if the bootloader keeps the gates enabled then
we're not disabling it either.
> I think it would better to drop this patch from the series.
> You can either keep it for your personal work, or send it again when upstreaming
> the support for your board and/or add the support for the bluetooth chip.
if we decide to pass the core/gate clock directly in SoC.dtsi then we
should think about doing it for all three non-AO UARTs (uart_a, uart_b
and uart_c).
we can test uart_b on GPIODV_24 and GPIODV_25 on the Khadas VIM board
for example (pins 22 and 23 on the header, default mode of these pins
is i2c_sck_a and i2c_sda_a, but we can re-configure it).
uart_c unfortunately cannot be tested on the Khadas VIM board since
it's only routed to GPIOX_8 and GPIOX_9 which are hard-wired to the
bluetooth module's PCM pins (BTPCM_DOUT and BTPCM_DIN).
for Helmut this would mean that instead of dropping this patch (or
dropping CLKID_UART1 and CLKID_UART2 from this patch) he would rather
have to *add* another patch (for meson-gxbb.dtsi and meson-gxl.dtsi)
which passes the core clocks to the corresponding UART controllers
(similar to the CLKID_SD_EMMC_ clocks).
Regards,
Martin
[0] http://lxr.free-electrons.com/source/drivers/clk/meson/clkc.h?v=4.10#L110
^ permalink raw reply
* Re: [RFC PATCH 1/2] dt-bindings: mtd: Add Cavium SOCs NAND bindings
From: Jan Glauber @ 2017-03-28 21:30 UTC (permalink / raw)
To: Boris Brezillon
Cc: Richard Weinberger, David Woodhouse, Brian Norris, Marek Vasut,
Cyrille Pitchen, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
Rob Herring, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170328222035.29f4ed31@bbrezillon>
On Tue, Mar 28, 2017 at 10:20:35PM +0200, Boris Brezillon wrote:
> Hi Jan,
>
> On Mon, 27 Mar 2017 18:05:23 +0200
> Jan Glauber <jglauber-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org> wrote:
>
> > Add device tree binding description for Cavium SOC nand flash controller.
> >
> > CC: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > CC: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> > CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >
> > Signed-off-by: Jan Glauber <jglauber-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> > ---
> > .../devicetree/bindings/mtd/cavium_nand.txt | 32 ++++++++++++++++++++++
> > 1 file changed, 32 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/mtd/cavium_nand.txt
> >
> > diff --git a/Documentation/devicetree/bindings/mtd/cavium_nand.txt b/Documentation/devicetree/bindings/mtd/cavium_nand.txt
> > new file mode 100644
> > index 0000000..4698d1f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mtd/cavium_nand.txt
> > @@ -0,0 +1,32 @@
> > +* Cavium NAND controller
> > +
> > +Required properties:
> > +
> > +- compatible: should be "cavium,cn8xxx-nand"
> > +- reg: PCI devfn
> > +- clocks: must contain system clock
> > +- #address-cells: <1>
> > +- #size-cells: <0>
> > +
> > +The nand flash controller may contain up to 8 subnodes representing
> > +NAND flash chips. Their properties are as follows.
> > +
> > +Required properties:
> > +- compatible: should be "cavium,nandcs"
>
> Why do you need a compatible here? All sub-nodes should be representing
> NAND devices connected to the NAND controller. If you need an extra
> subnode to represent something that is not a NAND device, then it should
> not have a reg property, so testing if reg is present to detect if the
> subnode is reprensenting a NAND device should be enough.
>
> Am I missing something?
Hi Boris,
You're right. We don't need or check this compatible. The chip type
which would make more sense than what I used above is detected via ONFI,
so I can just remove the compatible string.
> > +- reg: a single integer representing the chip-select number
> > +- nand-ecc-mode: see nand.txt
> > +
> > +Example:
> > +
> > +nfc: nand@b,0 {
>
> ^ nand-controller@xxx
OK.
> > + compatible = "cavium,cn8xxx-nand";
> > + reg = <0x5800 0 0 0 0>;
> > + clocks = <&sclk>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + nand@1 {
> > + compatible = "cavium,nandcs";
> > + reg = <1>;
> > + nand-ecc-mode = "on-die";
> > +};
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 2/2] phy: meson: add USB2 PHY support for Meson GXL and GXM
From: Martin Blumenstingl @ 2017-03-28 21:33 UTC (permalink / raw)
To: kishon-l0cyMroinI0,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
hendrik-MJglGmTD+GWCT0AhDRffsw, Martin Blumenstingl,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, carlo-KA+7E9HrN00dnm+yROfE0A,
khilman-rdvid1DuHRBWk0Htik3J/w
In-Reply-To: <20170318130013.20771-3-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Hi Kishon,
On Sat, Mar 18, 2017 at 2:00 PM, Martin Blumenstingl
<martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:
> This adds a new driver for the USB2 PHYs found on Meson GXL and GXM SoCs
> (both SoCs are using the same USB PHY register layout).
>
> The USB2 PHY is a simple PHY which only has a few registers to configure
> the mode (host/device) and a reset register (to enable/disable the PHY).
>
> Unfortunately there are no datasheets available for this PHY. The driver
> was written by reading the code from Amlogic's GPL kernel sources and
> by analyzing the registers on an actual GXL and GXM device running the
> kernel that was shipped on the boards I have.
gentle ping - did you have time to review this patch in v2 yet?
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
> ---
> drivers/phy/Kconfig | 14 ++
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-meson-gxl-usb2.c | 273 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 288 insertions(+)
> create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index dc5277ad1b5a..2573e139fd17 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -510,6 +510,19 @@ config PHY_MESON8B_USB2
> and GXBB SoCs.
> If unsure, say N.
>
> +config PHY_MESON_GXL_USB
> + tristate "Meson GXL and GXM USB2 PHY drivers"
> + default ARCH_MESON
> + depends on OF && (ARCH_MESON || COMPILE_TEST)
> + depends on USB_SUPPORT
> + select USB_COMMON
> + select GENERIC_PHY
> + select REGMAP_MMIO
> + help
> + Enable this to support the Meson USB2 PHYs found in Meson
> + GXL and GXM SoCs.
> + If unsure, say N.
> +
> config PHY_NSP_USB3
> tristate "Broadcom NorthStar plus USB3 PHY driver"
> depends on OF && (ARCH_BCM_NSP || COMPILE_TEST)
> @@ -518,4 +531,5 @@ config PHY_NSP_USB3
> help
> Enable this to support the Broadcom Northstar plus USB3 PHY.
> If unsure, say N.
> +
> endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index e7b0feb1e125..e680b856e38e 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -62,4 +62,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
> obj-$(CONFIG_PHY_NSP_USB3) += phy-bcm-nsp-usb3.o
> diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
> new file mode 100644
> index 000000000000..4bf646a52c45
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb2.c
> @@ -0,0 +1,273 @@
> +/*
> + * Meson GXL and GXM USB2 PHY driver
> + *
> + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.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.
> + *
> + * 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/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +
> +/* bits [31:27] are read-only */
> +#define U2P_R0 0x0
> + #define U2P_R0_BYPASS_SEL BIT(0)
> + #define U2P_R0_BYPASS_DM_EN BIT(1)
> + #define U2P_R0_BYPASS_DP_EN BIT(2)
> + #define U2P_R0_TXBITSTUFF_ENH BIT(3)
> + #define U2P_R0_TXBITSTUFF_EN BIT(4)
> + #define U2P_R0_DM_PULLDOWN BIT(5)
> + #define U2P_R0_DP_PULLDOWN BIT(6)
> + #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
> + #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
> + #define U2P_R0_ADP_PRB_EN BIT(9)
> + #define U2P_R0_ADP_DISCHARGE BIT(10)
> + #define U2P_R0_ADP_CHARGE BIT(11)
> + #define U2P_R0_DRV_VBUS BIT(12)
> + #define U2P_R0_ID_PULLUP BIT(13)
> + #define U2P_R0_LOOPBACK_EN_B BIT(14)
> + #define U2P_R0_OTG_DISABLE BIT(15)
> + #define U2P_R0_COMMON_ONN BIT(16)
> + #define U2P_R0_FSEL_MASK GENMASK(19, 17)
> + #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
> + #define U2P_R0_POWER_ON_RESET BIT(22)
> + #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
> + #define U2P_R0_ID_SET_ID_DQ BIT(25)
> + #define U2P_R0_ATE_RESET BIT(26)
> + #define U2P_R0_FSV_MINUS BIT(27)
> + #define U2P_R0_FSV_PLUS BIT(28)
> + #define U2P_R0_BYPASS_DM_DATA BIT(29)
> + #define U2P_R0_BYPASS_DP_DATA BIT(30)
> +
> +#define U2P_R1 0x4
> + #define U2P_R1_BURN_IN_TEST BIT(0)
> + #define U2P_R1_ACA_ENABLE BIT(1)
> + #define U2P_R1_DCD_ENABLE BIT(2)
> + #define U2P_R1_VDAT_SRC_EN_B BIT(3)
> + #define U2P_R1_VDAT_DET_EN_B BIT(4)
> + #define U2P_R1_CHARGES_SEL BIT(5)
> + #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
> + #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
> + #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
> + #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
> + #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
> + #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
> + #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
> + #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
> + #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
> +
> +/* bits [31:14] are read-only */
> +#define U2P_R2 0x8
> + #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
> + #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
> + #define U2P_R2_ADDR_MASK GENMASK(11, 8)
> + #define U2P_R2_DATA_OUT_SEL BIT(12)
> + #define U2P_R2_CLK BIT(13)
> + #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
> + #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
> + #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
> + #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
> + #define U2P_R2_ACA_PIN_GND BIT(21)
> + #define U2P_R2_ACA_PIN_FLOAT BIT(22)
> + #define U2P_R2_CHARGE_DETECT BIT(23)
> + #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
> + #define U2P_R2_ADP_PROBE BIT(25)
> + #define U2P_R2_ADP_SENSE BIT(26)
> + #define U2P_R2_SESSION_END BIT(27)
> + #define U2P_R2_VBUS_VALID BIT(28)
> + #define U2P_R2_B_VALID BIT(29)
> + #define U2P_R2_A_VALID BIT(30)
> + #define U2P_R2_ID_DIG BIT(31)
> +
> +#define U2P_R3 0xc
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb2_priv {
> + struct regmap *regmap;
> + enum phy_mode mode;
> + int is_enabled;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
> + .reg_bits = 8,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = U2P_R3,
> +};
> +
> +static int phy_meson_gxl_usb2_reset(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + if (priv->is_enabled) {
> + /* reset the PHY and wait until settings are stabilized */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> + udelay(RESET_COMPLETE_TIME);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + 0);
> + udelay(RESET_COMPLETE_TIME);
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + switch (mode) {
> + case PHY_MODE_USB_HOST:
> + case PHY_MODE_USB_OTG:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + U2P_R0_DM_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + U2P_R0_DP_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
> + break;
> +
> + case PHY_MODE_USB_DEVICE:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
> + U2P_R0_ID_PULLUP);
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + phy_meson_gxl_usb2_reset(phy);
> +
> + priv->mode = mode;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + priv->is_enabled = 0;
> +
> + /* power off the PHY by putting it into reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> + int ret;
> +
> + priv->is_enabled = 1;
> +
> + /* power on the PHY by taking it out of reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> +
> + ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
> + if (ret) {
> + phy_meson_gxl_usb2_power_off(phy);
> +
> + dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
> + priv->mode);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb2_ops = {
> + .power_on = phy_meson_gxl_usb2_power_on,
> + .power_off = phy_meson_gxl_usb2_power_off,
> + .set_mode = phy_meson_gxl_usb2_set_mode,
> + .reset = phy_meson_gxl_usb2_reset,
> + .owner = THIS_MODULE,
> +};
> +
> +static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct phy_provider *phy_provider;
> + struct resource *res;
> + struct phy_meson_gxl_usb2_priv *priv;
> + struct phy *phy;
> + void __iomem *base;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, priv);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + switch (of_usb_get_dr_mode_by_phy(dev->of_node, -1)) {
> + case USB_DR_MODE_PERIPHERAL:
> + priv->mode = PHY_MODE_USB_DEVICE;
> + break;
> + case USB_DR_MODE_OTG:
> + priv->mode = PHY_MODE_USB_OTG;
> + break;
> + case USB_DR_MODE_HOST:
> + default:
> + priv->mode = PHY_MODE_USB_HOST;
> + break;
> + }
> +
> + priv->regmap = devm_regmap_init_mmio(dev, base,
> + &phy_meson_gxl_usb2_regmap_conf);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
> + if (IS_ERR(phy)) {
> + dev_err(dev, "failed to create PHY\n");
> + return PTR_ERR(phy);
> + }
> +
> + phy_set_drvdata(phy, priv);
> +
> + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
> + { .compatible = "amlogic,meson-gxl-usb2-phy", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
> +
> +static struct platform_driver phy_meson_gxl_usb2_driver = {
> + .probe = phy_meson_gxl_usb2_probe,
> + .driver = {
> + .name = "phy-meson-gxl-usb2",
> + .of_match_table = phy_meson_gxl_usb2_of_match,
> + },
> +};
> +module_platform_driver(phy_meson_gxl_usb2_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>");
> +MODULE_DESCRIPTION("Meson GXL and GXM USB2 PHY driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.12.0
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 0/8] bus: brcmstb_gisb: add support for GISBv7 arbiter
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland-5wv7dgnIgG8
Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, catalin.marinas-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
gregory.0xf0-Re5JQEeQqe8AvxtiuMwx3w,
f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
opendmb-Re5JQEeQqe8AvxtiuMwx3w,
wangkefeng.wang-hv44wF8Li93QT0dZR+AlfA, james.morse-5wv7dgnIgG8,
mingo-DgEjT+Ai2ygdnm+yROfE0A,
sandeepa.s.prabhu-Re5JQEeQqe8AvxtiuMwx3w,
shijie.huang-5wv7dgnIgG8, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
treding-DDmLM1+adcrQT0dZR+AlfA, jonathanh-DDmLM1+adcrQT0dZR+AlfA,
olof-nZhT3qVonbNeoWH0uzbU5w, mirza.krak-Re5JQEeQqe8AvxtiuMwx3w,
suzuki.poulose-5wv7dgnIgG8, bgolaszewski-rdvid1DuHRBWk0Htik3J/w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
This patch set contains changes to enable the GISB arbiter driver
on the latest ARM64 architecture Set-Top Box chips from Broadcom.
This driver relies on being able to hook the abort handlers of
the processor core that are triggered by bus error signals
generated by the GISB bus arbiter hardware found in BCM7XXX chips.
The first two patches are based on the arm64/for-next/core
branch to enable this functionality for the arm64 architecture.
The remaining patches correct some issues with the existing driver,
add the ARM64 architecture specific support to the driver, and
finally add the new register map for the GISBv7 hardware first
appearing in the BCM7278 device.
Changes since v1 at [1]:
- Removed code associated with hooking SError handling in favor
of a registered notifier (Thanks Mark!)
- Removed an unnecessary explicit cast (Thanks Gregory!)
[1] https://lkml.org/lkml/2017/3/24/413
Doug Berger (6):
arm64: mm: mark fault_info __ro_after_init
bus: brcmstb_gisb: Use register offsets with writes too
bus: brcmstb_gisb: Correct hooking of ARM aborts
bus: brcmstb_gisb: correct support for 64-bit address output
bus: brcmstb_gisb: add notifier handling
bus: brcmstb_gisb: update to support new revision
Florian Fainelli (2):
arm64: mm: Allow installation of memory abort handlers
bus: brcmstb_gisb: Add ARM64 support
.../devicetree/bindings/bus/brcm,gisb-arb.txt | 3 +-
arch/arm64/include/asm/system_misc.h | 3 +
arch/arm64/mm/fault.c | 17 +++-
drivers/bus/Kconfig | 2 +-
drivers/bus/brcmstb_gisb.c | 111 ++++++++++++++++-----
5 files changed, 106 insertions(+), 30 deletions(-)
--
2.12.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 1/8] arm64: mm: Allow installation of memory abort handlers
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
From: Florian Fainelli <f.fainelli@gmail.com>
Similarly to what the ARM/Linux kernel provides, add a hook_fault_code()
function which allows drivers or other parts of the kernel to install
custom memory abort handlers. This is useful when a given SoC's busing
does not propagate the exact faulting physical address, but there is a
way to read it through e.g: a special arbiter driver.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm64/include/asm/system_misc.h | 3 +++
arch/arm64/mm/fault.c | 15 ++++++++++++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index bc812435bc76..e05f5b8c7c1c 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -38,6 +38,9 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
struct pt_regs *),
int sig, int code, const char *name);
+void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
+ struct pt_regs *),
+ int sig, int code, const char *name);
struct mm_struct;
extern void show_pte(struct mm_struct *mm, unsigned long addr);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 4bf899fb451b..cdf1260f1005 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -488,7 +488,7 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
return 1;
}
-static const struct fault_info {
+static struct fault_info {
int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs);
int sig;
int code;
@@ -560,6 +560,19 @@ static const struct fault_info {
{ do_bad, SIGBUS, 0, "unknown 63" },
};
+void __init hook_fault_code(int nr,
+ int (*fn)(unsigned long, unsigned int, struct pt_regs *),
+ int sig, int code, const char *name)
+{
+ BUG_ON(nr < 0 || nr >= ARRAY_SIZE(fault_info));
+
+ fault_info[nr].fn = fn;
+ fault_info[nr].sig = sig;
+ fault_info[nr].code = code;
+ fault_info[nr].name = name;
+}
+
+
static const char *fault_name(unsigned int esr)
{
const struct fault_info *inf = fault_info + (esr & 63);
--
2.12.0
^ permalink raw reply related
* [PATCH v2 2/8] arm64: mm: mark fault_info __ro_after_init
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
The fault_info table must be made writeable to allow installation
of custom memory abort handlers, but it can be made read-only
after initialization to provide some protection.
Signed-off-by: Doug Berger <opendmb@gmail.com>
---
arch/arm64/mm/fault.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index cdf1260f1005..43319ed58a47 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -493,7 +493,7 @@ static struct fault_info {
int sig;
int code;
const char *name;
-} fault_info[] = {
+} fault_info[] __ro_after_init = {
{ do_bad, SIGBUS, 0, "ttbr address size fault" },
{ do_bad, SIGBUS, 0, "level 1 address size fault" },
{ do_bad, SIGBUS, 0, "level 2 address size fault" },
--
2.12.0
^ permalink raw reply related
* [PATCH v2 3/8] bus: brcmstb_gisb: Use register offsets with writes too
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
This commit corrects the bug introduced in commit f80835875d3d
("bus: brcmstb_gisb: Look up register offsets in a table") such
that gisb_write() translates the register enumeration into an
offset from the base address for writes as well as reads.
Fixes: f80835875d3d ("bus: brcmstb_gisb: Look up register offsets in a table")
Signed-off-by: Doug Berger <opendmb@gmail.com>
Acked-by: Gregory Fong <gregory.0xf0@gmail.com>
---
drivers/bus/brcmstb_gisb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 72fe0a5a8bf3..a94598d0945a 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
*
* 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
@@ -127,9 +127,9 @@ static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
return;
if (gdev->big_endian)
- iowrite32be(val, gdev->base + reg);
+ iowrite32be(val, gdev->base + offset);
else
- iowrite32(val, gdev->base + reg);
+ iowrite32(val, gdev->base + offset);
}
static ssize_t gisb_arb_get_timeout(struct device *dev,
--
2.12.0
^ permalink raw reply related
* [PATCH v2 4/8] bus: brcmstb_gisb: Correct hooking of ARM aborts
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland-5wv7dgnIgG8
Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, catalin.marinas-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
gregory.0xf0-Re5JQEeQqe8AvxtiuMwx3w,
f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
opendmb-Re5JQEeQqe8AvxtiuMwx3w,
wangkefeng.wang-hv44wF8Li93QT0dZR+AlfA, james.morse-5wv7dgnIgG8,
mingo-DgEjT+Ai2ygdnm+yROfE0A,
sandeepa.s.prabhu-Re5JQEeQqe8AvxtiuMwx3w,
shijie.huang-5wv7dgnIgG8, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
treding-DDmLM1+adcrQT0dZR+AlfA, jonathanh-DDmLM1+adcrQT0dZR+AlfA,
olof-nZhT3qVonbNeoWH0uzbU5w, mirza.krak-Re5JQEeQqe8AvxtiuMwx3w,
suzuki.poulose-5wv7dgnIgG8, bgolaszewski-rdvid1DuHRBWk0Htik3J/w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170328213431.10904-1-opendmb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
The fault status reporting in the FSR registers is different depending
on whether the Long Physical Address Extension (LPAE) is being used.
This commit corrects the registerring of fault handlers for arm
architecture kernels when the LPAE is enabled. It also forces the
handler to report that the abort exception was unhandled so that the
appropriate signal is sent to the offending user process.
Signed-off-by: Doug Berger <opendmb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/bus/brcmstb_gisb.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index a94598d0945a..9eba0143f1a4 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -225,27 +225,29 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
- int ret = 0;
struct brcmstb_gisb_arb_device *gdev;
/* iterate over each GISB arb registered handlers */
list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
- ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error");
+ brcmstb_gisb_arb_decode_addr(gdev, "bus error");
+
+#if !defined(CONFIG_ARM_LPAE)
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
*/
if (fsr & (1 << 10))
regs->ARM_pc += 4;
+#endif
- return ret;
+ /* Always report unhandled exception */
+ return 1;
}
#endif
#ifdef CONFIG_MIPS
static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
{
- int ret = 0;
struct brcmstb_gisb_arb_device *gdev;
u32 cap_status;
@@ -258,7 +260,7 @@ static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
goto out;
}
- ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error");
+ brcmstb_gisb_arb_decode_addr(gdev, "bus error");
}
out:
return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
@@ -379,9 +381,16 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);
#ifdef CONFIG_ARM
+#ifdef CONFIG_ARM_LPAE
+ hook_fault_code(16, brcmstb_bus_error_handler, SIGBUS, 0,
+ "synchronous external abort");
+ hook_fault_code(17, brcmstb_bus_error_handler, SIGBUS, 0,
+ "asynchronous external abort");
+#else
hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
"imprecise external abort");
#endif
+#endif /* CONFIG_ARM */
#ifdef CONFIG_MIPS
board_be_handler = brcmstb_bus_error_handler;
#endif
--
2.12.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 5/8] bus: brcmstb_gisb: correct support for 64-bit address output
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: wangkefeng.wang, catalin.marinas, linus.walleij, will.deacon,
mingo, f.fainelli, jonathanh, bgolaszewski,
bcm-kernel-feedback-list, shijie.huang, opendmb, treding,
devicetree, suzuki.poulose, robh+dt, gregory.0xf0,
sandeepa.s.prabhu, linux-arm-kernel, mirza.krak, linux-kernel,
james.morse, olof, computersforpeace
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
The GISB bus can support addresses beyond 32-bits. So this commit
corrects support for reading a captured 64-bit address into a 64-bit
variable by obtaining the high bits from the ARB_ERR_CAP_HI_ADDR
register (when present) and then outputting the full 64-bit value.
It also removes unused definitions.
Fixes: 44127b771d9c ("bus: add Broadcom GISB bus arbiter timeout/error handler")
Signed-off-by: Doug Berger <opendmb@gmail.com>
Acked-by: Gregory Fong <gregory.0xf0@gmail.com>
---
drivers/bus/brcmstb_gisb.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 9eba0143f1a4..edf79432f899 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -37,8 +37,6 @@
#define ARB_ERR_CAP_CLEAR (1 << 0)
#define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12)
#define ARB_ERR_CAP_STATUS_TEA (1 << 11)
-#define ARB_ERR_CAP_STATUS_BS_SHIFT (1 << 2)
-#define ARB_ERR_CAP_STATUS_BS_MASK 0x3c
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
@@ -47,7 +45,6 @@ enum {
ARB_ERR_CAP_CLR,
ARB_ERR_CAP_HI_ADDR,
ARB_ERR_CAP_ADDR,
- ARB_ERR_CAP_DATA,
ARB_ERR_CAP_STATUS,
ARB_ERR_CAP_MASTER,
};
@@ -57,7 +54,6 @@ static const int gisb_offsets_bcm7038[] = {
[ARB_ERR_CAP_CLR] = 0x0c4,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0c8,
- [ARB_ERR_CAP_DATA] = 0x0cc,
[ARB_ERR_CAP_STATUS] = 0x0d0,
[ARB_ERR_CAP_MASTER] = -1,
};
@@ -67,7 +63,6 @@ static const int gisb_offsets_bcm7400[] = {
[ARB_ERR_CAP_CLR] = 0x0c8,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0cc,
- [ARB_ERR_CAP_DATA] = 0x0d0,
[ARB_ERR_CAP_STATUS] = 0x0d4,
[ARB_ERR_CAP_MASTER] = 0x0d8,
};
@@ -77,7 +72,6 @@ static const int gisb_offsets_bcm7435[] = {
[ARB_ERR_CAP_CLR] = 0x168,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x16c,
- [ARB_ERR_CAP_DATA] = 0x170,
[ARB_ERR_CAP_STATUS] = 0x174,
[ARB_ERR_CAP_MASTER] = 0x178,
};
@@ -87,7 +81,6 @@ static const int gisb_offsets_bcm7445[] = {
[ARB_ERR_CAP_CLR] = 0x7e4,
[ARB_ERR_CAP_HI_ADDR] = 0x7e8,
[ARB_ERR_CAP_ADDR] = 0x7ec,
- [ARB_ERR_CAP_DATA] = 0x7f0,
[ARB_ERR_CAP_STATUS] = 0x7f4,
[ARB_ERR_CAP_MASTER] = 0x7f8,
};
@@ -109,9 +102,13 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
{
int offset = gdev->gisb_offsets[reg];
- /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
- if (offset == -1)
- return 1;
+ if (offset < 0) {
+ /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
+ if (reg == ARB_ERR_CAP_MASTER)
+ return 1;
+ else
+ return 0;
+ }
if (gdev->big_endian)
return ioread32be(gdev->base + offset);
@@ -119,6 +116,16 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
return ioread32(gdev->base + offset);
}
+static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
+{
+ u64 value;
+
+ value = gisb_read(gdev, ARB_ERR_CAP_ADDR);
+ value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
+
+ return value;
+}
+
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
{
int offset = gdev->gisb_offsets[reg];
@@ -185,7 +192,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
const char *reason)
{
u32 cap_status;
- unsigned long arb_addr;
+ u64 arb_addr;
u32 master;
const char *m_name;
char m_fmt[11];
@@ -197,10 +204,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
return 1;
/* Read the address and master */
- arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
-#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
- arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
-#endif
+ arb_addr = gisb_read_address(gdev);
master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
m_name = brcmstb_gisb_master_to_str(gdev, master);
@@ -209,7 +213,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
m_name = m_fmt;
}
- pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n",
+ pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
__func__, reason, arb_addr,
cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
--
2.12.0
^ permalink raw reply related
* [PATCH v2 6/8] bus: brcmstb_gisb: Add ARM64 support
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
From: Florian Fainelli <f.fainelli@gmail.com>
Hook to the ARM64 data abort exception #16: synchronous external
abort, which is how the GISB errors will be funneled back to the
ARM64 CPU in case of problems
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/bus/Kconfig | 2 +-
drivers/bus/brcmstb_gisb.c | 15 ++++++++++++---
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 0a52da439abf..d2a5f1184022 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -57,7 +57,7 @@ config ARM_CCN
config BRCMSTB_GISB_ARB
bool "Broadcom STB GISB bus arbiter"
- depends on ARM || MIPS
+ depends on ARM || ARM64 || MIPS
default ARCH_BRCMSTB || BMIPS_GENERIC
help
Driver for the Broadcom Set Top Box System-on-a-chip internal bus
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index edf79432f899..500b6bb5c739 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -30,6 +30,11 @@
#include <asm/signal.h>
#endif
+#ifdef CONFIG_ARM64
+#include <asm/signal.h>
+#include <asm/system_misc.h>
+#endif
+
#ifdef CONFIG_MIPS
#include <asm/traps.h>
#endif
@@ -225,7 +230,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
return 0;
}
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
@@ -235,7 +240,7 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
brcmstb_gisb_arb_decode_addr(gdev, "bus error");
-#if !defined(CONFIG_ARM_LPAE)
+#if defined(CONFIG_ARM) && !defined(CONFIG_ARM_LPAE)
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
@@ -247,7 +252,7 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
/* Always report unhandled exception */
return 1;
}
-#endif
+#endif /* CONFIG_ARM || CONFIG_ARM64 */
#ifdef CONFIG_MIPS
static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
@@ -395,6 +400,10 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
"imprecise external abort");
#endif
#endif /* CONFIG_ARM */
+#ifdef CONFIG_ARM64
+ hook_fault_code(16, brcmstb_bus_error_handler, SIGBUS, 0,
+ "synchronous external abort");
+#endif
#ifdef CONFIG_MIPS
board_be_handler = brcmstb_bus_error_handler;
#endif
--
2.12.0
^ permalink raw reply related
* [PATCH v2 7/8] bus: brcmstb_gisb: add notifier handling
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: wangkefeng.wang, catalin.marinas, linus.walleij, will.deacon,
mingo, f.fainelli, jonathanh, bgolaszewski,
bcm-kernel-feedback-list, shijie.huang, opendmb, treding,
devicetree, suzuki.poulose, robh+dt, gregory.0xf0,
sandeepa.s.prabhu, linux-arm-kernel, mirza.krak, linux-kernel,
james.morse, olof, computersforpeace
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
Check for GISB arbitration errors through a chained notifier
when a process dies or a kernel panic occurs. This allows a
meaningful diagnostic message to occur along with other
diagnostic information.
Notably writes to a bad GISB address on an ARM64 architecture
kernel cause unrecoverable SError aborts and this allows the
cause of the abort to be seen.
Signed-off-by: Doug Berger <opendmb@gmail.com>
---
drivers/bus/brcmstb_gisb.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 500b6bb5c739..774729002b8c 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -24,6 +24,8 @@
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/pm.h>
+#include <linux/kernel.h>
+#include <linux/kdebug.h>
#ifdef CONFIG_ARM
#include <asm/bug.h>
@@ -290,6 +292,25 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * Dump out gisb errors on die or panic.
+ */
+static int dump_gisb_error(struct notifier_block *self, unsigned long v,
+ void *p)
+{
+ struct brcmstb_gisb_arb_device *gdev;
+
+ /* iterate over each GISB arb registered handlers */
+ list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
+ brcmstb_gisb_arb_decode_addr(gdev, "async abort");
+
+ return 0;
+}
+
+static struct notifier_block gisb_error_notifier = {
+ .notifier_call = dump_gisb_error,
+};
+
static DEVICE_ATTR(gisb_arb_timeout, S_IWUSR | S_IRUGO,
gisb_arb_get_timeout, gisb_arb_set_timeout);
@@ -408,6 +429,12 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
board_be_handler = brcmstb_bus_error_handler;
#endif
+ if (list_is_singular(&brcmstb_gisb_arb_device_list)) {
+ register_die_notifier(&gisb_error_notifier);
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &gisb_error_notifier);
+ }
+
dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
gdev->base, timeout_irq, tea_irq);
--
2.12.0
^ permalink raw reply related
* [PATCH v2 8/8] bus: brcmstb_gisb: update to support new revision
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
To: mark.rutland
Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>
The 7278 introduces a new version of this core. This
commit adds support for that revision.
Signed-off-by: Doug Berger <opendmb@gmail.com>
---
Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt | 3 ++-
drivers/bus/brcmstb_gisb.c | 10 ++++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
index 1eceefb20f01..8a6c3c2e58fe 100644
--- a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
+++ b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
@@ -3,7 +3,8 @@ Broadcom GISB bus Arbiter controller
Required properties:
- compatible:
- "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for 28nm chips
+ "brcm,bcm7278-gisb-arb" for V7 28nm chips
+ "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for other 28nm chips
"brcm,bcm7435-gisb-arb" for newer 40nm chips
"brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
"brcm,bcm7038-gisb-arb" for 130nm chips
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 774729002b8c..6c3b0dda75f2 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -65,6 +65,15 @@ static const int gisb_offsets_bcm7038[] = {
[ARB_ERR_CAP_MASTER] = -1,
};
+static const int gisb_offsets_bcm7278[] = {
+ [ARB_TIMER] = 0x008,
+ [ARB_ERR_CAP_CLR] = 0x7f8,
+ [ARB_ERR_CAP_HI_ADDR] = -1,
+ [ARB_ERR_CAP_ADDR] = 0x7e0,
+ [ARB_ERR_CAP_STATUS] = 0x7f0,
+ [ARB_ERR_CAP_MASTER] = 0x7f4,
+};
+
static const int gisb_offsets_bcm7400[] = {
[ARB_TIMER] = 0x00c,
[ARB_ERR_CAP_CLR] = 0x0c8,
@@ -328,6 +337,7 @@ static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
{ .compatible = "brcm,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 },
{ .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },
{ .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },
+ { .compatible = "brcm,bcm7278-gisb-arb", .data = gisb_offsets_bcm7278 },
{ .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 },
{ },
};
--
2.12.0
^ permalink raw reply related
* [PATCH v5 1/2] Documentation: dt-bindings: Document bindings for Aspeed ADC
From: Rick Altherr @ 2017-03-28 21:52 UTC (permalink / raw)
To: openbmc-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Hartmut Knaack, Rob Herring,
Lars-Peter Clausen, Mark Rutland, Jonathan Cameron,
Peter Meerwald-Stadler
Signed-off-by: Rick Altherr <raltherr-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---
Changes in v5: None
Changes in v4: None
Changes in v3:
- Consistently write hex contstants with lowercase letters
- Drop model numbers from description as same IP is used in every generation
Changes in v2:
- Rewritten as an IIO ADC device
.../devicetree/bindings/iio/adc/aspeed_adc.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
new file mode 100644
index 000000000000..674e133b7cd7
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
@@ -0,0 +1,20 @@
+Aspeed ADC
+
+This device is a 10-bit converter for 16 voltage channels. All inputs are
+single ended.
+
+Required properties:
+- compatible: Should be "aspeed,ast2400-adc" or "aspeed,ast2500-adc"
+- reg: memory window mapping address and length
+- clocks: Input clock used to derive the sample clock. Expected to be the
+ SoC's APB clock.
+- #io-channel-cells: Must be set to <1> to indicate channels are selected
+ by index.
+
+Example:
+ adc@1e6e9000 {
+ compatible = "aspeed,ast2400-adc";
+ reg = <0x1e6e9000 0xb0>;
+ clocks = <&clk_apb>;
+ #io-channel-cells = <1>;
+ };
--
2.12.2.564.g063fe858b8-goog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v3 1/3] clk: meson-gxbb: expose clock CLKID_RNG0
From: Michael Turquette @ 2017-03-28 22:07 UTC (permalink / raw)
To: Herbert Xu
Cc: Kevin Hilman, Heiner Kallweit, Jerome Brunet, Neil Armstrong,
linux-amlogic, linux-crypto, Stephen Boyd, linux-clk, Linux-DT
In-Reply-To: <20170323075602.GA6054@gondor.apana.org.au>
Herbert,
On Thu, Mar 23, 2017 at 12:56 AM, Herbert Xu
<herbert@gondor.apana.org.au> wrote:
> On Wed, Mar 22, 2017 at 08:24:08AM -0700, Kevin Hilman wrote:
>>
>> Because this will be causing conflicts with both the platform (amlogic)
>> tree and the clk tree, could provide an immutable branch where these are
>> applied to help us handle these conflicts?
>
> If you apply the same patches to your tree there should be no
> conflicts at all. git is able to resolve this automatically.
The commits will have different SHA1 hashes (commit id's). Having
multiple "copies" of the same patch with separate id's is undesirable
and completely avoidable. Immutable, shared branches resolve this
issue.
Best regards,
Mike
>
> Cheers,
> --
> Email: Herbert Xu <herbert@gondor.apana.org.au>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [RFC 3/8] cpufreq: imx6q: Set max suspend_freq to avoid changes during suspend
From: Rafael J. Wysocki @ 2017-03-28 22:23 UTC (permalink / raw)
To: Leonard Crestez
Cc: Viresh Kumar, Mark Brown, Liam Girdwood, Shawn Guo, Sascha Hauer,
Robin Gong, Anson Huang, Irina Tirdea, Rob Herring, Mark Rutland,
Fabio Estevam, Octavian Purdila, linux-pm, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <45185440.SBt0mf6LXq@aspire.rjw.lan>
On Tuesday, March 28, 2017 10:50:50 PM Rafael J. Wysocki wrote:
> On Tuesday, March 28, 2017 11:03:51 PM Leonard Crestez wrote:
> > On Thu, 2017-03-23 at 10:04 +0530, Viresh Kumar wrote:
> > > On 22-03-17, 18:53, Leonard Crestez wrote:
> > > > If the cpufreq driver tries to modify voltage/freq during suspend/resume
> > > > it might need to control an external PMIC via I2C or SPI but those
> > > > devices might be already suspended.
> > > >
> > > > To avoid this scenario we just increase cpufreq to highest setpoint
> > > > before suspend. This issue can easily be triggered by ldo-bypass but in
> > > > theory any regulator set_voltage call can end up having to modify
> > > > external supply voltages.
> > > >
> > > > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > > > ---
> > > > drivers/cpufreq/imx6q-cpufreq.c | 2 ++
> > > > 1 file changed, 2 insertions(+)
> > >
> > > Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
> >
> > The first couple of patches are obvious fixes despite being marked as
> > RFC. It would be great if you could apply them to your tree separately
>
> Why?
>
> > from the rest of the series but I'm not sure what the process is here.
>
> Well, you have to talk to me.
OK, so if I understand this correctly, you would like the patches ACKed by
Viresh to be applied regardless of what happens to the rest of the series,
right?
In that case please resend them separately without the [RFC] tag and with
the ACKs from Viresh.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH 1/1] of: Move OF property and graph API from base.c to property.c
From: Frank Rowand @ 2017-03-28 23:51 UTC (permalink / raw)
To: Sakari Ailus, linux-acpi, devicetree, robh
Cc: sudeep.holla, lorenzo.pieralisi, mika.westerberg, rafael,
mark.rutland, broonie, ahs3
In-Reply-To: <1490353147-11917-1-git-send-email-sakari.ailus@linux.intel.com>
Hi Sakari,
On 03/24/17 03:59, Sakari Ailus wrote:
> base.c contains both core OF functions and increasingly other
> functionality such as accessing properties and graphs, including
> convenience functions. In the near future this would also include OF
> specific implementation of the fwnode property and graph APIs. Prepare for
> this by moving the functionality to property.c.
For future me, for when I look back and read this commit, please add something
to the effect of:
Create driver/of/property.c to contain procedures for accessing and
interpreting device tree properties. The procedures are moved from
drivers/of/base.c, with no changes other than copying only the
includes required by the moved procedures.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
> Hi Rob,
>
> Did you mean something like this?
>
> Because of the upcoming changes to the base.c in linux-next I split the
> patchset reworking the implementation of the fwnode property interface and
> distributing it across the FW implementation. This patch is applicable to
> the for-next now, the rest in the set require the ACPI graph support
> patches as well.
One more comment below in the "diff --git a/drivers/of/property.c b/drivers/of/property.c"
>
> I'll post them shortly.
>
> Kind regards,
> Sakari
>
> drivers/of/Makefile | 2 +-
> drivers/of/base.c | 702 ------------------------------------------------
> drivers/of/property.c | 727 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 728 insertions(+), 703 deletions(-)
> create mode 100644 drivers/of/property.c
>
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index d7efd9d..97dc01c 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -1,4 +1,4 @@
> -obj-y = base.o device.o platform.o
> +obj-y = base.o device.o platform.o property.o
> obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
> obj-$(CONFIG_OF_FLATTREE) += fdt.o
> obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index d7c4629..d57188d 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1113,427 +1113,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
> }
> EXPORT_SYMBOL(of_find_node_by_phandle);
>
> -/**
> - * of_property_count_elems_of_size - Count the number of elements in a property
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @elem_size: size of the individual element
> - *
> - * Search for a property in a device node and count the number of elements of
> - * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
> - * property does not exist or its length does not match a multiple of elem_size
> - * and -ENODATA if the property does not have a value.
> - */
> -int of_property_count_elems_of_size(const struct device_node *np,
> - const char *propname, int elem_size)
> -{
> - struct property *prop = of_find_property(np, propname, NULL);
> -
> - if (!prop)
> - return -EINVAL;
> - if (!prop->value)
> - return -ENODATA;
> -
> - if (prop->length % elem_size != 0) {
> - pr_err("size of %s in node %s is not a multiple of %d\n",
> - propname, np->full_name, elem_size);
> - return -EINVAL;
> - }
> -
> - return prop->length / elem_size;
> -}
> -EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
> -
> -/**
> - * of_find_property_value_of_size
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @min: minimum allowed length of property value
> - * @max: maximum allowed length of property value (0 means unlimited)
> - * @len: if !=NULL, actual length is written to here
> - *
> - * Search for a property in a device node and valid the requested size.
> - * Returns the property value on success, -EINVAL if the property does not
> - * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
> - * property data is too small or too large.
> - *
> - */
> -static void *of_find_property_value_of_size(const struct device_node *np,
> - const char *propname, u32 min, u32 max, size_t *len)
> -{
> - struct property *prop = of_find_property(np, propname, NULL);
> -
> - if (!prop)
> - return ERR_PTR(-EINVAL);
> - if (!prop->value)
> - return ERR_PTR(-ENODATA);
> - if (prop->length < min)
> - return ERR_PTR(-EOVERFLOW);
> - if (max && prop->length > max)
> - return ERR_PTR(-EOVERFLOW);
> -
> - if (len)
> - *len = prop->length;
> -
> - return prop->value;
> -}
> -
> -/**
> - * of_property_read_u32_index - Find and read a u32 from a multi-value property.
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @index: index of the u32 in the list of values
> - * @out_value: pointer to return value, modified only if no error.
> - *
> - * Search for a property in a device node and read nth 32-bit value from
> - * it. Returns 0 on success, -EINVAL if the property does not exist,
> - * -ENODATA if property does not have a value, and -EOVERFLOW if the
> - * property data isn't large enough.
> - *
> - * The out_value is modified only if a valid u32 value can be decoded.
> - */
> -int of_property_read_u32_index(const struct device_node *np,
> - const char *propname,
> - u32 index, u32 *out_value)
> -{
> - const u32 *val = of_find_property_value_of_size(np, propname,
> - ((index + 1) * sizeof(*out_value)),
> - 0,
> - NULL);
> -
> - if (IS_ERR(val))
> - return PTR_ERR(val);
> -
> - *out_value = be32_to_cpup(((__be32 *)val) + index);
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_u32_index);
> -
> -/**
> - * of_property_read_variable_u8_array - Find and read an array of u8 from a
> - * property, with bounds on the minimum and maximum array size.
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_values: pointer to return value, modified only if return value is 0.
> - * @sz_min: minimum number of array elements to read
> - * @sz_max: maximum number of array elements to read, if zero there is no
> - * upper limit on the number of elements in the dts entry but only
> - * sz_min will be read.
> - *
> - * Search for a property in a device node and read 8-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * dts entry of array should be like:
> - * property = /bits/ 8 <0x50 0x60 0x70>;
> - *
> - * The out_values is modified only if a valid u8 value can be decoded.
> - */
> -int of_property_read_variable_u8_array(const struct device_node *np,
> - const char *propname, u8 *out_values,
> - size_t sz_min, size_t sz_max)
> -{
> - size_t sz, count;
> - const u8 *val = of_find_property_value_of_size(np, propname,
> - (sz_min * sizeof(*out_values)),
> - (sz_max * sizeof(*out_values)),
> - &sz);
> -
> - if (IS_ERR(val))
> - return PTR_ERR(val);
> -
> - if (!sz_max)
> - sz = sz_min;
> - else
> - sz /= sizeof(*out_values);
> -
> - count = sz;
> - while (count--)
> - *out_values++ = *val++;
> -
> - return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
> -
> -/**
> - * of_property_read_variable_u16_array - Find and read an array of u16 from a
> - * property, with bounds on the minimum and maximum array size.
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_values: pointer to return value, modified only if return value is 0.
> - * @sz_min: minimum number of array elements to read
> - * @sz_max: maximum number of array elements to read, if zero there is no
> - * upper limit on the number of elements in the dts entry but only
> - * sz_min will be read.
> - *
> - * Search for a property in a device node and read 16-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * dts entry of array should be like:
> - * property = /bits/ 16 <0x5000 0x6000 0x7000>;
> - *
> - * The out_values is modified only if a valid u16 value can be decoded.
> - */
> -int of_property_read_variable_u16_array(const struct device_node *np,
> - const char *propname, u16 *out_values,
> - size_t sz_min, size_t sz_max)
> -{
> - size_t sz, count;
> - const __be16 *val = of_find_property_value_of_size(np, propname,
> - (sz_min * sizeof(*out_values)),
> - (sz_max * sizeof(*out_values)),
> - &sz);
> -
> - if (IS_ERR(val))
> - return PTR_ERR(val);
> -
> - if (!sz_max)
> - sz = sz_min;
> - else
> - sz /= sizeof(*out_values);
> -
> - count = sz;
> - while (count--)
> - *out_values++ = be16_to_cpup(val++);
> -
> - return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
> -
> -/**
> - * of_property_read_variable_u32_array - Find and read an array of 32 bit
> - * integers from a property, with bounds on the minimum and maximum array size.
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_values: pointer to return value, modified only if return value is 0.
> - * @sz_min: minimum number of array elements to read
> - * @sz_max: maximum number of array elements to read, if zero there is no
> - * upper limit on the number of elements in the dts entry but only
> - * sz_min will be read.
> - *
> - * Search for a property in a device node and read 32-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * The out_values is modified only if a valid u32 value can be decoded.
> - */
> -int of_property_read_variable_u32_array(const struct device_node *np,
> - const char *propname, u32 *out_values,
> - size_t sz_min, size_t sz_max)
> -{
> - size_t sz, count;
> - const __be32 *val = of_find_property_value_of_size(np, propname,
> - (sz_min * sizeof(*out_values)),
> - (sz_max * sizeof(*out_values)),
> - &sz);
> -
> - if (IS_ERR(val))
> - return PTR_ERR(val);
> -
> - if (!sz_max)
> - sz = sz_min;
> - else
> - sz /= sizeof(*out_values);
> -
> - count = sz;
> - while (count--)
> - *out_values++ = be32_to_cpup(val++);
> -
> - return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
> -
> -/**
> - * of_property_read_u64 - Find and read a 64 bit integer from a property
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_value: pointer to return value, modified only if return value is 0.
> - *
> - * Search for a property in a device node and read a 64-bit value from
> - * it. Returns 0 on success, -EINVAL if the property does not exist,
> - * -ENODATA if property does not have a value, and -EOVERFLOW if the
> - * property data isn't large enough.
> - *
> - * The out_value is modified only if a valid u64 value can be decoded.
> - */
> -int of_property_read_u64(const struct device_node *np, const char *propname,
> - u64 *out_value)
> -{
> - const __be32 *val = of_find_property_value_of_size(np, propname,
> - sizeof(*out_value),
> - 0,
> - NULL);
> -
> - if (IS_ERR(val))
> - return PTR_ERR(val);
> -
> - *out_value = of_read_number(val, 2);
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_u64);
> -
> -/**
> - * of_property_read_variable_u64_array - Find and read an array of 64 bit
> - * integers from a property, with bounds on the minimum and maximum array size.
> - *
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_values: pointer to return value, modified only if return value is 0.
> - * @sz_min: minimum number of array elements to read
> - * @sz_max: maximum number of array elements to read, if zero there is no
> - * upper limit on the number of elements in the dts entry but only
> - * sz_min will be read.
> - *
> - * Search for a property in a device node and read 64-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * The out_values is modified only if a valid u64 value can be decoded.
> - */
> -int of_property_read_variable_u64_array(const struct device_node *np,
> - const char *propname, u64 *out_values,
> - size_t sz_min, size_t sz_max)
> -{
> - size_t sz, count;
> - const __be32 *val = of_find_property_value_of_size(np, propname,
> - (sz_min * sizeof(*out_values)),
> - (sz_max * sizeof(*out_values)),
> - &sz);
> -
> - if (IS_ERR(val))
> - return PTR_ERR(val);
> -
> - if (!sz_max)
> - sz = sz_min;
> - else
> - sz /= sizeof(*out_values);
> -
> - count = sz;
> - while (count--) {
> - *out_values++ = of_read_number(val, 2);
> - val += 2;
> - }
> -
> - return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
> -
> -/**
> - * of_property_read_string - Find and read a string from a property
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_string: pointer to null terminated return string, modified only if
> - * return value is 0.
> - *
> - * Search for a property in a device tree node and retrieve a null
> - * terminated string value (pointer to data, not a copy). Returns 0 on
> - * success, -EINVAL if the property does not exist, -ENODATA if property
> - * does not have a value, and -EILSEQ if the string is not null-terminated
> - * within the length of the property data.
> - *
> - * The out_string pointer is modified only if a valid string can be decoded.
> - */
> -int of_property_read_string(const struct device_node *np, const char *propname,
> - const char **out_string)
> -{
> - const struct property *prop = of_find_property(np, propname, NULL);
> - if (!prop)
> - return -EINVAL;
> - if (!prop->value)
> - return -ENODATA;
> - if (strnlen(prop->value, prop->length) >= prop->length)
> - return -EILSEQ;
> - *out_string = prop->value;
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_string);
> -
> -/**
> - * of_property_match_string() - Find string in a list and return index
> - * @np: pointer to node containing string list property
> - * @propname: string list property name
> - * @string: pointer to string to search for in string list
> - *
> - * This function searches a string list property and returns the index
> - * of a specific string value.
> - */
> -int of_property_match_string(const struct device_node *np, const char *propname,
> - const char *string)
> -{
> - const struct property *prop = of_find_property(np, propname, NULL);
> - size_t l;
> - int i;
> - const char *p, *end;
> -
> - if (!prop)
> - return -EINVAL;
> - if (!prop->value)
> - return -ENODATA;
> -
> - p = prop->value;
> - end = p + prop->length;
> -
> - for (i = 0; p < end; i++, p += l) {
> - l = strnlen(p, end - p) + 1;
> - if (p + l > end)
> - return -EILSEQ;
> - pr_debug("comparing %s with %s\n", string, p);
> - if (strcmp(string, p) == 0)
> - return i; /* Found it; return index */
> - }
> - return -ENODATA;
> -}
> -EXPORT_SYMBOL_GPL(of_property_match_string);
> -
> -/**
> - * of_property_read_string_helper() - Utility helper for parsing string properties
> - * @np: device node from which the property value is to be read.
> - * @propname: name of the property to be searched.
> - * @out_strs: output array of string pointers.
> - * @sz: number of array elements to read.
> - * @skip: Number of strings to skip over at beginning of list.
> - *
> - * Don't call this function directly. It is a utility helper for the
> - * of_property_read_string*() family of functions.
> - */
> -int of_property_read_string_helper(const struct device_node *np,
> - const char *propname, const char **out_strs,
> - size_t sz, int skip)
> -{
> - const struct property *prop = of_find_property(np, propname, NULL);
> - int l = 0, i = 0;
> - const char *p, *end;
> -
> - if (!prop)
> - return -EINVAL;
> - if (!prop->value)
> - return -ENODATA;
> - p = prop->value;
> - end = p + prop->length;
> -
> - for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
> - l = strnlen(p, end - p) + 1;
> - if (p + l > end)
> - return -EILSEQ;
> - if (out_strs && i >= skip)
> - *out_strs++ = p;
> - }
> - i -= skip;
> - return i <= 0 ? -ENODATA : i;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_string_helper);
> -
> void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
> {
> int i;
> @@ -2180,47 +1759,6 @@ int of_alias_get_highest_id(const char *stem)
> }
> EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
>
> -const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
> - u32 *pu)
> -{
> - const void *curv = cur;
> -
> - if (!prop)
> - return NULL;
> -
> - if (!cur) {
> - curv = prop->value;
> - goto out_val;
> - }
> -
> - curv += sizeof(*cur);
> - if (curv >= prop->value + prop->length)
> - return NULL;
> -
> -out_val:
> - *pu = be32_to_cpup(curv);
> - return curv;
> -}
> -EXPORT_SYMBOL_GPL(of_prop_next_u32);
> -
> -const char *of_prop_next_string(struct property *prop, const char *cur)
> -{
> - const void *curv = cur;
> -
> - if (!prop)
> - return NULL;
> -
> - if (!cur)
> - return prop->value;
> -
> - curv += strlen(cur) + 1;
> - if (curv >= prop->value + prop->length)
> - return NULL;
> -
> - return curv;
> -}
> -EXPORT_SYMBOL_GPL(of_prop_next_string);
> -
> /**
> * of_console_check() - Test and setup console for DT setup
> * @dn - Pointer to device node
> @@ -2295,243 +1833,3 @@ int of_find_last_cache_level(unsigned int cpu)
>
> return cache_level;
> }
> -
> -/**
> - * of_graph_parse_endpoint() - parse common endpoint node properties
> - * @node: pointer to endpoint device_node
> - * @endpoint: pointer to the OF endpoint data structure
> - *
> - * The caller should hold a reference to @node.
> - */
> -int of_graph_parse_endpoint(const struct device_node *node,
> - struct of_endpoint *endpoint)
> -{
> - struct device_node *port_node = of_get_parent(node);
> -
> - WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
> - __func__, node->full_name);
> -
> - memset(endpoint, 0, sizeof(*endpoint));
> -
> - endpoint->local_node = node;
> - /*
> - * It doesn't matter whether the two calls below succeed.
> - * If they don't then the default value 0 is used.
> - */
> - of_property_read_u32(port_node, "reg", &endpoint->port);
> - of_property_read_u32(node, "reg", &endpoint->id);
> -
> - of_node_put(port_node);
> -
> - return 0;
> -}
> -EXPORT_SYMBOL(of_graph_parse_endpoint);
> -
> -/**
> - * of_graph_get_port_by_id() - get the port matching a given id
> - * @parent: pointer to the parent device node
> - * @id: id of the port
> - *
> - * Return: A 'port' node pointer with refcount incremented. The caller
> - * has to use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> -{
> - struct device_node *node, *port;
> -
> - node = of_get_child_by_name(parent, "ports");
> - if (node)
> - parent = node;
> -
> - for_each_child_of_node(parent, port) {
> - u32 port_id = 0;
> -
> - if (of_node_cmp(port->name, "port") != 0)
> - continue;
> - of_property_read_u32(port, "reg", &port_id);
> - if (id == port_id)
> - break;
> - }
> -
> - of_node_put(node);
> -
> - return port;
> -}
> -EXPORT_SYMBOL(of_graph_get_port_by_id);
> -
> -/**
> - * of_graph_get_next_endpoint() - get next endpoint node
> - * @parent: pointer to the parent device node
> - * @prev: previous endpoint node, or NULL to get first
> - *
> - * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> - * of the passed @prev node is decremented.
> - */
> -struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> - struct device_node *prev)
> -{
> - struct device_node *endpoint;
> - struct device_node *port;
> -
> - if (!parent)
> - return NULL;
> -
> - /*
> - * Start by locating the port node. If no previous endpoint is specified
> - * search for the first port node, otherwise get the previous endpoint
> - * parent port node.
> - */
> - if (!prev) {
> - struct device_node *node;
> -
> - node = of_get_child_by_name(parent, "ports");
> - if (node)
> - parent = node;
> -
> - port = of_get_child_by_name(parent, "port");
> - of_node_put(node);
> -
> - if (!port) {
> - pr_err("graph: no port node found in %s\n",
> - parent->full_name);
> - return NULL;
> - }
> - } else {
> - port = of_get_parent(prev);
> - if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
> - __func__, prev->full_name))
> - return NULL;
> - }
> -
> - while (1) {
> - /*
> - * Now that we have a port node, get the next endpoint by
> - * getting the next child. If the previous endpoint is NULL this
> - * will return the first child.
> - */
> - endpoint = of_get_next_child(port, prev);
> - if (endpoint) {
> - of_node_put(port);
> - return endpoint;
> - }
> -
> - /* No more endpoints under this port, try the next one. */
> - prev = NULL;
> -
> - do {
> - port = of_get_next_child(parent, port);
> - if (!port)
> - return NULL;
> - } while (of_node_cmp(port->name, "port"));
> - }
> -}
> -EXPORT_SYMBOL(of_graph_get_next_endpoint);
> -
> -/**
> - * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
> - * @parent: pointer to the parent device node
> - * @port_reg: identifier (value of reg property) of the parent port node
> - * @reg: identifier (value of reg property) of the endpoint node
> - *
> - * Return: An 'endpoint' node pointer which is identified by reg and at the same
> - * is the child of a port node identified by port_reg. reg and port_reg are
> - * ignored when they are -1.
> - */
> -struct device_node *of_graph_get_endpoint_by_regs(
> - const struct device_node *parent, int port_reg, int reg)
> -{
> - struct of_endpoint endpoint;
> - struct device_node *node = NULL;
> -
> - for_each_endpoint_of_node(parent, node) {
> - of_graph_parse_endpoint(node, &endpoint);
> - if (((port_reg == -1) || (endpoint.port == port_reg)) &&
> - ((reg == -1) || (endpoint.id == reg)))
> - return node;
> - }
> -
> - return NULL;
> -}
> -EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
> -
> -/**
> - * of_graph_get_remote_port_parent() - get remote port's parent node
> - * @node: pointer to a local endpoint device_node
> - *
> - * Return: Remote device node associated with remote endpoint node linked
> - * to @node. Use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_remote_port_parent(
> - const struct device_node *node)
> -{
> - struct device_node *np;
> - unsigned int depth;
> -
> - /* Get remote endpoint node. */
> - np = of_parse_phandle(node, "remote-endpoint", 0);
> -
> - /* Walk 3 levels up only if there is 'ports' node. */
> - for (depth = 3; depth && np; depth--) {
> - np = of_get_next_parent(np);
> - if (depth == 2 && of_node_cmp(np->name, "ports"))
> - break;
> - }
> - return np;
> -}
> -EXPORT_SYMBOL(of_graph_get_remote_port_parent);
> -
> -/**
> - * of_graph_get_remote_port() - get remote port node
> - * @node: pointer to a local endpoint device_node
> - *
> - * Return: Remote port node associated with remote endpoint node linked
> - * to @node. Use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_remote_port(const struct device_node *node)
> -{
> - struct device_node *np;
> -
> - /* Get remote endpoint node. */
> - np = of_parse_phandle(node, "remote-endpoint", 0);
> - if (!np)
> - return NULL;
> - return of_get_next_parent(np);
> -}
> -EXPORT_SYMBOL(of_graph_get_remote_port);
> -
> -/**
> - * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
> - * @node: pointer to parent device_node containing graph port/endpoint
> - * @port: identifier (value of reg property) of the parent port node
> - * @endpoint: identifier (value of reg property) of the endpoint node
> - *
> - * Return: Remote device node associated with remote endpoint node linked
> - * to @node. Use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_remote_node(const struct device_node *node,
> - u32 port, u32 endpoint)
> -{
> - struct device_node *endpoint_node, *remote;
> -
> - endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
> - if (!endpoint_node) {
> - pr_debug("no valid endpoint (%d, %d) for node %s\n",
> - port, endpoint, node->full_name);
> - return NULL;
> - }
> -
> - remote = of_graph_get_remote_port_parent(endpoint_node);
> - of_node_put(endpoint_node);
> - if (!remote) {
> - pr_debug("no valid remote node\n");
> - return NULL;
> - }
> -
> - if (!of_device_is_available(remote)) {
> - pr_debug("not available for remote node\n");
> - return NULL;
> - }
> -
> - return remote;
> -}
> -EXPORT_SYMBOL(of_graph_get_remote_node);
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> new file mode 100644
> index 0000000..afcf00a
> --- /dev/null
> +++ b/drivers/of/property.c
> @@ -0,0 +1,727 @@
> +/*
> + * drivers/of/property.c - Devicetree properties and graphs.
* drivers/of/property.c - Procedures for accessing and interpreting
* Devicetree properties and graphs.
*
* Initially created by copying procedures from drivers/of/base.c
The reference to base.c provides a documentation trail to all of the
earlier git commits that created and modified the procedures.
It would also be useful to say what procedures do and do not belong
in this file. My understanding is that the intent is for
drivers/of/property.c and drivers/acpi/property.c to provide the
respective functionality that is used by drivers/base/property.c
and that drivers also may directly access the procedures in
drivers/of/property.c.
-Frank
> + *
> + * Paul Mackerras August 1996.
> + * Copyright (C) 1996-2005 Paul Mackerras.
> + *
> + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
> + * {engebret|bergner}@us.ibm.com
> + *
> + * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
> + *
> + * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
> + * Grant Likely.
> + *
> + * 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.
> + */
> +
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/string.h>
> +
> +#include "of_private.h"
> +/**
> + * of_property_count_elems_of_size - Count the number of elements in a property
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @elem_size: size of the individual element
> + *
> + * Search for a property in a device node and count the number of elements of
> + * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
> + * property does not exist or its length does not match a multiple of elem_size
> + * and -ENODATA if the property does not have a value.
> + */
> +int of_property_count_elems_of_size(const struct device_node *np,
> + const char *propname, int elem_size)
> +{
> + struct property *prop = of_find_property(np, propname, NULL);
> +
> + if (!prop)
> + return -EINVAL;
> + if (!prop->value)
> + return -ENODATA;
> +
> + if (prop->length % elem_size != 0) {
> + pr_err("size of %s in node %s is not a multiple of %d\n",
> + propname, np->full_name, elem_size);
> + return -EINVAL;
> + }
> +
> + return prop->length / elem_size;
> +}
> +EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
> +
> +/**
> + * of_find_property_value_of_size
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @min: minimum allowed length of property value
> + * @max: maximum allowed length of property value (0 means unlimited)
> + * @len: if !=NULL, actual length is written to here
> + *
> + * Search for a property in a device node and valid the requested size.
> + * Returns the property value on success, -EINVAL if the property does not
> + * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
> + * property data is too small or too large.
> + *
> + */
> +static void *of_find_property_value_of_size(const struct device_node *np,
> + const char *propname, u32 min, u32 max, size_t *len)
> +{
> + struct property *prop = of_find_property(np, propname, NULL);
> +
> + if (!prop)
> + return ERR_PTR(-EINVAL);
> + if (!prop->value)
> + return ERR_PTR(-ENODATA);
> + if (prop->length < min)
> + return ERR_PTR(-EOVERFLOW);
> + if (max && prop->length > max)
> + return ERR_PTR(-EOVERFLOW);
> +
> + if (len)
> + *len = prop->length;
> +
> + return prop->value;
> +}
> +
> +/**
> + * of_property_read_u32_index - Find and read a u32 from a multi-value property.
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @index: index of the u32 in the list of values
> + * @out_value: pointer to return value, modified only if no error.
> + *
> + * Search for a property in a device node and read nth 32-bit value from
> + * it. Returns 0 on success, -EINVAL if the property does not exist,
> + * -ENODATA if property does not have a value, and -EOVERFLOW if the
> + * property data isn't large enough.
> + *
> + * The out_value is modified only if a valid u32 value can be decoded.
> + */
> +int of_property_read_u32_index(const struct device_node *np,
> + const char *propname,
> + u32 index, u32 *out_value)
> +{
> + const u32 *val = of_find_property_value_of_size(np, propname,
> + ((index + 1) * sizeof(*out_value)),
> + 0,
> + NULL);
> +
> + if (IS_ERR(val))
> + return PTR_ERR(val);
> +
> + *out_value = be32_to_cpup(((__be32 *)val) + index);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_u32_index);
> +
> +/**
> + * of_property_read_variable_u8_array - Find and read an array of u8 from a
> + * property, with bounds on the minimum and maximum array size.
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_values: pointer to return value, modified only if return value is 0.
> + * @sz_min: minimum number of array elements to read
> + * @sz_max: maximum number of array elements to read, if zero there is no
> + * upper limit on the number of elements in the dts entry but only
> + * sz_min will be read.
> + *
> + * Search for a property in a device node and read 8-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * dts entry of array should be like:
> + * property = /bits/ 8 <0x50 0x60 0x70>;
> + *
> + * The out_values is modified only if a valid u8 value can be decoded.
> + */
> +int of_property_read_variable_u8_array(const struct device_node *np,
> + const char *propname, u8 *out_values,
> + size_t sz_min, size_t sz_max)
> +{
> + size_t sz, count;
> + const u8 *val = of_find_property_value_of_size(np, propname,
> + (sz_min * sizeof(*out_values)),
> + (sz_max * sizeof(*out_values)),
> + &sz);
> +
> + if (IS_ERR(val))
> + return PTR_ERR(val);
> +
> + if (!sz_max)
> + sz = sz_min;
> + else
> + sz /= sizeof(*out_values);
> +
> + count = sz;
> + while (count--)
> + *out_values++ = *val++;
> +
> + return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
> +
> +/**
> + * of_property_read_variable_u16_array - Find and read an array of u16 from a
> + * property, with bounds on the minimum and maximum array size.
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_values: pointer to return value, modified only if return value is 0.
> + * @sz_min: minimum number of array elements to read
> + * @sz_max: maximum number of array elements to read, if zero there is no
> + * upper limit on the number of elements in the dts entry but only
> + * sz_min will be read.
> + *
> + * Search for a property in a device node and read 16-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * dts entry of array should be like:
> + * property = /bits/ 16 <0x5000 0x6000 0x7000>;
> + *
> + * The out_values is modified only if a valid u16 value can be decoded.
> + */
> +int of_property_read_variable_u16_array(const struct device_node *np,
> + const char *propname, u16 *out_values,
> + size_t sz_min, size_t sz_max)
> +{
> + size_t sz, count;
> + const __be16 *val = of_find_property_value_of_size(np, propname,
> + (sz_min * sizeof(*out_values)),
> + (sz_max * sizeof(*out_values)),
> + &sz);
> +
> + if (IS_ERR(val))
> + return PTR_ERR(val);
> +
> + if (!sz_max)
> + sz = sz_min;
> + else
> + sz /= sizeof(*out_values);
> +
> + count = sz;
> + while (count--)
> + *out_values++ = be16_to_cpup(val++);
> +
> + return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
> +
> +/**
> + * of_property_read_variable_u32_array - Find and read an array of 32 bit
> + * integers from a property, with bounds on the minimum and maximum array size.
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_values: pointer to return value, modified only if return value is 0.
> + * @sz_min: minimum number of array elements to read
> + * @sz_max: maximum number of array elements to read, if zero there is no
> + * upper limit on the number of elements in the dts entry but only
> + * sz_min will be read.
> + *
> + * Search for a property in a device node and read 32-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * The out_values is modified only if a valid u32 value can be decoded.
> + */
> +int of_property_read_variable_u32_array(const struct device_node *np,
> + const char *propname, u32 *out_values,
> + size_t sz_min, size_t sz_max)
> +{
> + size_t sz, count;
> + const __be32 *val = of_find_property_value_of_size(np, propname,
> + (sz_min * sizeof(*out_values)),
> + (sz_max * sizeof(*out_values)),
> + &sz);
> +
> + if (IS_ERR(val))
> + return PTR_ERR(val);
> +
> + if (!sz_max)
> + sz = sz_min;
> + else
> + sz /= sizeof(*out_values);
> +
> + count = sz;
> + while (count--)
> + *out_values++ = be32_to_cpup(val++);
> +
> + return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
> +
> +/**
> + * of_property_read_u64 - Find and read a 64 bit integer from a property
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_value: pointer to return value, modified only if return value is 0.
> + *
> + * Search for a property in a device node and read a 64-bit value from
> + * it. Returns 0 on success, -EINVAL if the property does not exist,
> + * -ENODATA if property does not have a value, and -EOVERFLOW if the
> + * property data isn't large enough.
> + *
> + * The out_value is modified only if a valid u64 value can be decoded.
> + */
> +int of_property_read_u64(const struct device_node *np, const char *propname,
> + u64 *out_value)
> +{
> + const __be32 *val = of_find_property_value_of_size(np, propname,
> + sizeof(*out_value),
> + 0,
> + NULL);
> +
> + if (IS_ERR(val))
> + return PTR_ERR(val);
> +
> + *out_value = of_read_number(val, 2);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_u64);
> +
> +/**
> + * of_property_read_variable_u64_array - Find and read an array of 64 bit
> + * integers from a property, with bounds on the minimum and maximum array size.
> + *
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_values: pointer to return value, modified only if return value is 0.
> + * @sz_min: minimum number of array elements to read
> + * @sz_max: maximum number of array elements to read, if zero there is no
> + * upper limit on the number of elements in the dts entry but only
> + * sz_min will be read.
> + *
> + * Search for a property in a device node and read 64-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * The out_values is modified only if a valid u64 value can be decoded.
> + */
> +int of_property_read_variable_u64_array(const struct device_node *np,
> + const char *propname, u64 *out_values,
> + size_t sz_min, size_t sz_max)
> +{
> + size_t sz, count;
> + const __be32 *val = of_find_property_value_of_size(np, propname,
> + (sz_min * sizeof(*out_values)),
> + (sz_max * sizeof(*out_values)),
> + &sz);
> +
> + if (IS_ERR(val))
> + return PTR_ERR(val);
> +
> + if (!sz_max)
> + sz = sz_min;
> + else
> + sz /= sizeof(*out_values);
> +
> + count = sz;
> + while (count--) {
> + *out_values++ = of_read_number(val, 2);
> + val += 2;
> + }
> +
> + return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
> +
> +/**
> + * of_property_read_string - Find and read a string from a property
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_string: pointer to null terminated return string, modified only if
> + * return value is 0.
> + *
> + * Search for a property in a device tree node and retrieve a null
> + * terminated string value (pointer to data, not a copy). Returns 0 on
> + * success, -EINVAL if the property does not exist, -ENODATA if property
> + * does not have a value, and -EILSEQ if the string is not null-terminated
> + * within the length of the property data.
> + *
> + * The out_string pointer is modified only if a valid string can be decoded.
> + */
> +int of_property_read_string(const struct device_node *np, const char *propname,
> + const char **out_string)
> +{
> + const struct property *prop = of_find_property(np, propname, NULL);
> + if (!prop)
> + return -EINVAL;
> + if (!prop->value)
> + return -ENODATA;
> + if (strnlen(prop->value, prop->length) >= prop->length)
> + return -EILSEQ;
> + *out_string = prop->value;
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_string);
> +
> +/**
> + * of_property_match_string() - Find string in a list and return index
> + * @np: pointer to node containing string list property
> + * @propname: string list property name
> + * @string: pointer to string to search for in string list
> + *
> + * This function searches a string list property and returns the index
> + * of a specific string value.
> + */
> +int of_property_match_string(const struct device_node *np, const char *propname,
> + const char *string)
> +{
> + const struct property *prop = of_find_property(np, propname, NULL);
> + size_t l;
> + int i;
> + const char *p, *end;
> +
> + if (!prop)
> + return -EINVAL;
> + if (!prop->value)
> + return -ENODATA;
> +
> + p = prop->value;
> + end = p + prop->length;
> +
> + for (i = 0; p < end; i++, p += l) {
> + l = strnlen(p, end - p) + 1;
> + if (p + l > end)
> + return -EILSEQ;
> + pr_debug("comparing %s with %s\n", string, p);
> + if (strcmp(string, p) == 0)
> + return i; /* Found it; return index */
> + }
> + return -ENODATA;
> +}
> +EXPORT_SYMBOL_GPL(of_property_match_string);
> +
> +/**
> + * of_property_read_string_helper() - Utility helper for parsing string properties
> + * @np: device node from which the property value is to be read.
> + * @propname: name of the property to be searched.
> + * @out_strs: output array of string pointers.
> + * @sz: number of array elements to read.
> + * @skip: Number of strings to skip over at beginning of list.
> + *
> + * Don't call this function directly. It is a utility helper for the
> + * of_property_read_string*() family of functions.
> + */
> +int of_property_read_string_helper(const struct device_node *np,
> + const char *propname, const char **out_strs,
> + size_t sz, int skip)
> +{
> + const struct property *prop = of_find_property(np, propname, NULL);
> + int l = 0, i = 0;
> + const char *p, *end;
> +
> + if (!prop)
> + return -EINVAL;
> + if (!prop->value)
> + return -ENODATA;
> + p = prop->value;
> + end = p + prop->length;
> +
> + for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
> + l = strnlen(p, end - p) + 1;
> + if (p + l > end)
> + return -EILSEQ;
> + if (out_strs && i >= skip)
> + *out_strs++ = p;
> + }
> + i -= skip;
> + return i <= 0 ? -ENODATA : i;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_string_helper);
> +
> +const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
> + u32 *pu)
> +{
> + const void *curv = cur;
> +
> + if (!prop)
> + return NULL;
> +
> + if (!cur) {
> + curv = prop->value;
> + goto out_val;
> + }
> +
> + curv += sizeof(*cur);
> + if (curv >= prop->value + prop->length)
> + return NULL;
> +
> +out_val:
> + *pu = be32_to_cpup(curv);
> + return curv;
> +}
> +EXPORT_SYMBOL_GPL(of_prop_next_u32);
> +
> +const char *of_prop_next_string(struct property *prop, const char *cur)
> +{
> + const void *curv = cur;
> +
> + if (!prop)
> + return NULL;
> +
> + if (!cur)
> + return prop->value;
> +
> + curv += strlen(cur) + 1;
> + if (curv >= prop->value + prop->length)
> + return NULL;
> +
> + return curv;
> +}
> +EXPORT_SYMBOL_GPL(of_prop_next_string);
> +
> +/**
> + * of_graph_parse_endpoint() - parse common endpoint node properties
> + * @node: pointer to endpoint device_node
> + * @endpoint: pointer to the OF endpoint data structure
> + *
> + * The caller should hold a reference to @node.
> + */
> +int of_graph_parse_endpoint(const struct device_node *node,
> + struct of_endpoint *endpoint)
> +{
> + struct device_node *port_node = of_get_parent(node);
> +
> + WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
> + __func__, node->full_name);
> +
> + memset(endpoint, 0, sizeof(*endpoint));
> +
> + endpoint->local_node = node;
> + /*
> + * It doesn't matter whether the two calls below succeed.
> + * If they don't then the default value 0 is used.
> + */
> + of_property_read_u32(port_node, "reg", &endpoint->port);
> + of_property_read_u32(node, "reg", &endpoint->id);
> +
> + of_node_put(port_node);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(of_graph_parse_endpoint);
> +
> +/**
> + * of_graph_get_port_by_id() - get the port matching a given id
> + * @parent: pointer to the parent device node
> + * @id: id of the port
> + *
> + * Return: A 'port' node pointer with refcount incremented. The caller
> + * has to use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> +{
> + struct device_node *node, *port;
> +
> + node = of_get_child_by_name(parent, "ports");
> + if (node)
> + parent = node;
> +
> + for_each_child_of_node(parent, port) {
> + u32 port_id = 0;
> +
> + if (of_node_cmp(port->name, "port") != 0)
> + continue;
> + of_property_read_u32(port, "reg", &port_id);
> + if (id == port_id)
> + break;
> + }
> +
> + of_node_put(node);
> +
> + return port;
> +}
> +EXPORT_SYMBOL(of_graph_get_port_by_id);
> +
> +/**
> + * of_graph_get_next_endpoint() - get next endpoint node
> + * @parent: pointer to the parent device node
> + * @prev: previous endpoint node, or NULL to get first
> + *
> + * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> + * of the passed @prev node is decremented.
> + */
> +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> + struct device_node *prev)
> +{
> + struct device_node *endpoint;
> + struct device_node *port;
> +
> + if (!parent)
> + return NULL;
> +
> + /*
> + * Start by locating the port node. If no previous endpoint is specified
> + * search for the first port node, otherwise get the previous endpoint
> + * parent port node.
> + */
> + if (!prev) {
> + struct device_node *node;
> +
> + node = of_get_child_by_name(parent, "ports");
> + if (node)
> + parent = node;
> +
> + port = of_get_child_by_name(parent, "port");
> + of_node_put(node);
> +
> + if (!port) {
> + pr_err("graph: no port node found in %s\n",
> + parent->full_name);
> + return NULL;
> + }
> + } else {
> + port = of_get_parent(prev);
> + if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
> + __func__, prev->full_name))
> + return NULL;
> + }
> +
> + while (1) {
> + /*
> + * Now that we have a port node, get the next endpoint by
> + * getting the next child. If the previous endpoint is NULL this
> + * will return the first child.
> + */
> + endpoint = of_get_next_child(port, prev);
> + if (endpoint) {
> + of_node_put(port);
> + return endpoint;
> + }
> +
> + /* No more endpoints under this port, try the next one. */
> + prev = NULL;
> +
> + do {
> + port = of_get_next_child(parent, port);
> + if (!port)
> + return NULL;
> + } while (of_node_cmp(port->name, "port"));
> + }
> +}
> +EXPORT_SYMBOL(of_graph_get_next_endpoint);
> +
> +/**
> + * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
> + * @parent: pointer to the parent device node
> + * @port_reg: identifier (value of reg property) of the parent port node
> + * @reg: identifier (value of reg property) of the endpoint node
> + *
> + * Return: An 'endpoint' node pointer which is identified by reg and at the same
> + * is the child of a port node identified by port_reg. reg and port_reg are
> + * ignored when they are -1.
> + */
> +struct device_node *of_graph_get_endpoint_by_regs(
> + const struct device_node *parent, int port_reg, int reg)
> +{
> + struct of_endpoint endpoint;
> + struct device_node *node = NULL;
> +
> + for_each_endpoint_of_node(parent, node) {
> + of_graph_parse_endpoint(node, &endpoint);
> + if (((port_reg == -1) || (endpoint.port == port_reg)) &&
> + ((reg == -1) || (endpoint.id == reg)))
> + return node;
> + }
> +
> + return NULL;
> +}
> +EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
> +
> +/**
> + * of_graph_get_remote_port_parent() - get remote port's parent node
> + * @node: pointer to a local endpoint device_node
> + *
> + * Return: Remote device node associated with remote endpoint node linked
> + * to @node. Use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_remote_port_parent(
> + const struct device_node *node)
> +{
> + struct device_node *np;
> + unsigned int depth;
> +
> + /* Get remote endpoint node. */
> + np = of_parse_phandle(node, "remote-endpoint", 0);
> +
> + /* Walk 3 levels up only if there is 'ports' node. */
> + for (depth = 3; depth && np; depth--) {
> + np = of_get_next_parent(np);
> + if (depth == 2 && of_node_cmp(np->name, "ports"))
> + break;
> + }
> + return np;
> +}
> +EXPORT_SYMBOL(of_graph_get_remote_port_parent);
> +
> +/**
> + * of_graph_get_remote_port() - get remote port node
> + * @node: pointer to a local endpoint device_node
> + *
> + * Return: Remote port node associated with remote endpoint node linked
> + * to @node. Use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_remote_port(const struct device_node *node)
> +{
> + struct device_node *np;
> +
> + /* Get remote endpoint node. */
> + np = of_parse_phandle(node, "remote-endpoint", 0);
> + if (!np)
> + return NULL;
> + return of_get_next_parent(np);
> +}
> +EXPORT_SYMBOL(of_graph_get_remote_port);
> +
> +/**
> + * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
> + * @node: pointer to parent device_node containing graph port/endpoint
> + * @port: identifier (value of reg property) of the parent port node
> + * @endpoint: identifier (value of reg property) of the endpoint node
> + *
> + * Return: Remote device node associated with remote endpoint node linked
> + * to @node. Use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_remote_node(const struct device_node *node,
> + u32 port, u32 endpoint)
> +{
> + struct device_node *endpoint_node, *remote;
> +
> + endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
> + if (!endpoint_node) {
> + pr_debug("no valid endpoint (%d, %d) for node %s\n",
> + port, endpoint, node->full_name);
> + return NULL;
> + }
> +
> + remote = of_graph_get_remote_port_parent(endpoint_node);
> + of_node_put(endpoint_node);
> + if (!remote) {
> + pr_debug("no valid remote node\n");
> + return NULL;
> + }
> +
> + if (!of_device_is_available(remote)) {
> + pr_debug("not available for remote node\n");
> + return NULL;
> + }
> +
> + return remote;
> +}
> +EXPORT_SYMBOL(of_graph_get_remote_node);
>
^ permalink raw reply
* Re: [PATCH v6 02/39] [media] dt-bindings: Add bindings for i.MX media driver
From: Rob Herring @ 2017-03-29 0:21 UTC (permalink / raw)
To: Steve Longerbeam
Cc: Mark Rutland, Shawn Guo, kernel@pengutronix.de, Fabio Estevam,
Russell King, Mauro Carvalho Chehab, Hans Verkuil, Nick Dyer,
markus.heiser, Philipp Zabel, Laurent Pinchart, Benoit Parrot,
Geert Uytterhoeven, Arnd Bergmann, Sudip Mukherjee, Minghsiu Tsai,
tiffany lin, Jean-Christophe Trotin, Simon Horman
In-Reply-To: <1490661656-10318-3-git-send-email-steve_longerbeam@mentor.com>
On Mon, Mar 27, 2017 at 7:40 PM, Steve Longerbeam <slongerbeam@gmail.com> wrote:
> Add bindings documentation for the i.MX media driver.
>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
> Documentation/devicetree/bindings/media/imx.txt | 74 +++++++++++++++++++++++++
> 1 file changed, 74 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/imx.txt
>
> diff --git a/Documentation/devicetree/bindings/media/imx.txt b/Documentation/devicetree/bindings/media/imx.txt
> new file mode 100644
> index 0000000..3059c06
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/imx.txt
> @@ -0,0 +1,74 @@
> +Freescale i.MX Media Video Device
> +=================================
> +
> +Video Media Controller node
> +---------------------------
> +
> +This is the media controller node for video capture support. It is a
> +virtual device that lists the camera serial interface nodes that the
> +media device will control.
> +
> +Required properties:
> +- compatible : "fsl,imx-capture-subsystem";
> +- ports : Should contain a list of phandles pointing to camera
> + sensor interface ports of IPU devices
> +
> +example:
> +
> +capture-subsystem {
> + compatible = "fsl,imx-capture-subsystem";
> + ports = <&ipu1_csi0>, <&ipu1_csi1>;
> +};
> +
> +fim child node
> +--------------
> +
> +This is an optional child node of the ipu_csi port nodes. If present and
> +available, it enables the Frame Interval Monitor. Its properties can be
> +used to modify the method in which the FIM measures frame intervals.
> +Refer to Documentation/media/v4l-drivers/imx.rst for more info on the
> +Frame Interval Monitor.
> +
> +Optional properties:
> +- fsl,input-capture-channel: an input capture channel and channel flags,
> + specified as <chan flags>. The channel number
> + must be 0 or 1. The flags can be
> + IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, or
> + IRQ_TYPE_EDGE_BOTH, and specify which input
> + capture signal edge will trigger the input
> + capture event. If an input capture channel is
> + specified, the FIM will use this method to
> + measure frame intervals instead of via the EOF
> + interrupt. The input capture method is much
> + preferred over EOF as it is not subject to
> + interrupt latency errors. However it requires
> + routing the VSYNC or FIELD output signals of
> + the camera sensor to one of the i.MX input
> + capture pads (SD1_DAT0, SD1_DAT1), which also
> + gives up support for SD1.
> +
> +
> +mipi_csi2 node
> +--------------
> +
> +This is the device node for the MIPI CSI-2 Receiver, required for MIPI
> +CSI-2 sensors.
> +
> +Required properties:
> +- compatible : "fsl,imx6-mipi-csi2", "snps,dw-mipi-csi2";
As I mentioned in v5, there's a DW CSI2 binding in progress. This
needs to be based on that.
Rob
^ permalink raw reply
* Re: [PATCH v2 1/5] dt-bindings: Document STM32 CRC bindings
From: Rob Herring @ 2017-03-29 0:28 UTC (permalink / raw)
To: Fabien Dessenne
Cc: Herbert Xu, David S . Miller, Mark Rutland, Maxime Coquelin,
Alexandre Torgue, Russell King, linux-crypto, devicetree,
linux-arm-kernel, Benjamin Gaignard
In-Reply-To: <1490109211-4869-2-git-send-email-fabien.dessenne@st.com>
On Tue, Mar 21, 2017 at 04:13:27PM +0100, Fabien Dessenne wrote:
> Document device tree bindings for the STM32 CRC (crypto CRC32)
>
> Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
> ---
> .../devicetree/bindings/crypto/st,stm32-crc.txt | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/crypto/st,stm32-crc.txt
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v3 04/11] Documentation: DT: bindings: mfd: add A33 GPADC binding
From: Rob Herring @ 2017-03-29 0:31 UTC (permalink / raw)
To: Quentin Schulz
Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, mark.rutland-5wv7dgnIgG8,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, wens-jdAy2FN1RRM,
lee.jones-QSEj5FYQhm4dnm+yROfE0A, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-input-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, icenowy-ymACFijhrKM
In-Reply-To: <20170321153611.16228-5-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
On Tue, Mar 21, 2017 at 04:36:04PM +0100, Quentin Schulz wrote:
> This patch adds documentation for the A33 GPADC binding.
>
> Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
>
> v3:
> - fixed missing allwinner in front of compatible,
> - updated compatible to allwinner,sun8i-a33-ths to better reflect the
> datasheet's name,
> - updated example's DT node name and label to ths,
>
> added in v2
>
> .../devicetree/bindings/mfd/sun4i-gpadc.txt | 59 ++++++++++++++++++++++
> 1 file changed, 59 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt
If you respin, "dt-bindings: mfd: ..." for the subject.
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
^ permalink raw reply
* Re: [PATCH v2 1/2] Documentation: dt-bindings: Document bindings for Aspeed AST2400/AST2500 ADC
From: Rob Herring @ 2017-03-29 0:33 UTC (permalink / raw)
To: Rick Altherr
Cc: openbmc, linux-kernel, devicetree, linux-iio, Hartmut Knaack,
Lars-Peter Clausen, Mark Rutland, Jonathan Cameron,
Peter Meerwald-Stadler
In-Reply-To: <20170321204828.31303-1-raltherr@google.com>
On Tue, Mar 21, 2017 at 01:48:27PM -0700, Rick Altherr wrote:
> Signed-off-by: Rick Altherr <raltherr@google.com>
> ---
>
> Changes in v2:
> - Rewritten as an IIO ADC device
>
> .../devicetree/bindings/iio/adc/aspeed_adc.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v6 02/39] [media] dt-bindings: Add bindings for i.MX media driver
From: Steve Longerbeam @ 2017-03-29 0:35 UTC (permalink / raw)
To: Rob Herring, Steve Longerbeam
Cc: Mark Rutland, Andrew-CT Chen (陳智迪),
Minghsiu Tsai, Sakari Ailus, Nick Dyer, Songjun Wu, Hans Verkuil,
Pavel Machek, Robert Jarzmik, devel, markus.heiser,
Laurent Pinchart, shuah, Russell King, Geert Uytterhoeven,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
kernel@pengutronix.de, Arnd Bergmann, Mauro Carvalho Chehab,
Benoit Parrot
In-Reply-To: <CAL_JsqJm_JjuVPcOBERCqsnjTDdNoKr9xRE9MXMO4ivxGath2Q@mail.gmail.com>
On 03/28/2017 05:21 PM, Rob Herring wrote:
> On Mon, Mar 27, 2017 at 7:40 PM, Steve Longerbeam <slongerbeam@gmail.com> wrote:
>> Add bindings documentation for the i.MX media driver.
>>
>> <snip>
>> +
>> +mipi_csi2 node
>> +--------------
>> +
>> +This is the device node for the MIPI CSI-2 Receiver, required for MIPI
>> +CSI-2 sensors.
>> +
>> +Required properties:
>> +- compatible : "fsl,imx6-mipi-csi2", "snps,dw-mipi-csi2";
>
> As I mentioned in v5, there's a DW CSI2 binding in progress. This
> needs to be based on that.
Hi Rob, I'm not sure what you are asking me to do.
I assume if there's another binding doc in progress, it means
someone is working on another Synopsys DW CSI-2 subdevice driver.
Unfortunately I don't have the time to contribute and switch to
this other subdevice, and do test/debug.
For now I would prefer if this patchset is merged as is, and
then contribute/switch to another CSI-2 subdev later. It is
also getting very difficult managing all these patches (39 as
of this version), and I'd prefer not to spam the lists with
such large patchsets for too much longer.
Steve
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox