* [RESEND PATCH v2 4/9] pinctrl: meson: allow gpio to request irq
From: Jerome Brunet @ 2016-10-19 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-5-git-send-email-jbrunet@baylibre.com>
Add the ability for gpio to request irq from the gpio interrupt controller
if present. We have to specificaly that the parent interrupt controller is
the gpio interrupt controller because gpio on meson SoCs can't generate
interrupt directly on the GIC.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
I messed up in v2 and actually sent the v1 again. Here is the actual v2
with the fix. Again, sorry for the inconvenience.
drivers/pinctrl/Kconfig | 2 +
drivers/pinctrl/meson/pinctrl-meson.c | 69 +++++++++++++++++++++++++++++++++++
drivers/pinctrl/meson/pinctrl-meson.h | 1 +
3 files changed, 72 insertions(+)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 0e75d94972ba..d5bfbfcddab0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -126,7 +126,9 @@ config PINCTRL_MESON
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
+ select IRQ_DOMAIN
select OF_GPIO
+ select OF_IRQ
select REGMAP_MMIO
config PINCTRL_OXNAS
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 57122eda155a..e3f5241f337f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -50,6 +50,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -481,6 +482,58 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
value ? BIT(bit) : 0);
}
+static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
+{
+ unsigned int hwirq;
+
+ if (bank->irq_first < 0)
+ /* this bank cannot generate irqs */
+ return -1;
+
+ hwirq = offset - bank->first + bank->irq_first;
+
+ if (hwirq > bank->irq_last)
+ /* this pin cannot generate irqs */
+ return -1;
+
+ return hwirq;
+}
+
+static int meson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct meson_pinctrl *pc = gpiochip_get_data(chip);
+ struct meson_bank *bank;
+ struct irq_fwspec fwspec;
+ unsigned int hwirq;
+ int ret;
+
+ ret = meson_get_bank(pc, offset, &bank);
+ if (ret)
+ return ret;
+
+ /*
+ * The interrupt controller might be missing, in such case we can't
+ * provide an interrupt for a pin
+ */
+ if (is_fwnode_irqchip(pc->fwnode)) {
+ dev_info(pc->dev, "interrupt controller not found\n");
+ return 0;
+ }
+
+ hwirq = meson_gpio_to_hwirq(bank, offset);
+ if (hwirq < 0) {
+ dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
+ return 0;
+ }
+
+ fwspec.fwnode = pc->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_NONE;
+
+ return irq_create_fwspec_mapping(&fwspec);
+}
+
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
struct meson_pinctrl *pc = gpiochip_get_data(chip);
@@ -539,6 +592,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
pc->chip.direction_output = meson_gpio_direction_output;
pc->chip.get = meson_gpio_get;
pc->chip.set = meson_gpio_set;
+ pc->chip.to_irq = meson_gpio_to_irq;
pc->chip.base = pc->data->pin_base;
pc->chip.ngpio = pc->data->num_pins;
pc->chip.can_sleep = false;
@@ -598,6 +652,19 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc,
return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config);
}
+static void meson_pinctrl_get_irq_gpio_intc(struct meson_pinctrl *pc,
+ struct device_node *node)
+{
+ struct device_node *np = of_irq_find_parent(node);
+
+ if (!np || !of_device_is_compatible(np, pc->data->irq_compat)) {
+ dev_info(pc->dev, "gpio interrupt disabled\n");
+ pc->fwnode = NULL;
+ } else {
+ pc->fwnode = of_node_to_fwnode(np);
+ }
+}
+
static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
struct device_node *node)
{
@@ -643,6 +710,8 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
return PTR_ERR(pc->reg_gpio);
}
+ meson_pinctrl_get_irq_gpio_intc(pc, gpio_np);
+
return 0;
}
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index b90d69e366df..2e6c83adbd1f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -123,6 +123,7 @@ struct meson_pinctrl {
struct regmap *reg_gpio;
struct gpio_chip chip;
struct device_node *of_node;
+ struct fwnode_handle *fwnode;
};
#define PIN(x, b) (b + x)
--
2.7.4
^ permalink raw reply related
* [PATCH] mtd: nand: Add OX820 NAND Support
From: Boris Brezillon @ 2016-10-19 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161019145523.6763-1-narmstrong@baylibre.com>
On Wed, 19 Oct 2016 16:55:23 +0200
Neil Armstrong <narmstrong@baylibre.com> wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
It looks pretty good already (I like those dummy controllers :-)). Just
a few comments below.
> ---
> .../devicetree/bindings/mtd/oxnas-nand.txt | 24 +++
> drivers/mtd/nand/Kconfig | 5 +
> drivers/mtd/nand/Makefile | 1 +
> drivers/mtd/nand/oxnas_nand.c | 204 +++++++++++++++++++++
> 4 files changed, 234 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> create mode 100644 drivers/mtd/nand/oxnas_nand.c
>
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
> - Avoid using chip->IO_ADDR*
> - Use new DT structure
> - Assign a chip for the subnode
> - Use the nand_hw_control structure
> - Cleanup probe
> - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
>
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {
nandc: nand-controller at 41000000 {
> + compatible = "oxsemi,ox820-nand";
> + reg = <0x41000000 0x100000>;
> + nand-ecc-mode = "soft";
> + clocks = <&stdclk CLK_820_NAND>;
> + resets = <&reset RESET_NAND>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + status = "disabled";
> +};
You should probably provide an example where the NAND controller is
enabled and at least one nand chip is connected to the NAND bus.
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
> No board specific support is done by this driver, each board
> must advertise a platform_device for the driver to attach.
>
> +config MTD_NAND_OXNAS
> + tristate "NAND Flash support for Oxford Semiconductor SoC"
> + help
> + This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
> config MTD_NAND_FSL_ELBC
> tristate "NAND support for Freescale eLBC controllers"
> depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
> obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
> obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
> obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
> obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
> obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
> obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..a9fe1ac
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,204 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> +
> + * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool@gmail.com>
> + * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
> + * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of.h>
> +
> +/* Nand commands */
> +#define OXNAS_NAND_CMD_ALE BIT(18)
> +#define OXNAS_NAND_CMD_CLE BIT(19)
> +
> +#define OXNAS_NAND_MAX_CHIPS 1
> +
> +struct oxnas_nand {
> + struct nand_hw_control base;
> + void __iomem *io_base;
> + struct clk *clk;
> + struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> + unsigned long ctrl;
> +};
> +
> +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + return readb(oxnas->io_base);
> +}
> +
> +static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + ioread8_rep(oxnas->io_base, buf, len);
> +}
> +
> +static void oxnas_nand_write_buf(struct mtd_info *mtd,
> + const uint8_t *buf, int len)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
> +}
> +
> +/* Single CS command control */
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> + unsigned int ctrl)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + if (ctrl & NAND_CTRL_CHANGE) {
> + if (ctrl & NAND_CLE)
> + oxnas->ctrl = OXNAS_NAND_CMD_CLE;
> + else if (ctrl & NAND_ALE)
> + oxnas->ctrl = OXNAS_NAND_CMD_ALE;
> + else
> + oxnas->ctrl = 0;
> + }
> +
> + if (cmd != NAND_CMD_NONE)
> + writeb(cmd, oxnas->io_base + oxnas->ctrl);
There's no need to test the NAND_CTRL_CHANGE here, and I don't think
the CLE or ALE flag is ever set when cmd == CMD_NONE. So, you can kill
the ->ctrl field and simply do:
if (ctrl & NAND_CLE)
writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
else if (ctrl & NAND_ALE)
writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
> +}
^ permalink raw reply
* [PATCH V5 00/10] dmaengine: qcom_hidma: add MSI interrupt support
From: Sinan Kaya @ 2016-10-19 15:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161019133406.GO2467@localhost>
On 10/19/2016 6:34 AM, Vinod Koul wrote:
> On Fri, Oct 07, 2016 at 01:25:05AM -0400, Sinan Kaya wrote:
>> The new version of the HW supports MSI interrupts instead of wired
>> interrupts. The MSI interrupts are especially useful for the guest machine
>> execution. The wired interrupts usually trap to the hypervisor and then are
>> relayed to the actual interrupt.
>>
>> The MSI interrupts can be directly fed into the interrupt controller.
>>
>> Adding a new OF compat string (qcom,hidma-1.1) and ACPI string (QCOM8062)
>> to distinguish newer HW from the older ones.
>
> I was only able to apply 6 patches in this series. Which tree were these
> generated against?
>
> Please rebase rest..
>
Sure, let me do that. The other two patches (sysfs and debugfs) probably broke
the git merge.
--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Gregory CLEMENT @ 2016-10-19 15:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4333753.kxspqi1Miz@wuerfel>
Hi Arnd,
On mer., oct. 19 2016, Arnd Bergmann <arnd@arndb.de> wrote:
> On Wednesday, October 19, 2016 4:01:58 PM CEST Ard Biesheuvel wrote:
>> On 19 October 2016 at 15:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> > On 19 October 2016 at 14:35, Will Deacon <will.deacon@arm.com> wrote:
>> >> On Mon, Oct 17, 2016 at 08:43:19PM +0100, Ard Biesheuvel wrote:
>> >>> On 17 October 2016 at 19:38, Will Deacon <will.deacon@arm.com> wrote:
>> >
>> > Yes, and that would be perfectly legal from a correctness point of
>> > view, and would likely help performance as well. By using
>> > __builtin_constant_p(), you are choosing to perform a build time
>> > evaluation of an expression that would ordinarily be evaluated only at
>> > runtime. This implies that you have to address undefined behavior at
>> > build time rather than at runtime as well.
>> >
>> >>> If order_base_2() is not defined for input 0, it should BUG() in that
>> >>> case, and the associated __builtin_unreachable() should prevent the
>> >>> special version from being emitted. If order_base_2() is defined for input
>> >>> 0, it should not invoke ilog2() with that argument, and the problem should
>> >>> go away as well.
>> >>
>> >> I don't necessarily think it should BUG() if it's not defined for input
>> >> 0; things like __ffs don't do that and we'd be introducing conditional
>> >> checks for cases that should not happen. The comment above order_base_2
>> >> does suggest that ob2(0) should return 0, but it can actually end up
>> >> invoking ilog2(-1), which is obviously wrong.
>> >>
>> >> I could update the comment, but that doesn't fix the build issue.
>> >>
>> >
>> > Fixing roundup_pow_of_two() [which is arguably incorrect]
>>
>> I just spotted the comment that says it is undefined. But that means
>> it could legally return 1 for input 0, i suppose
>
> I think having the link error in roundup_pow_of_two() is safer than
> returning 1.
>
> Why not turn it into a runtime warning in this driver?
>
> diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
> index cecb0fdfaef6..711d1d9842cc 100644
> --- a/drivers/clk/mvebu/armada-37xx-periph.c
> +++ b/drivers/clk/mvebu/armada-37xx-periph.c
> @@ -349,8 +349,10 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
> rate->reg = reg + (u64)rate->reg;
> for (clkt = rate->table; clkt->div; clkt++)
> table_size++;
> - rate->width = order_base_2(table_size);
> - rate->lock = lock;
> + if (!WARN_ON(table_size == 0)) {
> + rate->width = order_base_2(table_size);
> + rate->lock = lock;
> + }
With the way the data are constructed in the driver I don't see how the
table_size can be 0.
However I understand it is more something for the compiler.
In this case it is better to nullify the rate_hw as having width=0 will
lead to trouble in the clk_divider operations
If it is the needed solution for this build error I can submit this kind
of patch:
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index 45905fc0d75b..dbc49359406d 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -345,11 +345,16 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
const struct clk_div_table *clkt;
int table_size = 0;
- rate->reg = reg + (u64)rate->reg;
for (clkt = rate->table; clkt->div; clkt++)
table_size++;
- rate->width = order_base_2(table_size);
- rate->lock = lock;
+ if (!WARN_ON(table_size == 0)) {
+ rate->reg = reg + (u64)rate->reg;
+ rate->width = order_base_2(table_size);
+ rate->lock = lock;
+ } else {
+ rate_hw = NULL;
+ rate_ops = NULL;
+ }
}
}
Gregory
> }
> }
>
>
>
> Arnd
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply related
* [PATCH 2/3] ARM: convert to generated system call tables
From: Arnd Bergmann @ 2016-10-19 15:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1bwa6s-0004ZY-4k@rmk-PC.armlinux.org.uk>
On Tuesday, October 18, 2016 8:31:38 PM CEST Russell King wrote:
> Convert ARM to use a similar mechanism to x86 to generate the unistd.h
> system call numbers and the various kernel system call tables. This
> means that rather than having to edit three places (asm/unistd.h for
> the total number of system calls, uapi/asm/unistd.h for the system call
> numbers, and arch/arm/kernel/calls.S for the call table) we have only
> one place to edit, making the process much more simple.
>
> The scripts have knowledge of the table padding requirements, so there's
> no need to worry about __NR_syscalls not fitting within the immediate
> constant field of ALU instructions anymore.
>
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Ah, very nice!
I have some vague plans to do something like this for all architectures,
so having it done for one of the more complex examples (there are very
few architectures with more than one table) simplifies it a lot.
The next step is probably to do it for asm-generic/unistd.h, which
covers a lot of architectures, and then we can introduce a shared
table for all future additions so we only have to add the new calls
in one place, and change the scripts so they can merge two input
files into one.
> diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
> new file mode 100644
> index 000000000000..62285cbd09c0
> --- /dev/null
> +++ b/arch/arm/tools/syscall.tbl
> @@ -0,0 +1,428 @@
> +#
> +# Linux system call numbers and entry vectors
> +#
> +# The format is:
> +# <num> <abi> <name> <entry point> <oabi compat entry point>
> +#
> +# Where abi is:
> +# common - for system calls shared between oabi and eabi
> +# oabi - for oabi-only system calls (may have compat)
> +# eabi - for eabi-only system calls
Why do we need all three? I would have guessed that these two are
sufficient to cover all cases:
arm - one entry for eabi, optional second entry for oabi if different
oabi - only one entry for oabi, syscall is not used on eabi
> +180 oabi pread64 sys_pread64 sys_oabi_pread64
> +180 eabi pread64 sys_pread64
> +181 oabi pwrite64 sys_pwrite64 sys_oabi_pwrite64
> +181 eabi pwrite64 sys_pwrite64
That would avoid having to list those numbers twice, which looks
a bit odd here, and is inconsistent with how x86 handles their
compat table for x32
> diff --git a/arch/arm/tools/syscallhdr.sh b/arch/arm/tools/syscallhdr.sh
> new file mode 100644
> index 000000000000..72d4b2e3bdec
> --- /dev/null
> +++ b/arch/arm/tools/syscallhdr.sh
The scripts are still very similar to the x86 version. Any chance
we can move them to a top-level scripts/syscall/ directory and make
them work for both architectures? It would be good to avoid duplicating
them for all the other architectures too, so starting out with a common
version could make that easier.
If necessary, I can do that once I get to the following stage of
doing the asm-generic/unistd.h replacement.
Arnd
^ permalink raw reply
* [PATCH] mtd: nand: Add OX820 NAND Support
From: Neil Armstrong @ 2016-10-19 15:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161019145523.6763-1-narmstrong@baylibre.com>
On 10/19/2016 04:55 PM, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Forgot
Acked-by: Rob Herring <robh@kernel.org>
Will add in v2 if a respin is needed.
> ---
> .../devicetree/bindings/mtd/oxnas-nand.txt | 24 +++
> drivers/mtd/nand/Kconfig | 5 +
> drivers/mtd/nand/Makefile | 1 +
> drivers/mtd/nand/oxnas_nand.c | 204 +++++++++++++++++++++
> 4 files changed, 234 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> create mode 100644 drivers/mtd/nand/oxnas_nand.c
>
> Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
> - Avoid using chip->IO_ADDR*
> - Use new DT structure
> - Assign a chip for the subnode
> - Use the nand_hw_control structure
> - Cleanup probe
> - Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
>
> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> new file mode 100644
> index 0000000..83b684d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> @@ -0,0 +1,24 @@
> +* Oxford Semiconductor OXNAS NAND Controller
> +
> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> +
> +Required properties:
> + - compatible: "oxsemi,ox820-nand"
> + - reg: Base address and length for NAND mapped memory.
> +
> +Optional Properties:
> + - clocks: phandle to the NAND gate clock if needed.
> + - resets: phandle to the NAND reset control if needed.
> +
> +Example:
> +
> +nand: nand at 41000000 {
> + compatible = "oxsemi,ox820-nand";
> + reg = <0x41000000 0x100000>;
> + nand-ecc-mode = "soft";
> + clocks = <&stdclk CLK_820_NAND>;
> + resets = <&reset RESET_NAND>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + status = "disabled";
> +};
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 7b7a887..c023125 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -426,6 +426,11 @@ config MTD_NAND_ORION
> No board specific support is done by this driver, each board
> must advertise a platform_device for the driver to attach.
>
> +config MTD_NAND_OXNAS
> + tristate "NAND Flash support for Oxford Semiconductor SoC"
> + help
> + This enables the NAND flash controller on Oxford Semiconductor SoCs.
> +
> config MTD_NAND_FSL_ELBC
> tristate "NAND support for Freescale eLBC controllers"
> depends on FSL_SOC
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index cafde6f..05fc054 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
> obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
> obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
> obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
> +obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
> obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
> obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
> obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
> new file mode 100644
> index 0000000..a9fe1ac
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,204 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> +
> + * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool@gmail.com>
> + * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
> + * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/reset.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of.h>
> +
> +/* Nand commands */
> +#define OXNAS_NAND_CMD_ALE BIT(18)
> +#define OXNAS_NAND_CMD_CLE BIT(19)
> +
> +#define OXNAS_NAND_MAX_CHIPS 1
> +
> +struct oxnas_nand {
> + struct nand_hw_control base;
> + void __iomem *io_base;
> + struct clk *clk;
> + struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> + unsigned long ctrl;
> +};
> +
> +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + return readb(oxnas->io_base);
> +}
> +
> +static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + ioread8_rep(oxnas->io_base, buf, len);
> +}
> +
> +static void oxnas_nand_write_buf(struct mtd_info *mtd,
> + const uint8_t *buf, int len)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
> +}
> +
> +/* Single CS command control */
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> + unsigned int ctrl)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct oxnas_nand *oxnas = nand_get_controller_data(chip);
> +
> + if (ctrl & NAND_CTRL_CHANGE) {
> + if (ctrl & NAND_CLE)
> + oxnas->ctrl = OXNAS_NAND_CMD_CLE;
> + else if (ctrl & NAND_ALE)
> + oxnas->ctrl = OXNAS_NAND_CMD_ALE;
> + else
> + oxnas->ctrl = 0;
> + }
> +
> + if (cmd != NAND_CMD_NONE)
> + writeb(cmd, oxnas->io_base + oxnas->ctrl);
> +}
> +
> +/*
> + * Probe for the NAND device.
> + */
> +static int oxnas_nand_probe(struct platform_device *pdev)
> +{
> + struct device_node *np = pdev->dev.of_node;
> + struct device_node *nand_np;
> + struct oxnas_nand *oxnas;
> + struct nand_chip *chip;
> + struct mtd_info *mtd;
> + struct resource *res;
> + int nchips = 0;
> + int count = 0;
> + int err = 0;
> +
> + /* Allocate memory for the device structure (and zero it) */
> + oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
> + GFP_KERNEL);
> + if (!oxnas)
> + return -ENOMEM;
> +
> + nand_hw_control_init(&oxnas->base);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(oxnas->io_base))
> + return PTR_ERR(oxnas->io_base);
> +
> + oxnas->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(oxnas->clk))
> + oxnas->clk = NULL;
> +
> + /* Only a single chip node is supported */
> + count = of_get_child_count(np);
> + if (count > 1)
> + return -EINVAL;
> +
> + clk_prepare_enable(oxnas->clk);
> + device_reset_optional(&pdev->dev);
> +
> + for_each_child_of_node(np, nand_np) {
> + chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
> + GFP_KERNEL);
> + if (!chip)
> + return -ENOMEM;
> +
> + chip->controller = &oxnas->base;
> +
> + nand_set_flash_node(chip, nand_np);
> + nand_set_controller_data(chip, oxnas);
> +
> + mtd = nand_to_mtd(chip);
> + mtd->dev.parent = &pdev->dev;
> + mtd->priv = chip;
> +
> + chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
> + chip->read_buf = oxnas_nand_read_buf;
> + chip->read_byte = oxnas_nand_read_byte;
> + chip->write_buf = oxnas_nand_write_buf;
> + chip->chip_delay = 30;
> +
> + /* Scan to find existence of the device */
> + err = nand_scan(mtd, 1);
> + if (err)
> + return err;
> +
> + err = mtd_device_register(mtd, NULL, 0);
> + if (err) {
> + nand_release(mtd);
> + return err;
> + }
> +
> + oxnas->chips[nchips] = chip;
> + ++nchips;
> + }
> +
> + /* Exit if no chips found */
> + if (!nchips)
> + return -ENODEV;
> +
> + platform_set_drvdata(pdev, oxnas);
> +
> + return 0;
> +}
> +
> +static int oxnas_nand_remove(struct platform_device *pdev)
> +{
> + struct oxnas_nand *oxnas = platform_get_drvdata(pdev);
> +
> + if (oxnas->chips[0])
> + nand_release(nand_to_mtd(oxnas->chips[0]));
> +
> + clk_disable_unprepare(oxnas->clk);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id oxnas_nand_match[] = {
> + { .compatible = "oxsemi,ox820-nand" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, oxnas_nand_match);
> +
> +static struct platform_driver oxnas_nand_driver = {
> + .probe = oxnas_nand_probe,
> + .remove = oxnas_nand_remove,
> + .driver = {
> + .name = "oxnas_nand",
> + .of_match_table = oxnas_nand_match,
> + },
> +};
> +
> +module_platform_driver(oxnas_nand_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
> +MODULE_DESCRIPTION("Oxnas NAND driver");
> +MODULE_ALIAS("platform:oxnas_nand");
>
^ permalink raw reply
* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Ard Biesheuvel @ 2016-10-19 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4333753.kxspqi1Miz@wuerfel>
On 19 October 2016 at 16:11, Arnd Bergmann <arnd@arndb.de> wrote:
> On Wednesday, October 19, 2016 4:01:58 PM CEST Ard Biesheuvel wrote:
>> On 19 October 2016 at 15:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> > On 19 October 2016 at 14:35, Will Deacon <will.deacon@arm.com> wrote:
>> >> On Mon, Oct 17, 2016 at 08:43:19PM +0100, Ard Biesheuvel wrote:
>> >>> On 17 October 2016 at 19:38, Will Deacon <will.deacon@arm.com> wrote:
>> >
>> > Yes, and that would be perfectly legal from a correctness point of
>> > view, and would likely help performance as well. By using
>> > __builtin_constant_p(), you are choosing to perform a build time
>> > evaluation of an expression that would ordinarily be evaluated only at
>> > runtime. This implies that you have to address undefined behavior at
>> > build time rather than at runtime as well.
>> >
>> >>> If order_base_2() is not defined for input 0, it should BUG() in that
>> >>> case, and the associated __builtin_unreachable() should prevent the
>> >>> special version from being emitted. If order_base_2() is defined for input
>> >>> 0, it should not invoke ilog2() with that argument, and the problem should
>> >>> go away as well.
>> >>
>> >> I don't necessarily think it should BUG() if it's not defined for input
>> >> 0; things like __ffs don't do that and we'd be introducing conditional
>> >> checks for cases that should not happen. The comment above order_base_2
>> >> does suggest that ob2(0) should return 0, but it can actually end up
>> >> invoking ilog2(-1), which is obviously wrong.
>> >>
>> >> I could update the comment, but that doesn't fix the build issue.
>> >>
>> >
>> > Fixing roundup_pow_of_two() [which is arguably incorrect]
>>
>> I just spotted the comment that says it is undefined. But that means
>> it could legally return 1 for input 0, i suppose
>
> I think having the link error in roundup_pow_of_two() is safer than
> returning 1.
>
> Why not turn it into a runtime warning in this driver?
>
> diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
> index cecb0fdfaef6..711d1d9842cc 100644
> --- a/drivers/clk/mvebu/armada-37xx-periph.c
> +++ b/drivers/clk/mvebu/armada-37xx-periph.c
> @@ -349,8 +349,10 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
> rate->reg = reg + (u64)rate->reg;
> for (clkt = rate->table; clkt->div; clkt++)
> table_size++;
> - rate->width = order_base_2(table_size);
> - rate->lock = lock;
> + if (!WARN_ON(table_size == 0)) {
> + rate->width = order_base_2(table_size);
> + rate->lock = lock;
> + }
> }
> }
>
I guess Will is not looking for a way to fix the driver, but for a way
to eliminate this issue entirely going forward.
In general, I think the issue where constant folding results in
ilog2() or other similar functions being called with invalid build
time constant parameter values is simply something we have to deal
with.
In this case, it is in fact order_base_2() that deviates from its
documented behavior (as Will points out), and fixing /that/ should
make this particular issue go away afaict.
^ permalink raw reply
* [PATCH v2 9/9] ARM: dts: amlogic: enable gpio interrupt controller on meson8
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm/boot/dts/meson8.dtsi | 11 +++++++++++
arch/arm/boot/dts/meson8b.dtsi | 11 +++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 45619f6162c5..713a22456ff1 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -43,6 +43,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/meson8-gpio.h>
/include/ "meson.dtsi"
@@ -91,6 +93,13 @@
clock-frequency = <141666666>;
};
+ gpio_interrupt: interrupt-controller at c1109880 {
+ compatible = "amlogic,meson8-gpio-intc";
+ reg = <0xc1109880 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pinctrl_cbus: pinctrl at c1109880 {
compatible = "amlogic,meson8-cbus-pinctrl";
reg = <0xc1109880 0x10>;
@@ -106,6 +115,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
spi_nor_pins: nor {
@@ -148,6 +158,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 41fd53671859..36a239a645f5 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -44,6 +44,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/meson8b-clkc.h>
#include <dt-bindings/gpio/meson8b-gpio.h>
#include <dt-bindings/reset/amlogic,meson8b-reset.h>
@@ -183,6 +185,13 @@
status = "disabled";
};
+ gpio_interrupt: interrupt-controller at c1109880 {
+ compatible = "amlogic,meson8b-gpio-intc";
+ reg = <0xc1109880 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pinctrl_cbus: pinctrl at c1109880 {
compatible = "amlogic,meson8b-cbus-pinctrl";
reg = <0xc1109880 0x10>;
@@ -198,6 +207,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
};
@@ -215,6 +225,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
--
2.7.4
^ permalink raw reply related
* [PATCH v2 8/9] ARM64: dts: amlogic: enable gpio interrupt controller on gxbb
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index aad639ab0112..5208cb80b55e 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -141,6 +141,13 @@
#reset-cells = <1>;
};
+ gpio_interrupt: interrupt-controller at 9880 {
+ compatible = "amlogic,meson-gxbb-gpio-intc";
+ reg = <0x0 0x9880 0x0 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
uart_B: serial at 84dc {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84dc 0x0 0x14>;
@@ -238,6 +245,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
@@ -343,6 +351,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
emmc_pins: emmc {
--
2.7.4
^ permalink raw reply related
* [PATCH v2 7/9] ARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Add select MESON_IRQ_GPIO in Kconfig for Amlogic's meson8 and meson8b SoC
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm/mach-meson/Kconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index b6e3acc63e14..63157295cd9d 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -21,11 +21,13 @@ config MACH_MESON8
bool "Amlogic Meson8 SoCs support"
default ARCH_MESON
select MESON6_TIMER
+ select MESON_IRQ_GPIO
config MACH_MESON8B
bool "Amlogic Meson8b SoCs support"
default ARCH_MESON
select MESON6_TIMER
select COMMON_CLK_MESON8B
+ select MESON_IRQ_GPIO
endif
--
2.7.4
^ permalink raw reply related
* [PATCH v2 6/9] ARM64: meson: enable MESON_IRQ_GPIO in Kconfig
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Add select MESON_IRQ_GPIO in Kconfig for Amlogic's meson SoC family
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm64/Kconfig.platforms | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index cfbdf02ef566..846479d4492d 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -95,6 +95,7 @@ config ARCH_MESON
select PINCTRL_MESON
select COMMON_CLK_AMLOGIC
select COMMON_CLK_GXBB
+ select MESON_GPIO_IRQ
help
This enables support for the Amlogic S905 SoCs.
--
2.7.4
^ permalink raw reply related
* [PATCH v2 5/9] dt-bindings: pinctrl: meson: update gpio dt-bindings
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Add description for the interrupt-parent property of the gpio sub-node
If provided here, this property must be a phandle to an interrupt
controller suitable for meson pinctrl, like the meson gpio interrupt
controller.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
index fe7fe0b03cfb..39932c4dfb32 100644
--- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -23,6 +23,10 @@ Required properties for sub-nodes are:
- gpio-controller: identifies the node as a gpio controller
- #gpio-cells: must be 2
+Optional property for sub-nodes is:
+ - interrupt-parent: must be a phandle to the meson gpio interrupt controller.
+ if this property is provided, enables gpio ability to generate interrupts
+
=== Other sub-nodes ===
Child nodes without the "gpio-controller" represent some desired
--
2.7.4
^ permalink raw reply related
* [PATCH v2 4/9] pinctrl: meson: allow gpio to request irq
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Add the ability for gpio to request irq from the gpio interrupt controller
if present. We have to specificaly that the parent interrupt controller is
the gpio interrupt controller because gpio on meson SoCs can't generate
interrupt directly on the GIC.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/pinctrl/Kconfig | 2 +
drivers/pinctrl/meson/pinctrl-meson.c | 77 ++++++++++++++++++++++++++++++++++-
drivers/pinctrl/meson/pinctrl-meson.h | 1 +
3 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 0e75d94972ba..d5bfbfcddab0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -126,7 +126,9 @@ config PINCTRL_MESON
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
+ select IRQ_DOMAIN
select OF_GPIO
+ select OF_IRQ
select REGMAP_MMIO
config PINCTRL_OXNAS
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 57122eda155a..fd3c1d44978b 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -50,6 +50,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -481,6 +482,58 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
value ? BIT(bit) : 0);
}
+static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
+{
+ unsigned int hwirq;
+
+ if (bank->irq_first < 0)
+ /* this bank cannot generate irqs */
+ return -1;
+
+ hwirq = offset - bank->first + bank->irq_first;
+
+ if (hwirq > bank->irq_last)
+ /* this pin cannot generate irqs */
+ return -1;
+
+ return hwirq;
+}
+
+static int meson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct meson_pinctrl *pc = gpiochip_get_data(chip);
+ struct meson_bank *bank;
+ struct irq_fwspec fwspec;
+ unsigned int hwirq;
+ int ret;
+
+ ret = meson_get_bank(pc, offset, &bank);
+ if (ret)
+ return ret;
+
+ /*
+ * The interrupt controller might be missing, in such case we can't
+ * provide an interrupt for a pin
+ */
+ if (is_fwnode_irqchip(pc->fwnode)) {
+ dev_info(pc->dev, "interrupt controller not found\n");
+ return 0;
+ }
+
+ hwirq = meson_gpio_to_hwirq(bank, offset);
+ if (hwirq < 0) {
+ dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
+ return 0;
+ }
+
+ fwspec.fwnode = pc->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_NONE;
+
+ return irq_create_fwspec_mapping(&fwspec);
+}
+
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
struct meson_pinctrl *pc = gpiochip_get_data(chip);
@@ -539,6 +592,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
pc->chip.direction_output = meson_gpio_direction_output;
pc->chip.get = meson_gpio_get;
pc->chip.set = meson_gpio_set;
+ pc->chip.to_irq = meson_gpio_to_irq;
pc->chip.base = pc->data->pin_base;
pc->chip.ngpio = pc->data->num_pins;
pc->chip.can_sleep = false;
@@ -598,6 +652,27 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc,
return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config);
}
+static int meson_pinctrl_get_irq_gpio_intc(struct meson_pinctrl *pc,
+ struct device_node *node)
+{
+ struct device_node *np;
+
+ np = of_irq_find_parent(node);
+ if (unlikely(!np)) {
+ dev_err(pc->dev, "interrupt parent not found\n");
+ return -EINVAL;
+ }
+
+ if (!of_device_is_compatible(np, pc->data->irq_compat)) {
+ dev_info(pc->dev, "gpio interrupt disabled\n");
+ pc->fwnode = NULL;
+ }
+
+ pc->fwnode = of_node_to_fwnode(np);
+
+ return 0;
+}
+
static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
struct device_node *node)
{
@@ -643,7 +718,7 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
return PTR_ERR(pc->reg_gpio);
}
- return 0;
+ return meson_pinctrl_get_irq_gpio_intc(pc, gpio_np);
}
static int meson_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index b90d69e366df..2e6c83adbd1f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -123,6 +123,7 @@ struct meson_pinctrl {
struct regmap *reg_gpio;
struct gpio_chip chip;
struct device_node *of_node;
+ struct fwnode_handle *fwnode;
};
#define PIN(x, b) (b + x)
--
2.7.4
^ permalink raw reply related
* [PATCH v2 3/9] pinctrl: meson: update pinctrl data with gpio irq data
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
This patch extends meson's pinctrl SoC specific data by adding the gpio
irq base number and the compatible controller for each SoC. This will
allow gpios to request an interrupt on the gpio interrupt controller
using this base irq number the pin offset inbank
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 24 +++++++++++----------
drivers/pinctrl/meson/pinctrl-meson.h | 16 +++++++++-----
drivers/pinctrl/meson/pinctrl-meson8.c | 22 ++++++++++---------
drivers/pinctrl/meson/pinctrl-meson8b.c | 34 +++++++++++++++++++++---------
4 files changed, 60 insertions(+), 36 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index c3928aa3fefa..ed8a1222de3b 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -715,24 +715,25 @@ static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
};
static struct meson_bank meson_gxbb_periphs_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
- BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
- BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
- BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
- BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
- BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
- BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 106, 128, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
+ BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 89, 105, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 59, 88, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
+ BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 30, 33, 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
+ BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 14, 29, 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
+ BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 52, 58, 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
+ BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 34, 51, 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
+ BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 129, 132, 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
};
static struct meson_bank meson_gxbb_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
.name = "periphs-banks",
+ .irq_compat = "amlogic,meson-gxbb-gpio-intc",
.pin_base = 14,
.pins = meson_gxbb_periphs_pins,
.groups = meson_gxbb_periphs_groups,
@@ -746,6 +747,7 @@ struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = {
.name = "aobus-banks",
+ .irq_compat = "amlogic,meson-gxbb-gpio-intc",
.pin_base = 0,
.pins = meson_gxbb_aobus_pins,
.groups = meson_gxbb_aobus_groups,
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 98b5080650c1..b90d69e366df 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -81,6 +81,7 @@ enum meson_reg_type {
* @name: bank name
* @first: first pin of the bank
* @last: last pin of the bank
+ * @irq: hwirq base number of the bank
* @regs: array of register descriptors
*
* A bank represents a set of pins controlled by a contiguous set of
@@ -92,11 +93,14 @@ struct meson_bank {
const char *name;
unsigned int first;
unsigned int last;
+ int irq_first;
+ int irq_last;
struct meson_reg_desc regs[NUM_REG];
};
struct meson_pinctrl_data {
const char *name;
+ const char *irq_compat;
const struct pinctrl_pin_desc *pins;
struct meson_pmx_group *groups;
struct meson_pmx_func *funcs;
@@ -147,12 +151,14 @@ struct meson_pinctrl {
.num_groups = ARRAY_SIZE(fn ## _groups), \
}
-#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
{ \
- .name = n, \
- .first = f, \
- .last = l, \
- .regs = { \
+ .name = n, \
+ .first = f, \
+ .last = l, \
+ .irq_first = fi, \
+ .irq_last = li, \
+ .regs = { \
[REG_PULLEN] = { per, peb }, \
[REG_PULL] = { pr, pb }, \
[REG_DIR] = { dr, db }, \
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 07f1cb21c1b8..eddab1091408 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -916,23 +916,24 @@ static struct meson_pmx_func meson8_aobus_functions[] = {
};
static struct meson_bank meson8_cbus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
- BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_0, 0), PIN(GPIODV_29, 0), 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
- BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
- BANK("Z", PIN(GPIOZ_0, 0), PIN(GPIOZ_14, 0), 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
- BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
- BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 112, 133, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 95, 111, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_0, 0), PIN(GPIODV_29, 0), 65, 94, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 29, 38, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("Z", PIN(GPIOZ_0, 0), PIN(GPIOZ_14, 0), 14, 28, 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
+ BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 58, 64, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 39, 57, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
};
static struct meson_bank meson8_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
.name = "cbus-banks",
+ .irq_compat = "amlogic,meson8-gpio-intc",
.pin_base = 0,
.pins = meson8_cbus_pins,
.groups = meson8_cbus_groups,
@@ -946,6 +947,7 @@ struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
struct meson_pinctrl_data meson8_aobus_pinctrl_data = {
.name = "ao-bank",
+ .irq_compat = "amlogic,meson8-gpio-intc",
.pin_base = 120,
.pins = meson8_aobus_pins,
.groups = meson8_aobus_groups,
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index 76f077f18193..d7505f492639 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -124,6 +124,12 @@ static const struct pinctrl_pin_desc meson8b_aobus_pins[] = {
MESON_PIN(GPIOAO_11, AO_OFF),
MESON_PIN(GPIOAO_12, AO_OFF),
MESON_PIN(GPIOAO_13, AO_OFF),
+
+ /*
+ * The following 2 pins are not mentionned in the public datasheet
+ * According to this datasheet, they can't be used with the gpio
+ * interrupt controller
+ */
MESON_PIN(GPIO_BSD_EN, AO_OFF),
MESON_PIN(GPIO_TEST_N, AO_OFF),
};
@@ -881,23 +887,30 @@ static struct meson_pmx_func meson8b_aobus_functions[] = {
};
static struct meson_bank meson8b_cbus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
- BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_9, 0), PIN(GPIODV_29, 0), 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
- BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
- BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
- BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
- BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 97, 118, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 80, 96, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_9, 0), PIN(GPIODV_29, 0), 59, 79, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 14, 23, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 43, 49, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 24, 42, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+
+ /*
+ * The following bank is not mentionned in the public datasheet
+ * There is no information whether it can be used with the gpio
+ * interrupt controller
+ */
+ BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), -1, -1, 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
};
static struct meson_bank meson8b_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
.name = "cbus-banks",
+ .irq_compat = "amlogic,meson8b-gpio-intc",
.pin_base = 0,
.pins = meson8b_cbus_pins,
.groups = meson8b_cbus_groups,
@@ -911,6 +924,7 @@ struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
struct meson_pinctrl_data meson8b_aobus_pinctrl_data = {
.name = "aobus-banks",
+ .irq_compat = "amlogic,meson8b-gpio-intc",
.pin_base = 130,
.pins = meson8b_aobus_pins,
.groups = meson8b_aobus_groups,
--
2.7.4
^ permalink raw reply related
* [PATCH v2 2/9] dt-bindings: interrupt-controller: add DT binding for meson GPIO interrupt controller
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
This commit adds the device tree bindings description for Amlogic's GPIO
interrupt controller available on the meson8, meson8b and gxbb SoC families
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
Rob, I did not include the Ack you gave for the RFC as bindings have slightly
changed. Only the interrupt property has be removed following a discussion I
had with Marc
.../amlogic,meson-gpio-intc.txt | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
new file mode 100644
index 000000000000..2464d9a0865d
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
@@ -0,0 +1,31 @@
+Amlogic meson GPIO interrupt controller
+
+Meson SoCs contains an interrupt controller which is able watch the SoC pads
+and generate an interrupt on edges or level. The controller is essentially a
+256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge
+or level and polarity. We don?t expose all 256 mux inputs because the
+documentation shows that upper part is not mapped to any pad. The actual number
+of interrupt exposed depends on the SoC.
+
+Required properties:
+
+- compatible : should be either
+ "amlogic,meson8-gpio-intc? for meson8 SoCs (AML7826MX) or
+ ?amlogic,meson8b-gpio-intc? for meson8b SoCs (S805) or
+ ?amlogic,meson-gxbb-gpio-intc? for GXBB SoCs (S905)
+- interrupt-parent : a phandle to the GIC the interrupts are routed to.
+ Usually this is provided at the root level of the device tree as it is
+ common to most of the SoC
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value must be 2.
+
+Example:
+
+gpio_interrupt: interrupt-controller at 9880 {
+ compatible = "amlogic,meson-gxbb-gpio-intc";
+ reg = <0x0 0x9880 0x0 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/9] irqchip: meson: add support for gpio interrupt controller
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476890480-8884-1-git-send-email-jbrunet@baylibre.com>
Add support for the interrupt gpio controller found on Amlogic's meson
SoC family.
Unlike what the IP name suggest, it is not directly linked to the gpio
subsystem. It is actually an independent IP that is able to spy on the
SoC pad. For that purpose, it can mux and filter (edge or level and
polarity) any single SoC pad to one of the 8 GIC's interrupts it owns.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-meson-gpio.c | 423 +++++++++++++++++++++++++++++++++++++++
3 files changed, 433 insertions(+)
create mode 100644 drivers/irqchip/irq-meson-gpio.c
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 82b0b5daf3f5..168837263e80 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -279,3 +279,12 @@ config EZNPS_GIC
config STM32_EXTI
bool
select IRQ_DOMAIN
+
+config MESON_GPIO_IRQ
+ bool "Meson GPIO Interrupt Multiplexer"
+ depends on ARCH_MESON || COMPILE_TEST
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ Support Meson SoC Family GPIO Interrupt Multiplexer
+
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc85abdb..33f913d037d0 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
+obj-$(CONFIG_MESON_GPIO_IRQ) += irq-meson-gpio.o
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
new file mode 100644
index 000000000000..869b4df8c483
--- /dev/null
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define IRQ_FREE (-1)
+
+#define REG_EDGE_POL 0x00
+#define REG_PIN_03_SEL 0x04
+#define REG_PIN_47_SEL 0x08
+#define REG_FILTER_SEL 0x0c
+
+#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x)))
+#define REG_EDGE_POL_EDGE(x) BIT(x)
+#define REG_EDGE_POL_LOW(x) BIT(16 + (x))
+#define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8)
+#define REG_FILTER_SEL_SHIFT(x) ((x) * 4)
+
+struct meson_gpio_irq_params {
+ unsigned int nhwirq;
+ irq_hw_number_t *source;
+ int nsource;
+};
+
+struct meson_gpio_irq_domain {
+ void __iomem *base;
+ int *map;
+ const struct meson_gpio_irq_params *params;
+};
+
+struct meson_gpio_irq_chip_data {
+ void __iomem *base;
+ int index;
+};
+
+static irq_hw_number_t meson_parent_hwirqs[] = {
+ 64, 65, 66, 67, 68, 69, 70, 71,
+};
+
+static const struct meson_gpio_irq_params meson8_params = {
+ .nhwirq = 134,
+ .source = meson_parent_hwirqs,
+ .nsource = ARRAY_SIZE(meson_parent_hwirqs),
+};
+
+static const struct meson_gpio_irq_params meson8b_params = {
+ .nhwirq = 119,
+ .source = meson_parent_hwirqs,
+ .nsource = ARRAY_SIZE(meson_parent_hwirqs),
+};
+
+static const struct meson_gpio_irq_params meson_gxbb_params = {
+ .nhwirq = 133,
+ .source = meson_parent_hwirqs,
+ .nsource = ARRAY_SIZE(meson_parent_hwirqs),
+};
+
+static const struct of_device_id meson_irq_gpio_matches[] = {
+ {
+ .compatible = "amlogic,meson8-gpio-intc",
+ .data = &meson8_params
+ },
+ {
+ .compatible = "amlogic,meson8b-gpio-intc",
+ .data = &meson8b_params
+ },
+ {
+ .compatible = "amlogic,meson-gxbb-gpio-intc",
+ .data = &meson_gxbb_params
+ },
+ {}
+};
+
+static void meson_gpio_irq_update_bits(void __iomem *base, unsigned int reg,
+ u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = readl(base + reg);
+ tmp &= ~mask;
+ tmp |= val;
+
+ writel(tmp, base + reg);
+}
+
+static int meson_gpio_irq_get_index(struct meson_gpio_irq_domain *domain_data,
+ int hwirq)
+{
+ int i;
+
+ for (i = 0; i < domain_data->params->nsource; i++) {
+ if (domain_data->map[i] == hwirq)
+ return i;
+ }
+
+ return -1;
+}
+
+static int mesion_gpio_irq_map_source(struct meson_gpio_irq_domain *domain_data,
+ irq_hw_number_t hwirq,
+ irq_hw_number_t *source)
+{
+ int index;
+ unsigned int reg;
+
+ index = meson_gpio_irq_get_index(domain_data, IRQ_FREE);
+ if (index < 0) {
+ pr_err("No irq available\n");
+ return -ENOSPC;
+ }
+
+ domain_data->map[index] = hwirq;
+
+ reg = (index < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL;
+ meson_gpio_irq_update_bits(domain_data->base, reg,
+ 0xff << REG_PIN_SEL_SHIFT(index),
+ hwirq << REG_PIN_SEL_SHIFT(index));
+
+ *source = domain_data->params->source[index];
+
+ pr_debug("hwirq %lu assigned to channel %d - source %lu\n",
+ hwirq, index, *source);
+
+ return index;
+}
+
+static int meson_gpio_irq_type_setup(unsigned int type, void __iomem *base,
+ int index)
+{
+ u32 val = 0;
+
+ type &= IRQ_TYPE_SENSE_MASK;
+
+ if (type == IRQ_TYPE_EDGE_BOTH)
+ return -EINVAL;
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ val |= REG_EDGE_POL_EDGE(index);
+
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ val |= REG_EDGE_POL_LOW(index);
+
+ meson_gpio_irq_update_bits(base, REG_EDGE_POL,
+ REG_EDGE_POL_MASK(index), val);
+
+ return 0;
+}
+
+static unsigned int meson_gpio_irq_type_output(unsigned int type)
+{
+ unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
+
+ type &= ~IRQ_TYPE_SENSE_MASK;
+
+ /*
+ * If the polarity of interrupt is low, the controller will
+ * invert the signal for gic
+ */
+ if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+ type |= IRQ_TYPE_LEVEL_HIGH;
+ else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ type |= IRQ_TYPE_EDGE_RISING;
+
+ return type;
+}
+
+static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct meson_gpio_irq_chip_data *cd = irq_data_get_irq_chip_data(data);
+ int ret;
+
+ pr_debug("set type of hwirq %lu to %u\n", data->hwirq, type);
+
+ ret = meson_gpio_irq_type_setup(type, cd->base, cd->index);
+ if (ret)
+ return ret;
+
+ return irq_chip_set_type_parent(data,
+ meson_gpio_irq_type_output(type));
+}
+
+static struct irq_chip meson_gpio_irq_chip = {
+ .name = "meson-gpio-irqchip",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_type = meson_gpio_irq_set_type,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+#endif
+};
+
+static int meson_gpio_irq_domain_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int meson_gpio_irq_allocate_gic_irq(struct irq_domain *domain,
+ unsigned int virq,
+ irq_hw_number_t source,
+ unsigned int type)
+{
+ struct irq_fwspec fwspec;
+
+ if (!irq_domain_get_of_node(domain->parent))
+ return -EINVAL;
+
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 3;
+ fwspec.param[0] = 0; /* SPI */
+ fwspec.param[1] = source;
+ fwspec.param[2] = meson_gpio_irq_type_output(type);
+
+ return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+}
+
+static int meson_gpio_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs,
+ void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ struct meson_gpio_irq_domain *domain_data = domain->host_data;
+ struct meson_gpio_irq_chip_data *cd;
+ unsigned long hwirq, source;
+ unsigned int type;
+ int i, index, ret;
+
+ ret = meson_gpio_irq_domain_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return ret;
+
+ pr_debug("irq %d, nr_irqs %d, hwirqs %lu\n", virq, nr_irqs, hwirq);
+
+ for (i = 0; i < nr_irqs; i++) {
+ index = mesion_gpio_irq_map_source(domain_data, hwirq + i,
+ &source);
+ if (index < 0)
+ return index;
+
+ ret = meson_gpio_irq_type_setup(type, domain_data->base,
+ index);
+ if (ret)
+ return ret;
+
+ cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+ if (!cd)
+ return -ENOMEM;
+
+ cd->base = domain_data->base;
+ cd->index = index;
+
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &meson_gpio_irq_chip, cd);
+
+ ret = meson_gpio_irq_allocate_gic_irq(domain, virq + i,
+ source, type);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void meson_gpio_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct meson_gpio_irq_domain *domain_data = domain->host_data;
+ struct meson_gpio_irq_chip_data *cd;
+ struct irq_data *irq_data;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ cd = irq_data_get_irq_chip_data(irq_data);
+
+ domain_data->map[cd->index] = IRQ_FREE;
+ kfree(cd);
+ }
+
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+
+}
+
+static const struct irq_domain_ops meson_gpio_irq_domain_ops = {
+ .alloc = meson_gpio_irq_domain_alloc,
+ .free = meson_gpio_irq_domain_free,
+ .translate = meson_gpio_irq_domain_translate,
+};
+
+static int __init
+meson_gpio_irq_init_domain(struct device_node *node,
+ struct meson_gpio_irq_domain *domain_data,
+ const struct meson_gpio_irq_params *params)
+{
+ int i;
+ int nsource = params->nsource;
+ int *map;
+
+ map = kcalloc(nsource, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ for (i = 0; i < nsource; i++)
+ map[i] = IRQ_FREE;
+
+ domain_data->map = map;
+ domain_data->params = params;
+
+ return 0;
+}
+
+static int __init meson_gpio_irq_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *domain, *parent_domain;
+ const struct of_device_id *match;
+ const struct meson_gpio_irq_params *params;
+ struct meson_gpio_irq_domain *domain_data;
+ int ret;
+
+ match = of_match_node(meson_irq_gpio_matches, node);
+ if (!match)
+ return -ENODEV;
+ params = match->data;
+
+ if (!parent) {
+ pr_err("missing parent interrupt node\n");
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("unable to obtain parent domain\n");
+ return -ENXIO;
+ }
+
+ domain_data = kzalloc(sizeof(*domain_data), GFP_KERNEL);
+ if (!domain_data)
+ return -ENOMEM;
+
+ domain_data->base = of_iomap(node, 0);
+ if (!domain_data->base) {
+ ret = -ENOMEM;
+ goto out_free_dev;
+ }
+
+ ret = meson_gpio_irq_init_domain(node, domain_data, params);
+ if (ret < 0)
+ goto out_free_dev_content;
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, params->nhwirq,
+ node, &meson_gpio_irq_domain_ops,
+ domain_data);
+
+ if (!domain) {
+ pr_err("failed to allocated domain\n");
+ ret = -ENOMEM;
+ goto out_free_dev_content;
+ }
+
+ pr_info("%d to %d gpio interrupt mux initialized\n",
+ params->nhwirq, params->nsource);
+
+ return 0;
+
+out_free_dev_content:
+ kfree(domain_data->map);
+ iounmap(domain_data->base);
+
+out_free_dev:
+ kfree(domain_data);
+
+ return ret;
+}
+
+IRQCHIP_DECLARE(meson8_gpio_intc, "amlogic,meson8-gpio-intc",
+ meson_gpio_irq_of_init);
+IRQCHIP_DECLARE(meson8b_gpio_intc, "amlogic,meson8b-gpio-intc",
+ meson_gpio_irq_of_init);
+IRQCHIP_DECLARE(gxbb_gpio_intc, "amlogic,meson-gxbb-gpio-intc",
+ meson_gpio_irq_of_init);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 0/9] irqchip: meson: add support for the gpio interrupt controller
From: Jerome Brunet @ 2016-10-19 15:21 UTC (permalink / raw)
To: linux-arm-kernel
This patch series adds support for the GPIO interrupt controller found
on Amlogic's meson SoC families.
Unlike what the name suggests, this controller is not part of the SoC GPIO
subsystem. It's an indepedent controller which can watch almost all pad of
the SoC and generate and interrupt from it. Some pins, which are not part
of the public datasheet, don't seem to have this capability though.
Hardware wise, the controller is a 256 to 8 multiplexer. It can take up
to 256 input pads and route them to any of 8 GIC's interrupts. There is
also a filter block in the middle to select the appropriate edge or level.
The number of interrupt declared by the irqchip is lowered from 256 to the
actual number of signal routed to the controller on each SoC family. As we
have access to only 8 GIC?s interrupts, these are allocated when an
interrupt is requested from the controller, on a first come, first served
basis.
This series has been tested on Amlogic S905-P200 board with the front
panel power button. Directly passing an IRQ or using gpio_to_irq both work
with this driver.
This work is derived from the previous work of Carlo Caione [1].
Changes since RFC : [2]
* Remove interrupt property in device tree: the controller cannot generate
interrupts on its own and is merely routing the interrupt to the GIC,
therefore it should not use the interrupt property. This data is now
stored directly in the driver, same as the pinctrl data.
* Improve compatibility checking of meson pinctrl on its interrupt parent
to activate gpio_to_irq callback
* Drop IRQ_BOTH hack. Need more work to have an acceptable solution for
this
Changes since v1 : [3]
* Correct mistake in patch 4 when no compatible controller is found. Sorry
for the inconvenience.
[1] : http://lkml.kernel.org/r/1448987062-31225-1-git-send-email-carlo at caione.org
[2] : http://lkml.kernel.org/r/1475593708-10526-1-git-send-email-jbrunet at baylibre.com
[3] : http://lkml.kernel.org/r/1476871709-8359-1-git-send-email-jbrunet at baylibre.com
Jerome Brunet (9):
irqchip: meson: add support for gpio interrupt controller
dt-bindings: interrupt-controller: add DT binding for meson GPIO
interrupt controller
pinctrl: meson: update pinctrl data with gpio irq data
pinctrl: meson: allow gpio to request irq
dt-bindings: pinctrl: meson: update gpio dt-bindings
ARM64: meson: enable MESON_IRQ_GPIO in Kconfig
ARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8
ARM64: dts: amlogic: enable gpio interrupt controller on gxbb
ARM: dts: amlogic: enable gpio interrupt controller on meson8
.../amlogic,meson-gpio-intc.txt | 31 ++
.../devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 +
arch/arm/boot/dts/meson8.dtsi | 11 +
arch/arm/boot/dts/meson8b.dtsi | 11 +
arch/arm/mach-meson/Kconfig | 2 +
arch/arm64/Kconfig.platforms | 1 +
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +
drivers/irqchip/Kconfig | 9 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-meson-gpio.c | 423 +++++++++++++++++++++
drivers/pinctrl/Kconfig | 2 +
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 24 +-
drivers/pinctrl/meson/pinctrl-meson.c | 77 +++-
drivers/pinctrl/meson/pinctrl-meson.h | 17 +-
drivers/pinctrl/meson/pinctrl-meson8.c | 22 +-
drivers/pinctrl/meson/pinctrl-meson8b.c | 34 +-
16 files changed, 641 insertions(+), 37 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
create mode 100644 drivers/irqchip/irq-meson-gpio.c
--
2.7.4
^ permalink raw reply
* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Arnd Bergmann @ 2016-10-19 15:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_wJWCtQGfQv2V_tNq+zygMzbassEa92c5sx90w0TW4vw@mail.gmail.com>
On Wednesday, October 19, 2016 4:01:58 PM CEST Ard Biesheuvel wrote:
> On 19 October 2016 at 15:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> > On 19 October 2016 at 14:35, Will Deacon <will.deacon@arm.com> wrote:
> >> On Mon, Oct 17, 2016 at 08:43:19PM +0100, Ard Biesheuvel wrote:
> >>> On 17 October 2016 at 19:38, Will Deacon <will.deacon@arm.com> wrote:
> >
> > Yes, and that would be perfectly legal from a correctness point of
> > view, and would likely help performance as well. By using
> > __builtin_constant_p(), you are choosing to perform a build time
> > evaluation of an expression that would ordinarily be evaluated only at
> > runtime. This implies that you have to address undefined behavior at
> > build time rather than at runtime as well.
> >
> >>> If order_base_2() is not defined for input 0, it should BUG() in that
> >>> case, and the associated __builtin_unreachable() should prevent the
> >>> special version from being emitted. If order_base_2() is defined for input
> >>> 0, it should not invoke ilog2() with that argument, and the problem should
> >>> go away as well.
> >>
> >> I don't necessarily think it should BUG() if it's not defined for input
> >> 0; things like __ffs don't do that and we'd be introducing conditional
> >> checks for cases that should not happen. The comment above order_base_2
> >> does suggest that ob2(0) should return 0, but it can actually end up
> >> invoking ilog2(-1), which is obviously wrong.
> >>
> >> I could update the comment, but that doesn't fix the build issue.
> >>
> >
> > Fixing roundup_pow_of_two() [which is arguably incorrect]
>
> I just spotted the comment that says it is undefined. But that means
> it could legally return 1 for input 0, i suppose
I think having the link error in roundup_pow_of_two() is safer than
returning 1.
Why not turn it into a runtime warning in this driver?
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index cecb0fdfaef6..711d1d9842cc 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -349,8 +349,10 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
rate->reg = reg + (u64)rate->reg;
for (clkt = rate->table; clkt->div; clkt++)
table_size++;
- rate->width = order_base_2(table_size);
- rate->lock = lock;
+ if (!WARN_ON(table_size == 0)) {
+ rate->width = order_base_2(table_size);
+ rate->lock = lock;
+ }
}
}
Arnd
^ permalink raw reply related
* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Ard Biesheuvel @ 2016-10-19 15:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_ts83bKc4mYujf7NnzGVHoxP7TXgHbFxSgb9LkxH=wXQ@mail.gmail.com>
On 19 October 2016 at 15:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 19 October 2016 at 14:35, Will Deacon <will.deacon@arm.com> wrote:
>> Hi Ard,
>>
>> On Mon, Oct 17, 2016 at 08:43:19PM +0100, Ard Biesheuvel wrote:
>>> On 17 October 2016 at 19:38, Will Deacon <will.deacon@arm.com> wrote:
>>> > I'm seeing an arm64 build failure with -rc1 and GCC trunk, although I
>>> > believe that the new compiler behaviour at the heart of the problem
>>> > has the potential to affect other architectures and other pieces of
>>> > kernel code relying on dead-code elimination to remove deliberately
>>> > undefined functions.
>>> >
>>> > The failure looks like:
>>> >
>>> > | drivers/built-in.o: In function `armada_3700_add_composite_clk':
>>> > |
>>> > | linux/drivers/clk/mvebu/armada-37xx-periph.c:351:
>>> > | undefined reference to `____ilog2_NaN'
>>> > |
>>> > | linux/drivers/clk/mvebu/armada-37xx-periph.c:351:(.text+0xc72e0):
>>> > | relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol
>>> > | `____ilog2_NaN'
>>> > |
>>> > | make: *** [vmlinux] Error 1
>>> >
>>> > and if we look at the source for armada_3700_add_composite_clk, we see
>>> > that this is caused by:
>>> >
>>> > int table_size = 0;
>>> >
>>> > rate->reg = reg + (u64)rate->reg;
>>> > for (clkt = rate->table; clkt->div; clkt++)
>>> > table_size++;
>>> > rate->width = order_base_2(table_size);
>>> >
>>> > order_base_2 calls ilog2, which has the ____ilog2_NaN call:
>>> >
>>> > #define ilog2(n) \
>>> > ( \
>>> > __builtin_constant_p(n) ? ( \
>>> > (n) < 1 ? ____ilog2_NaN() : \
>>> >
>>> > This is because we're in a curious case where GCC has emitted a
>>> > special-cased version of armada_3700_add_composite_clk, with table_size
>>> > effectively constant-folded as 0. Whilst we shouldn't see this in a
>>> > non-buggy kernel (hence the deliberate call to the undefined function
>>> > ____ilog2_NaN), it means that the final link fails because we have a
>>> > ____ilog2_NaN in the code, with a runtime check on table_size.
>>> >
>>>
>>> This is indeed an unintended side effect, but I would not call it
>>> weird behaviour at all. The code in its current form does not handle
>>> the case where it could end up passing 0 into order_base_2(), and we
>>> simply need to handle that case.
>>
>> The reasons I think it's weird are:
>>
>> (1) The optimisation doesn't generate better code in this case --
>> optimising for the table_size == 0 case is uninformed, particularly
>> as that *cannot* happen at runtime (GCC probably can't tell, due
>> to things like container_of, but all the clock data is static).
>>
>
> AFAICT, the references to the static clock data are indirected via
> of_device_get_match_data(), which means there is no way the compiler
> can prove that table_size is always non-zero.
>
>> (2) __builtin_constant_p(n) could be interpreted by a developer as
>> "this code will execute with a constant n at runtime". With this
>> issue, GCC could (in theory) generate a specialisation for every
>> possible value of a variable, and return __builtin_constant_p as
>> true for all of them, which somewhat undermines the point of the
>> builtin.
>>
>
> Yes, and that would be perfectly legal from a correctness point of
> view, and would likely help performance as well. By using
> __builtin_constant_p(), you are choosing to perform a build time
> evaluation of an expression that would ordinarily be evaluated only at
> runtime. This implies that you have to address undefined behavior at
> build time rather than at runtime as well.
>
>>> If order_base_2() is not defined for input 0, it should BUG() in that
>>> case, and the associated __builtin_unreachable() should prevent the
>>> special version from being emitted. If order_base_2() is defined for input
>>> 0, it should not invoke ilog2() with that argument, and the problem should
>>> go away as well.
>>
>> I don't necessarily think it should BUG() if it's not defined for input
>> 0; things like __ffs don't do that and we'd be introducing conditional
>> checks for cases that should not happen. The comment above order_base_2
>> does suggest that ob2(0) should return 0, but it can actually end up
>> invoking ilog2(-1), which is obviously wrong.
>>
>> I could update the comment, but that doesn't fix the build issue.
>>
>
> Fixing roundup_pow_of_two() [which is arguably incorrect]
I just spotted the comment that says it is undefined. But that means
it could legally return 1 for input 0, i suppose
> would
> probably fix the build issue as well, no?
>
> diff --git a/include/linux/log2.h b/include/linux/log2.h
> index fd7ff3d91e6a..8a4be5e4223b 100644
> --- a/include/linux/log2.h
> +++ b/include/linux/log2.h
> @@ -168,7 +168,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
> #define roundup_pow_of_two(n) \
> ( \
> __builtin_constant_p(n) ? ( \
> - (n == 1) ? 1 : \
> + (n <= 1) ? 1 : \
> (1UL << (ilog2((n) - 1) + 1)) \
> ) : \
> __roundup_pow_of_two(n) \
^ permalink raw reply
* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Ard Biesheuvel @ 2016-10-19 14:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161019133500.GQ9193@arm.com>
On 19 October 2016 at 14:35, Will Deacon <will.deacon@arm.com> wrote:
> Hi Ard,
>
> On Mon, Oct 17, 2016 at 08:43:19PM +0100, Ard Biesheuvel wrote:
>> On 17 October 2016 at 19:38, Will Deacon <will.deacon@arm.com> wrote:
>> > I'm seeing an arm64 build failure with -rc1 and GCC trunk, although I
>> > believe that the new compiler behaviour at the heart of the problem
>> > has the potential to affect other architectures and other pieces of
>> > kernel code relying on dead-code elimination to remove deliberately
>> > undefined functions.
>> >
>> > The failure looks like:
>> >
>> > | drivers/built-in.o: In function `armada_3700_add_composite_clk':
>> > |
>> > | linux/drivers/clk/mvebu/armada-37xx-periph.c:351:
>> > | undefined reference to `____ilog2_NaN'
>> > |
>> > | linux/drivers/clk/mvebu/armada-37xx-periph.c:351:(.text+0xc72e0):
>> > | relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol
>> > | `____ilog2_NaN'
>> > |
>> > | make: *** [vmlinux] Error 1
>> >
>> > and if we look at the source for armada_3700_add_composite_clk, we see
>> > that this is caused by:
>> >
>> > int table_size = 0;
>> >
>> > rate->reg = reg + (u64)rate->reg;
>> > for (clkt = rate->table; clkt->div; clkt++)
>> > table_size++;
>> > rate->width = order_base_2(table_size);
>> >
>> > order_base_2 calls ilog2, which has the ____ilog2_NaN call:
>> >
>> > #define ilog2(n) \
>> > ( \
>> > __builtin_constant_p(n) ? ( \
>> > (n) < 1 ? ____ilog2_NaN() : \
>> >
>> > This is because we're in a curious case where GCC has emitted a
>> > special-cased version of armada_3700_add_composite_clk, with table_size
>> > effectively constant-folded as 0. Whilst we shouldn't see this in a
>> > non-buggy kernel (hence the deliberate call to the undefined function
>> > ____ilog2_NaN), it means that the final link fails because we have a
>> > ____ilog2_NaN in the code, with a runtime check on table_size.
>> >
>>
>> This is indeed an unintended side effect, but I would not call it
>> weird behaviour at all. The code in its current form does not handle
>> the case where it could end up passing 0 into order_base_2(), and we
>> simply need to handle that case.
>
> The reasons I think it's weird are:
>
> (1) The optimisation doesn't generate better code in this case --
> optimising for the table_size == 0 case is uninformed, particularly
> as that *cannot* happen at runtime (GCC probably can't tell, due
> to things like container_of, but all the clock data is static).
>
AFAICT, the references to the static clock data are indirected via
of_device_get_match_data(), which means there is no way the compiler
can prove that table_size is always non-zero.
> (2) __builtin_constant_p(n) could be interpreted by a developer as
> "this code will execute with a constant n at runtime". With this
> issue, GCC could (in theory) generate a specialisation for every
> possible value of a variable, and return __builtin_constant_p as
> true for all of them, which somewhat undermines the point of the
> builtin.
>
Yes, and that would be perfectly legal from a correctness point of
view, and would likely help performance as well. By using
__builtin_constant_p(), you are choosing to perform a build time
evaluation of an expression that would ordinarily be evaluated only at
runtime. This implies that you have to address undefined behavior at
build time rather than at runtime as well.
>> If order_base_2() is not defined for input 0, it should BUG() in that
>> case, and the associated __builtin_unreachable() should prevent the
>> special version from being emitted. If order_base_2() is defined for input
>> 0, it should not invoke ilog2() with that argument, and the problem should
>> go away as well.
>
> I don't necessarily think it should BUG() if it's not defined for input
> 0; things like __ffs don't do that and we'd be introducing conditional
> checks for cases that should not happen. The comment above order_base_2
> does suggest that ob2(0) should return 0, but it can actually end up
> invoking ilog2(-1), which is obviously wrong.
>
> I could update the comment, but that doesn't fix the build issue.
>
Fixing roundup_pow_of_two() [which is arguably incorrect] would
probably fix the build issue as well, no?
diff --git a/include/linux/log2.h b/include/linux/log2.h
index fd7ff3d91e6a..8a4be5e4223b 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -168,7 +168,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
#define roundup_pow_of_two(n) \
( \
__builtin_constant_p(n) ? ( \
- (n == 1) ? 1 : \
+ (n <= 1) ? 1 : \
(1UL << (ilog2((n) - 1) + 1)) \
) : \
__roundup_pow_of_two(n) \
^ permalink raw reply related
* [PATCH] mtd: nand: Add OX820 NAND Support
From: Neil Armstrong @ 2016-10-19 14:55 UTC (permalink / raw)
To: linux-arm-kernel
Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
This is a simple memory mapped NAND controller with single chip select and
software ECC.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
.../devicetree/bindings/mtd/oxnas-nand.txt | 24 +++
drivers/mtd/nand/Kconfig | 5 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/oxnas_nand.c | 204 +++++++++++++++++++++
4 files changed, 234 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
create mode 100644 drivers/mtd/nand/oxnas_nand.c
Changes since RFC http://lkml.kernel.org/r/20161018090927.1990-1-narmstrong at baylibre.com :
- Avoid using chip->IO_ADDR*
- Use new DT structure
- Assign a chip for the subnode
- Use the nand_hw_control structure
- Cleanup probe
- Cleanup cmd_ctrl by using a context ctrl offset used in write_bytes
diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644
index 0000000..83b684d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
@@ -0,0 +1,24 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nand: nand at 41000000 {
+ compatible = "oxsemi,ox820-nand";
+ reg = <0x41000000 0x100000>;
+ nand-ecc-mode = "soft";
+ clocks = <&stdclk CLK_820_NAND>;
+ resets = <&reset RESET_NAND>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..c023125 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,11 @@ config MTD_NAND_ORION
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
+config MTD_NAND_OXNAS
+ tristate "NAND Flash support for Oxford Semiconductor SoC"
+ help
+ This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f..05fc054 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 0000000..a9fe1ac
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,204 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE BIT(18)
+#define OXNAS_NAND_CMD_CLE BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS 1
+
+struct oxnas_nand {
+ struct nand_hw_control base;
+ void __iomem *io_base;
+ struct clk *clk;
+ struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+ unsigned long ctrl;
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+ return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+ ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+ iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct oxnas_nand *oxnas = nand_get_controller_data(chip);
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_CLE)
+ oxnas->ctrl = OXNAS_NAND_CMD_CLE;
+ else if (ctrl & NAND_ALE)
+ oxnas->ctrl = OXNAS_NAND_CMD_ALE;
+ else
+ oxnas->ctrl = 0;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, oxnas->io_base + oxnas->ctrl);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *nand_np;
+ struct oxnas_nand *oxnas;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ struct resource *res;
+ int nchips = 0;
+ int count = 0;
+ int err = 0;
+
+ /* Allocate memory for the device structure (and zero it) */
+ oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+ GFP_KERNEL);
+ if (!oxnas)
+ return -ENOMEM;
+
+ nand_hw_control_init(&oxnas->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(oxnas->io_base))
+ return PTR_ERR(oxnas->io_base);
+
+ oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(oxnas->clk))
+ oxnas->clk = NULL;
+
+ /* Only a single chip node is supported */
+ count = of_get_child_count(np);
+ if (count > 1)
+ return -EINVAL;
+
+ clk_prepare_enable(oxnas->clk);
+ device_reset_optional(&pdev->dev);
+
+ for_each_child_of_node(np, nand_np) {
+ chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+ GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->controller = &oxnas->base;
+
+ nand_set_flash_node(chip, nand_np);
+ nand_set_controller_data(chip, oxnas);
+
+ mtd = nand_to_mtd(chip);
+ mtd->dev.parent = &pdev->dev;
+ mtd->priv = chip;
+
+ chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+ chip->read_buf = oxnas_nand_read_buf;
+ chip->read_byte = oxnas_nand_read_byte;
+ chip->write_buf = oxnas_nand_write_buf;
+ chip->chip_delay = 30;
+
+ /* Scan to find existence of the device */
+ err = nand_scan(mtd, 1);
+ if (err)
+ return err;
+
+ err = mtd_device_register(mtd, NULL, 0);
+ if (err) {
+ nand_release(mtd);
+ return err;
+ }
+
+ oxnas->chips[nchips] = chip;
+ ++nchips;
+ }
+
+ /* Exit if no chips found */
+ if (!nchips)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, oxnas);
+
+ return 0;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+ struct oxnas_nand *oxnas = platform_get_drvdata(pdev);
+
+ if (oxnas->chips[0])
+ nand_release(nand_to_mtd(oxnas->chips[0]));
+
+ clk_disable_unprepare(oxnas->clk);
+
+ return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+ { .compatible = "oxsemi,ox820-nand" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+ .probe = oxnas_nand_probe,
+ .remove = oxnas_nand_remove,
+ .driver = {
+ .name = "oxnas_nand",
+ .of_match_table = oxnas_nand_match,
+ },
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
--
2.7.0
^ permalink raw reply related
* [PATCH v5 0/5] Add support for legacy SCPI protocol
From: Sudeep Holla @ 2016-10-19 14:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476881472-13055-1-git-send-email-narmstrong@baylibre.com>
On 19/10/16 13:51, Neil Armstrong wrote:
> This patchset aims to support the legacy SCPI firmware implementation that was
> delivered as early technology preview for the JUNO platform.
>
> Finally a stable, maintained and public implementation for the SCPI protocol
> has been upstreamed part of the JUNO support and it is the recommended way
> of implementing SCP communication on ARMv8 platforms.
>
> The Amlogic GXBB platform is using this legacy protocol, as the RK3368 & RK3399
> platforms. This patchset will only add support for Amlogic GXBB SoC.
>
> This patchset add support for the legacy protocol in the arm_scpi.c file,
> avoiding code duplication.
>
> This patchset is rebased against scpi-updates/for-next from [2] and with
> already merged patches [3], [4] and [5] and ommited in this patchset.
>
> Last RFC discution thread can be found at : https://lkml.org/lkml/2016/8/9/210
>
> Changes since v4 at : http://lkml.kernel.org/r/1475652814-30619-1-git-send-email-narmstrong at baylibre.com
> - Removed legacy locking scheme
> - Removed cmd copy back after token insert
> - Various cleanups
>
> Changes since v3 at : http://lkml.kernel.org/r/1473262477-18045-1-git-send-email-narmstrong at baylibre.com
> - Changed back author to Sudeep Holla for first patch
> - Merged legacy functions to scpi_send_message, tx_prepare and handle_remote_message
> - Added legacy locking scheme
> - Merged back legacy_scpi_sensor_get_value into scpi_sensor_get_value
> - Rebased on linux-next-20161004 with patchset [1]
>
> Changes since v2 at : http://lkml.kernel.org/r/1471952816-30877-1-git-send-email-narmstrong at baylibre.com
> - Added command indirection table and use it in each commands
> - Added bitmap for high priority commands
> - Cleaned up legacy tx_prepare/handle_message to align to standard functions
> - Dropped legacy_scpi_ops
>
> Changes since v1 at : http://lkml.kernel.org/r/1471515066-3626-1-git-send-email-narmstrong at baylibre.com
> - Dropped vendor_send_message and rockchip vendor mechanism patches
> - Merged alternate functions into main functions using is_legacy boolean
> - Added DT match table to set is_legacy to true
> - Kept alternate scpi_ops structure for legacy
>
> [1] http://lkml.kernel.org/r/1475595430-30075-1-git-send-email-narmstrong at baylibre.com
> [2] git.kernel.org/sudeep.holla/linux
> [3] scpi: Add cmd indirection table to prepare for legacy commands
> [4] scpi: grow MAX_DVFS_OPPS to 16 entries
> [5] dt-bindings: Add support for Amlogic GXBB SCPI Interface
>
> Neil Armstrong (5):
> scpi: Add alternative legacy structures, functions and macros
> scpi: Do not fail if get_capabilities is not implemented
> scpi: Add support for Legacy match table for Amlogic GXBB SoC
> ARM64: dts: meson-gxbb: Add SRAM node
> ARM64: dts: meson-gxbb: Add SCPI with cpufreq & sensors Nodes
>
> arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 57 ++++++++
> drivers/firmware/arm_scpi.c | 206 +++++++++++++++++++++++++---
> 2 files changed, 245 insertions(+), 18 deletions(-)
>
Nice to see this diff stat from a whole new file legacy_scpi.c and 1000+
delta. Thanks for working on this. I have applied the first 3 patches in
this series with some subject/commit message changes to [1].
I assume the DT changes needs to go via the corresponding platform
maintainer.
--
Regards,
Sudeep
[1] git.kernel.org/sudeep.holla/linux/h/scpi-updates/for-next
^ permalink raw reply
* [PATCH v2 0/2] ARM: at91: properly handle LPDDR poweroff
From: Nicolas Ferre @ 2016-10-19 14:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMuHMdUnoHPOQeO=oSRkNWbfLGDzZbBZvPFr3dS7TOKPQFcUxQ@mail.gmail.com>
Le 19/10/2016 ? 16:07, Geert Uytterhoeven a ?crit :
> On Wed, Oct 19, 2016 at 1:44 PM, Alexandre Belloni
> <alexandre.belloni@free-electrons.com> wrote:
>> LPDDR memories can only handle up to 400 uncontrolled power offs in their
>> life. The proper power off sequence has to be applied before shutting down the
>> SoC.
>
> Interesting. How many boards have been killed during kernelci.org
> operation?
The reason given above is usually the one that prevent manufacturers
from using LPDDR on "evaluation" boards. So all Atmel boards use
SDRAM/DDR2/DDR3 not the LP variants.
Final products (and internal validation boards, obviously) though use
these type of RAM so we must be prepared to handle them.
Best regards,
--
Nicolas Ferre
^ permalink raw reply
* [PATCH 2/2] arm64: percpu: rewrite ll/sc loops in assembly
From: Mark Rutland @ 2016-10-19 14:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476874784-16214-2-git-send-email-will.deacon@arm.com>
On Wed, Oct 19, 2016 at 11:59:44AM +0100, Will Deacon wrote:
> Writing the outer loop of an LL/SC sequence using do {...} while
> constructs potentially allows the compiler to hoist memory accesses
> between the STXR and the branch back to the LDXR. On CPUs that do not
> guarantee forward progress of LL/SC loops when faced with memory
> accesses to the same ERG (up to 2k) between the failed STXR and the
> branch back, we may end up livelocking.
>
> This patch avoids this issue in our percpu atomics by rewriting the
> outer loop as part of the LL/SC inline assembly block.
>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
The new templates look correct to me, and appear to have been duplicated
correctly for each different size of access. My machines boot happily
with this applied, so FWIW:
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
I take it this (and the previous patch) will be Cc'd to stable?
As an aside, I have a local patch which gets rid of the duplication
here; I'll rebase that and send it out once this is in.
Thanks,
Mark.
> ---
> arch/arm64/include/asm/percpu.h | 120 +++++++++++++++++++---------------------
> 1 file changed, 56 insertions(+), 64 deletions(-)
>
> diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
> index 2fee2f59288c..5394c8405e66 100644
> --- a/arch/arm64/include/asm/percpu.h
> +++ b/arch/arm64/include/asm/percpu.h
> @@ -44,48 +44,44 @@ static inline unsigned long __percpu_##op(void *ptr, \
> \
> switch (size) { \
> case 1: \
> - do { \
> - asm ("//__per_cpu_" #op "_1\n" \
> - "ldxrb %w[ret], %[ptr]\n" \
> + asm ("//__per_cpu_" #op "_1\n" \
> + "1: ldxrb %w[ret], %[ptr]\n" \
> #asm_op " %w[ret], %w[ret], %w[val]\n" \
> - "stxrb %w[loop], %w[ret], %[ptr]\n" \
> - : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> - [ptr] "+Q"(*(u8 *)ptr) \
> - : [val] "Ir" (val)); \
> - } while (loop); \
> + " stxrb %w[loop], %w[ret], %[ptr]\n" \
> + " cbnz %w[loop], 1b" \
> + : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> + [ptr] "+Q"(*(u8 *)ptr) \
> + : [val] "Ir" (val)); \
> break; \
> case 2: \
> - do { \
> - asm ("//__per_cpu_" #op "_2\n" \
> - "ldxrh %w[ret], %[ptr]\n" \
> + asm ("//__per_cpu_" #op "_2\n" \
> + "1: ldxrh %w[ret], %[ptr]\n" \
> #asm_op " %w[ret], %w[ret], %w[val]\n" \
> - "stxrh %w[loop], %w[ret], %[ptr]\n" \
> - : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> - [ptr] "+Q"(*(u16 *)ptr) \
> - : [val] "Ir" (val)); \
> - } while (loop); \
> + " stxrh %w[loop], %w[ret], %[ptr]\n" \
> + " cbnz %w[loop], 1b" \
> + : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> + [ptr] "+Q"(*(u16 *)ptr) \
> + : [val] "Ir" (val)); \
> break; \
> case 4: \
> - do { \
> - asm ("//__per_cpu_" #op "_4\n" \
> - "ldxr %w[ret], %[ptr]\n" \
> + asm ("//__per_cpu_" #op "_4\n" \
> + "1: ldxr %w[ret], %[ptr]\n" \
> #asm_op " %w[ret], %w[ret], %w[val]\n" \
> - "stxr %w[loop], %w[ret], %[ptr]\n" \
> - : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> - [ptr] "+Q"(*(u32 *)ptr) \
> - : [val] "Ir" (val)); \
> - } while (loop); \
> + " stxr %w[loop], %w[ret], %[ptr]\n" \
> + " cbnz %w[loop], 1b" \
> + : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> + [ptr] "+Q"(*(u32 *)ptr) \
> + : [val] "Ir" (val)); \
> break; \
> case 8: \
> - do { \
> - asm ("//__per_cpu_" #op "_8\n" \
> - "ldxr %[ret], %[ptr]\n" \
> + asm ("//__per_cpu_" #op "_8\n" \
> + "1: ldxr %[ret], %[ptr]\n" \
> #asm_op " %[ret], %[ret], %[val]\n" \
> - "stxr %w[loop], %[ret], %[ptr]\n" \
> - : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> - [ptr] "+Q"(*(u64 *)ptr) \
> - : [val] "Ir" (val)); \
> - } while (loop); \
> + " stxr %w[loop], %[ret], %[ptr]\n" \
> + " cbnz %w[loop], 1b" \
> + : [loop] "=&r" (loop), [ret] "=&r" (ret), \
> + [ptr] "+Q"(*(u64 *)ptr) \
> + : [val] "Ir" (val)); \
> break; \
> default: \
> BUILD_BUG(); \
> @@ -150,44 +146,40 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
>
> switch (size) {
> case 1:
> - do {
> - asm ("//__percpu_xchg_1\n"
> - "ldxrb %w[ret], %[ptr]\n"
> - "stxrb %w[loop], %w[val], %[ptr]\n"
> - : [loop] "=&r"(loop), [ret] "=&r"(ret),
> - [ptr] "+Q"(*(u8 *)ptr)
> - : [val] "r" (val));
> - } while (loop);
> + asm ("//__percpu_xchg_1\n"
> + "1: ldxrb %w[ret], %[ptr]\n"
> + " stxrb %w[loop], %w[val], %[ptr]\n"
> + " cbnz %w[loop], 1b"
> + : [loop] "=&r"(loop), [ret] "=&r"(ret),
> + [ptr] "+Q"(*(u8 *)ptr)
> + : [val] "r" (val));
> break;
> case 2:
> - do {
> - asm ("//__percpu_xchg_2\n"
> - "ldxrh %w[ret], %[ptr]\n"
> - "stxrh %w[loop], %w[val], %[ptr]\n"
> - : [loop] "=&r"(loop), [ret] "=&r"(ret),
> - [ptr] "+Q"(*(u16 *)ptr)
> - : [val] "r" (val));
> - } while (loop);
> + asm ("//__percpu_xchg_2\n"
> + "1: ldxrh %w[ret], %[ptr]\n"
> + " stxrh %w[loop], %w[val], %[ptr]\n"
> + " cbnz %w[loop], 1b"
> + : [loop] "=&r"(loop), [ret] "=&r"(ret),
> + [ptr] "+Q"(*(u16 *)ptr)
> + : [val] "r" (val));
> break;
> case 4:
> - do {
> - asm ("//__percpu_xchg_4\n"
> - "ldxr %w[ret], %[ptr]\n"
> - "stxr %w[loop], %w[val], %[ptr]\n"
> - : [loop] "=&r"(loop), [ret] "=&r"(ret),
> - [ptr] "+Q"(*(u32 *)ptr)
> - : [val] "r" (val));
> - } while (loop);
> + asm ("//__percpu_xchg_4\n"
> + "1: ldxr %w[ret], %[ptr]\n"
> + " stxr %w[loop], %w[val], %[ptr]\n"
> + " cbnz %w[loop], 1b"
> + : [loop] "=&r"(loop), [ret] "=&r"(ret),
> + [ptr] "+Q"(*(u32 *)ptr)
> + : [val] "r" (val));
> break;
> case 8:
> - do {
> - asm ("//__percpu_xchg_8\n"
> - "ldxr %[ret], %[ptr]\n"
> - "stxr %w[loop], %[val], %[ptr]\n"
> - : [loop] "=&r"(loop), [ret] "=&r"(ret),
> - [ptr] "+Q"(*(u64 *)ptr)
> - : [val] "r" (val));
> - } while (loop);
> + asm ("//__percpu_xchg_8\n"
> + "1: ldxr %[ret], %[ptr]\n"
> + " stxr %w[loop], %[val], %[ptr]\n"
> + " cbnz %w[loop], 1b"
> + : [loop] "=&r"(loop), [ret] "=&r"(ret),
> + [ptr] "+Q"(*(u64 *)ptr)
> + : [val] "r" (val));
> break;
> default:
> BUILD_BUG();
> --
> 2.1.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* [PATCH V2] gpu/drm/exynos/exynos_hdmi - Unmap region obtained by of_iomap
From: Inki Dae @ 2016-10-19 14:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871456-1098-1-git-send-email-arvind.yadav.cs@gmail.com>
Will pick it up soon.
Thanks,
Inki Dae
2016-10-19 19:04 GMT+09:00 Arvind Yadav <arvind.yadav.cs@gmail.com>:
> Free memory mapping, if hdmi_probe is not successful.
>
> Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
> ---
> drivers/gpu/drm/exynos/exynos_hdmi.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index 2275efe..ba28dec 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -1901,6 +1901,8 @@ err_disable_pm_runtime:
> err_hdmiphy:
> if (hdata->hdmiphy_port)
> put_device(&hdata->hdmiphy_port->dev);
> + if (hdata->regs_hdmiphy)
> + iounmap(hdata->regs_hdmiphy);
> err_ddc:
> put_device(&hdata->ddc_adpt->dev);
>
> @@ -1923,6 +1925,9 @@ static int hdmi_remove(struct platform_device *pdev)
> if (hdata->hdmiphy_port)
> put_device(&hdata->hdmiphy_port->dev);
>
> + if (hdata->regs_hdmiphy)
> + iounmap(hdata->regs_hdmiphy);
> +
> put_device(&hdata->ddc_adpt->dev);
>
> return 0;
> --
> 1.7.9.5
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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