Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Will Deacon @ 2016-10-19 16:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+55aFx=ZX=7u07R6zJ7fSw=zSQNaYqVX7R3LQs4riiEf+uA=A@mail.gmail.com>

On Wed, Oct 19, 2016 at 09:01:33AM -0700, Linus Torvalds wrote:
> On Wed, Oct 19, 2016 at 8:56 AM, Markus Trippelsdorf
> <markus@trippelsdorf.de> wrote:
> > On 2016.10.19 at 08:55 -0700, Linus Torvalds wrote:
> >>
> >> Well, in the meantime we apparently have to live with it. Unless Will
> >> is using some unreleased gcc version that nobody else is using and we
> >> can just ignore it?
> >
> > Yes, he is using gcc-7 that is unreleased. (It will be released April
> > next year.)
> 
> Ahh, self-built? So it's not part of some experimental ARM distro
> setup and this will be annoying lots of people?

Our friendly compiler guys built it, but it's just a snapshot of trunk,
so it's all heading towards GCC 7.0. AFAIU, the problematic optimisation
is also a mid-end pass, so it would affect other architectures too.

> If so, still think that we could just get rid of the ____ilog2_NaN()
> thing as it's not _that_ important, but it's certainly not very
> high-priority. Will can do it in his tree too for testing, and it can
> remind people to get the gcc problem fixed.

I'm carrying the diff below, which fixes arm64 defconfig, but I'm worried
that we might be relying on this trick elsewhere. The arm __bad_cmpxchg
function, for example.

Will

--->8

diff --git a/include/linux/log2.h b/include/linux/log2.h
index fd7ff3d91e6a..9cf5ad69065d 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -16,12 +16,6 @@
 #include <linux/bitops.h>
 
 /*
- * deal with unrepresentable constant logarithms
- */
-extern __attribute__((const, noreturn))
-int ____ilog2_NaN(void);
-
-/*
  * non-constant log of base 2 calculators
  * - the arch may override these in asm/bitops.h if they can be implemented
  *   more efficiently than using fls() and fls64()
@@ -85,7 +79,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
 #define ilog2(n)				\
 (						\
 	__builtin_constant_p(n) ? (		\
-		(n) < 1 ? ____ilog2_NaN() :	\
+		(n) < 1 ? 0 :			\
 		(n) & (1ULL << 63) ? 63 :	\
 		(n) & (1ULL << 62) ? 62 :	\
 		(n) & (1ULL << 61) ? 61 :	\
@@ -149,9 +143,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
 		(n) & (1ULL <<  3) ?  3 :	\
 		(n) & (1ULL <<  2) ?  2 :	\
 		(n) & (1ULL <<  1) ?  1 :	\
-		(n) & (1ULL <<  0) ?  0 :	\
-		____ilog2_NaN()			\
-				   ) :		\
+		0) :				\
 	(sizeof(n) <= 4) ?			\
 	__ilog2_u32(n) :			\
 	__ilog2_u64(n)				\
@@ -194,7 +186,6 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
  * @n: parameter
  *
  * The first few values calculated by this routine:
- *  ob2(0) = 0
  *  ob2(1) = 0
  *  ob2(2) = 1
  *  ob2(3) = 2

^ permalink raw reply related

* [PATCH] mtd: nand: Add OX820 NAND Support
From: Boris Brezillon @ 2016-10-19 16:21 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>
> ---
>  .../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 {

One last thing, please rename the struct: oxnas_nandc, oxnas_nand_ctrl
or oxnas_nand_controller. Pick the one you prefer or choose another
one, I don't care, as long as the name clearly shows that this is a NAND
controller and not the NAND chip.

> +	struct nand_hw_control base;
> +	void __iomem *io_base;
> +	struct clk *clk;
> +	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
> +	unsigned long ctrl;
> +};

^ permalink raw reply

* [PATCH v4] MMC: meson: initial support for GX platforms
From: Javier Martinez Canillas @ 2016-10-19 16:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018195605.21145-1-khilman@baylibre.com>

Hello Kevin,

On Tue, Oct 18, 2016 at 4:56 PM, Kevin Hilman <khilman@baylibre.com> wrote:
> Initial support for the SD/eMMC controller in the Amlogic S905/GX*
> family of SoCs.
>
> Signed-off-by: Kevin Hilman <khilman@baylibre.com>

[snip]

> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);

Why is this module alias needed? I thought that the Amlogic was a
DT-only platform and so devices will always be registered from OF (and
the OF modalias used).

I've seen platform module aliases in other Meson drivers too (i.e:
meson-rng and meson-pwm), so the same question applies to those.

Best regards,
Javier

^ permalink raw reply

* [PATCH v4] MMC: meson: initial support for GX platforms
From: Kevin Hilman @ 2016-10-19 16:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPDyKFps2QYq9N1erqDdCnmXJyUT60HLQDe8+gR7A571-F8NLg@mail.gmail.com>

Ulf Hansson <ulf.hansson@linaro.org> writes:

> On 18 October 2016 at 21:56, Kevin Hilman <khilman@baylibre.com> wrote:
>> Initial support for the SD/eMMC controller in the Amlogic S905/GX*
>> family of SoCs.
>>
>> Signed-off-by: Kevin Hilman <khilman@baylibre.com>
>> ---
>> Changes from v3:
>> - better handling of clock error paths
>> - rename to meson-gx to reflect support for newer SoCs
>> - has now been tested with SDIO
>>
>>  .../devicetree/bindings/mmc/amlogic,meson-gxbb.txt |  33 +
>
> Just realize this. You should split the DT doc into a separate patch,
> such the DT maintainers can ack it.

OK, I separated out the binding and sent a v5.

> Otherwise this looks good to me!

Thanks for the review!

Kevin

^ permalink raw reply

* [PATCH v5 2/2] Documentation: DT: MMC: meson-gx: new bindings doc
From: Kevin Hilman @ 2016-10-19 16:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019161205.28565-1-khilman@baylibre.com>

Signed-off-by: Kevin Hilman <khilman@baylibre.com>
---
 .../devicetree/bindings/mmc/amlogic,meson-gx.txt   | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt

diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
new file mode 100644
index 000000000000..a2fa9a1c26ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
@@ -0,0 +1,33 @@
+Amlogic SD / eMMC controller for S905/GXBB family SoCs
+
+The MMC 5.1 compliant host controller on Amlogic provides the
+interface for SD, eMMC and SDIO devices.
+
+This file documents the properties in addition to those available in
+the MMC core bindings, documented by mmc.txt.
+
+Required properties:
+- compatible : contains one of:
+  - "amlogic,meson-gx-mmc"
+  - "amlogic,meson-gxbb-mmc"
+  - "amlogic,meson-gxl-mmc"
+  - "amlogic,meson-gxm-mmc"
+- clocks     : A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
+- clock-names: Should contain the following:
+	"core" - Main peripheral bus clock
+	"clkin0" - Parent clock of internal mux
+	"clkin1" - Other parent clock of internal mux
+  The driver has an interal mux clock which switches between clkin0 and clkin1 depending on the
+  clock rate requested by the MMC core.
+
+Example:
+
+	sd_emmc_a: mmc at 70000 {
+        	compatible = "amlogic,meson-gxbb-mmc";
+		reg = <0x0 0x70000 0x0 0x2000>;
+                interrupts = < GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
+		clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>;
+		clock-names = "core", "clkin0", "clkin1";
+		pinctrl-0 = <&emmc_pins>;
+	};
+
-- 
2.9.3

^ permalink raw reply related

* [PATCH v5 1/2] MMC: meson: initial support for GX platforms
From: Kevin Hilman @ 2016-10-19 16:12 UTC (permalink / raw)
  To: linux-arm-kernel

Initial support for the SD/eMMC controller in the Amlogic S905/GX*
family of SoCs.

Signed-off-by: Kevin Hilman <khilman@baylibre.com>
---
Changes since v4: put DT documentation into a separate patch

 MAINTAINERS                 |   1 +
 drivers/mmc/host/Kconfig    |  10 +
 drivers/mmc/host/Makefile   |   1 +
 drivers/mmc/host/meson-gx.c | 853 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 865 insertions(+)
 create mode 100644 drivers/mmc/host/meson-gx.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1cd38a7e0064..73e8d64ec28c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1036,6 +1036,7 @@ F:	arch/arm/mach-meson/
 F:	arch/arm/boot/dts/meson*
 F:	arch/arm64/boot/dts/amlogic/
 F: 	drivers/pinctrl/meson/
+F:	drivers/mmc/host/meson*
 N:	meson
 
 ARM/Annapurna Labs ALPINE ARCHITECTURE
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f503a39a..5cf7ebaf1e8b 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -322,6 +322,16 @@ config MMC_SDHCI_IPROC
 
 	  If unsure, say N.
 
+config MMC_MESON_GX
+	tristate "Amlogic S905/GX* SD/MMC Host Controller support"
+	depends on ARCH_MESON && MMC
+	help
+	  This selects support for the Amlogic SD/MMC Host Controller
+	  found on the S905/GX* family of SoCs.  This controller is
+	  MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
+
+	  If you have a controller with this interface, say Y here.
+
 config MMC_MOXART
 	tristate "MOXART SD/MMC Host Controller support"
 	depends on ARCH_MOXART && MMC
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf43184..1c4852999ae4 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)	+= vub300.o
 obj-$(CONFIG_MMC_USHC)		+= ushc.o
 obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
+obj-$(CONFIG_MMC_MESON_GX)	+= meson-gx.o
 obj-$(CONFIG_MMC_MOXART)	+= moxart-mmc.o
 obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mmc.o
 obj-$(CONFIG_MMC_USDHI6ROL0)	+= usdhi6rol0.o
diff --git a/drivers/mmc/host/meson-gx.c b/drivers/mmc/host/meson-gx.c
new file mode 100644
index 000000000000..fd3c40322b2d
--- /dev/null
+++ b/drivers/mmc/host/meson-gx.c
@@ -0,0 +1,853 @@
+/*
+ * Amlogic SD/eMMC driver for the GX/S905 family SoCs
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Kevin Hilman <khilman@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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regulator/consumer.h>
+
+#define DRIVER_NAME "meson-gxbb-mmc"
+
+#define SD_EMMC_CLOCK 0x0
+#define   CLK_DIV_SHIFT 0
+#define   CLK_DIV_WIDTH 6
+#define   CLK_DIV_MASK 0x3f
+#define   CLK_DIV_MAX 63
+#define   CLK_SRC_SHIFT 6
+#define   CLK_SRC_WIDTH 2
+#define   CLK_SRC_MASK 0x3
+#define   CLK_SRC_XTAL 0   /* external crystal */
+#define   CLK_SRC_XTAL_RATE 24000000
+#define   CLK_SRC_PLL 1    /* FCLK_DIV2 */
+#define   CLK_SRC_PLL_RATE 1000000000
+#define   CLK_PHASE_SHIFT 8
+#define   CLK_PHASE_MASK 0x3
+#define   CLK_PHASE_0 0
+#define   CLK_PHASE_90 1
+#define   CLK_PHASE_180 2
+#define   CLK_PHASE_270 3
+#define   CLK_ALWAYS_ON BIT(24)
+
+#define SD_EMMC_DElAY 0x4
+#define SD_EMMC_ADJUST 0x8
+#define SD_EMMC_CALOUT 0x10
+#define SD_EMMC_START 0x40
+#define   START_DESC_INIT BIT(0)
+#define   START_DESC_BUSY BIT(1)
+#define   START_DESC_ADDR_SHIFT 2
+#define   START_DESC_ADDR_MASK (~0x3)
+
+#define SD_EMMC_CFG 0x44
+#define   CFG_BUS_WIDTH_SHIFT 0
+#define   CFG_BUS_WIDTH_MASK 0x3
+#define   CFG_BUS_WIDTH_1 0x0
+#define   CFG_BUS_WIDTH_4 0x1
+#define   CFG_BUS_WIDTH_8 0x2
+#define   CFG_DDR BIT(2)
+#define   CFG_BLK_LEN_SHIFT 4
+#define   CFG_BLK_LEN_MASK 0xf
+#define   CFG_RESP_TIMEOUT_SHIFT 8
+#define   CFG_RESP_TIMEOUT_MASK 0xf
+#define   CFG_RC_CC_SHIFT 12
+#define   CFG_RC_CC_MASK 0xf
+#define   CFG_STOP_CLOCK BIT(22)
+#define   CFG_CLK_ALWAYS_ON BIT(18)
+#define   CFG_AUTO_CLK BIT(23)
+
+#define SD_EMMC_STATUS 0x48
+#define   STATUS_BUSY BIT(31)
+
+#define SD_EMMC_IRQ_EN 0x4c
+#define   IRQ_EN_MASK 0x3fff
+#define   IRQ_RXD_ERR_SHIFT 0
+#define   IRQ_RXD_ERR_MASK 0xff
+#define   IRQ_TXD_ERR BIT(8)
+#define   IRQ_DESC_ERR BIT(9)
+#define   IRQ_RESP_ERR BIT(10)
+#define   IRQ_RESP_TIMEOUT BIT(11)
+#define   IRQ_DESC_TIMEOUT BIT(12)
+#define   IRQ_END_OF_CHAIN BIT(13)
+#define   IRQ_RESP_STATUS BIT(14)
+#define   IRQ_SDIO BIT(15)
+
+#define SD_EMMC_CMD_CFG 0x50
+#define SD_EMMC_CMD_ARG 0x54
+#define SD_EMMC_CMD_DAT 0x58
+#define SD_EMMC_CMD_RSP 0x5c
+#define SD_EMMC_CMD_RSP1 0x60
+#define SD_EMMC_CMD_RSP2 0x64
+#define SD_EMMC_CMD_RSP3 0x68
+
+#define SD_EMMC_RXD 0x94
+#define SD_EMMC_TXD 0x94
+#define SD_EMMC_LAST_REG SD_EMMC_TXD
+
+#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
+#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
+#define SD_EMMC_CFG_CMD_GAP 16 /* in clock cycles */
+#define MUX_CLK_NUM_PARENTS 2
+
+struct meson_host {
+	struct	device		*dev;
+	struct	mmc_host	*mmc;
+	struct	mmc_request	*mrq;
+	struct	mmc_command	*cmd;
+
+	spinlock_t lock;
+	void __iomem *regs;
+	int irq;
+	u32 ocr_mask;
+	struct clk *core_clk;
+	struct clk_mux mux;
+	struct clk *mux_clk;
+	struct clk *mux_parent[MUX_CLK_NUM_PARENTS];
+	unsigned long mux_parent_rate[MUX_CLK_NUM_PARENTS];
+
+	struct clk_divider cfg_div;
+	struct clk *cfg_div_clk;
+
+	unsigned int bounce_buf_size;
+	void *bounce_buf;
+	dma_addr_t bounce_dma_addr;
+
+	bool vqmmc_enabled;
+};
+
+struct sd_emmc_desc {
+	u32 cmd_cfg;
+	u32 cmd_arg;
+	u32 cmd_data;
+	u32 cmd_resp;
+};
+#define CMD_CFG_LENGTH_SHIFT 0
+#define CMD_CFG_LENGTH_MASK 0x1ff
+#define CMD_CFG_BLOCK_MODE BIT(9)
+#define CMD_CFG_R1B BIT(10)
+#define CMD_CFG_END_OF_CHAIN BIT(11)
+#define CMD_CFG_TIMEOUT_SHIFT 12
+#define CMD_CFG_TIMEOUT_MASK 0xf
+#define CMD_CFG_NO_RESP BIT(16)
+#define CMD_CFG_NO_CMD BIT(17)
+#define CMD_CFG_DATA_IO BIT(18)
+#define CMD_CFG_DATA_WR BIT(19)
+#define CMD_CFG_RESP_NOCRC BIT(20)
+#define CMD_CFG_RESP_128 BIT(21)
+#define CMD_CFG_RESP_NUM BIT(22)
+#define CMD_CFG_DATA_NUM BIT(23)
+#define CMD_CFG_CMD_INDEX_SHIFT 24
+#define CMD_CFG_CMD_INDEX_MASK 0x3f
+#define CMD_CFG_ERROR BIT(30)
+#define CMD_CFG_OWNER BIT(31)
+
+#define CMD_DATA_MASK (~0x3)
+#define CMD_DATA_BIG_ENDIAN BIT(1)
+#define CMD_DATA_SRAM BIT(0)
+#define CMD_RESP_MASK (~0x1)
+#define CMD_RESP_SRAM BIT(0)
+
+static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
+{
+	struct mmc_host *mmc = host->mmc;
+	int ret = 0;
+	u32 cfg;
+
+	if (clk_rate) {
+		if (WARN_ON(clk_rate > mmc->f_max))
+			clk_rate = mmc->f_max;
+		else if (WARN_ON(clk_rate < mmc->f_min))
+			clk_rate = mmc->f_min;
+	}
+
+	if (clk_rate == mmc->actual_clock)
+		return 0;
+
+	/* stop clock */
+	cfg = readl(host->regs + SD_EMMC_CFG);
+	if (!(cfg & CFG_STOP_CLOCK)) {
+		cfg |= CFG_STOP_CLOCK;
+		writel(cfg, host->regs + SD_EMMC_CFG);
+	}
+
+	dev_dbg(host->dev, "change clock rate %u -> %lu\n",
+		mmc->actual_clock, clk_rate);
+
+	if (clk_rate == 0) {
+		mmc->actual_clock = 0;
+		return 0;
+	}
+
+	ret = clk_set_rate(host->cfg_div_clk, clk_rate);
+	if (ret)
+		dev_warn(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n",
+			 clk_rate, ret);
+	else if (clk_rate && clk_rate != clk_get_rate(host->cfg_div_clk))
+		dev_warn(host->dev, "divider requested rate %lu != actual rate %lu: ret=%d\n",
+			 clk_rate, clk_get_rate(host->cfg_div_clk), ret);
+	else
+		mmc->actual_clock = clk_rate;
+
+	/* (re)start clock, if non-zero */
+	if (!ret && clk_rate) {
+		cfg = readl(host->regs + SD_EMMC_CFG);
+		cfg &= ~CFG_STOP_CLOCK;
+		writel(cfg, host->regs + SD_EMMC_CFG);
+	}
+
+	return ret;
+}
+
+/*
+ * The SD/eMMC IP block has an internal mux and divider used for
+ * generating the MMC clock.  Use the clock framework to create and
+ * manage these clocks.
+ */
+static int meson_mmc_clk_init(struct meson_host *host)
+{
+	struct clk_init_data init;
+	char clk_name[32];
+	int i, ret = 0;
+	const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
+	unsigned int mux_parent_count = 0;
+	const char *clk_div_parents[1];
+	unsigned int f_min = UINT_MAX;
+	u32 clk_reg, cfg;
+
+	/* get the mux parents */
+	for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
+		char name[16];
+
+		snprintf(name, sizeof(name), "clkin%d", i);
+		host->mux_parent[i] = devm_clk_get(host->dev, name);
+		if (IS_ERR(host->mux_parent[i])) {
+			ret = PTR_ERR(host->mux_parent[i]);
+			if (PTR_ERR(host->mux_parent[i]) != -EPROBE_DEFER)
+				dev_err(host->dev, "Missing clock %s\n", name);
+			host->mux_parent[i] = NULL;
+			return ret;
+		}
+
+		host->mux_parent_rate[i] = clk_get_rate(host->mux_parent[i]);
+		mux_parent_names[i] = __clk_get_name(host->mux_parent[i]);
+		mux_parent_count++;
+		if (host->mux_parent_rate[i] < f_min)
+			f_min = host->mux_parent_rate[i];
+	}
+
+	/* cacluate f_min based on input clocks, and max divider value */
+	if (f_min != UINT_MAX)
+		f_min = DIV_ROUND_UP(CLK_SRC_XTAL_RATE, CLK_DIV_MAX);
+	else
+		f_min = 4000000;  /* default min: 400 MHz */
+	host->mmc->f_min = f_min;
+
+	/* create the mux */
+	snprintf(clk_name, sizeof(clk_name), "%s#mux", dev_name(host->dev));
+	init.name = clk_name;
+	init.ops = &clk_mux_ops;
+	init.flags = 0;
+	init.parent_names = mux_parent_names;
+	init.num_parents = mux_parent_count;
+
+	host->mux.reg = host->regs + SD_EMMC_CLOCK;
+	host->mux.shift = CLK_SRC_SHIFT;
+	host->mux.mask = CLK_SRC_MASK;
+	host->mux.flags = 0;
+	host->mux.table = NULL;
+	host->mux.hw.init = &init;
+
+	host->mux_clk = devm_clk_register(host->dev, &host->mux.hw);
+	if (WARN_ON(IS_ERR(host->mux_clk)))
+		return PTR_ERR(host->mux_clk);
+
+	/* create the divider */
+	snprintf(clk_name, sizeof(clk_name), "%s#div", dev_name(host->dev));
+	init.name = devm_kstrdup(host->dev, clk_name, GFP_KERNEL);
+	init.ops = &clk_divider_ops;
+	init.flags = CLK_SET_RATE_PARENT;
+	clk_div_parents[0] = __clk_get_name(host->mux_clk);
+	init.parent_names = clk_div_parents;
+	init.num_parents = ARRAY_SIZE(clk_div_parents);
+
+	host->cfg_div.reg = host->regs + SD_EMMC_CLOCK;
+	host->cfg_div.shift = CLK_DIV_SHIFT;
+	host->cfg_div.width = CLK_DIV_WIDTH;
+	host->cfg_div.hw.init = &init;
+	host->cfg_div.flags = CLK_DIVIDER_ONE_BASED |
+		CLK_DIVIDER_ROUND_CLOSEST | CLK_DIVIDER_ALLOW_ZERO;
+
+	host->cfg_div_clk = devm_clk_register(host->dev, &host->cfg_div.hw);
+	if (WARN_ON(PTR_ERR_OR_ZERO(host->cfg_div_clk)))
+		return PTR_ERR(host->cfg_div_clk);
+
+	/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
+	clk_reg = 0;
+	clk_reg |= CLK_PHASE_180 << CLK_PHASE_SHIFT;
+	clk_reg |= CLK_SRC_XTAL << CLK_SRC_SHIFT;
+	clk_reg |= CLK_DIV_MAX << CLK_DIV_SHIFT;
+	clk_reg &= ~CLK_ALWAYS_ON;
+	writel(clk_reg, host->regs + SD_EMMC_CLOCK);
+
+	/* Ensure clock starts in "auto" mode, not "always on" */
+	cfg = readl(host->regs + SD_EMMC_CFG);
+	cfg &= ~CFG_CLK_ALWAYS_ON;
+	cfg |= CFG_AUTO_CLK;
+	writel(cfg, host->regs + SD_EMMC_CFG);
+
+	ret = clk_prepare_enable(host->cfg_div_clk);
+	if (!ret)
+		ret = meson_mmc_clk_set(host, f_min);
+
+	if (!ret)
+		clk_disable_unprepare(host->cfg_div_clk);
+
+	return ret;
+}
+
+static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct meson_host *host = mmc_priv(mmc);
+	u32 bus_width;
+	u32 val, orig;
+
+	/*
+	 * GPIO regulator, only controls switching between 1v8 and
+	 * 3v3, doesn't support MMC_POWER_OFF, MMC_POWER_ON.
+	 */
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		if (!IS_ERR(mmc->supply.vmmc))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+		if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
+			regulator_disable(mmc->supply.vqmmc);
+			host->vqmmc_enabled = false;
+		}
+
+		break;
+
+	case MMC_POWER_UP:
+		if (!IS_ERR(mmc->supply.vmmc))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
+		break;
+
+	case MMC_POWER_ON:
+		if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
+			int ret = regulator_enable(mmc->supply.vqmmc);
+
+			if (ret < 0)
+				dev_err(mmc_dev(mmc),
+					"failed to enable vqmmc regulator\n");
+			else
+				host->vqmmc_enabled = true;
+		}
+
+		break;
+	}
+
+
+	meson_mmc_clk_set(host, ios->clock);
+
+	/* Bus width */
+	val = readl(host->regs + SD_EMMC_CFG);
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		bus_width = CFG_BUS_WIDTH_1;
+		break;
+	case MMC_BUS_WIDTH_4:
+		bus_width = CFG_BUS_WIDTH_4;
+		break;
+	case MMC_BUS_WIDTH_8:
+		bus_width = CFG_BUS_WIDTH_8;
+		break;
+	default:
+		dev_err(host->dev, "Invalid ios->bus_width: %u.  Setting to 4.\n",
+			ios->bus_width);
+		bus_width = CFG_BUS_WIDTH_4;
+		return;
+	}
+
+	val = readl(host->regs + SD_EMMC_CFG);
+	orig = val;
+
+	val &= ~(CFG_BUS_WIDTH_MASK << CFG_BUS_WIDTH_SHIFT);
+	val |= bus_width << CFG_BUS_WIDTH_SHIFT;
+
+	val &= ~(CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
+	val |= ilog2(SD_EMMC_CFG_BLK_SIZE) << CFG_BLK_LEN_SHIFT;
+
+	val &= ~(CFG_RESP_TIMEOUT_MASK << CFG_RESP_TIMEOUT_SHIFT);
+	val |= ilog2(SD_EMMC_CFG_RESP_TIMEOUT) << CFG_RESP_TIMEOUT_SHIFT;
+
+	val &= ~(CFG_RC_CC_MASK << CFG_RC_CC_SHIFT);
+	val |= ilog2(SD_EMMC_CFG_CMD_GAP) << CFG_RC_CC_SHIFT;
+
+	writel(val, host->regs + SD_EMMC_CFG);
+
+	if (val != orig)
+		dev_dbg(host->dev, "%s: SD_EMMC_CFG: 0x%08x -> 0x%08x\n",
+			__func__, orig, val);
+}
+
+static int meson_mmc_request_done(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct meson_host *host = mmc_priv(mmc);
+
+	WARN_ON(host->mrq != mrq);
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+	mmc_request_done(host->mmc, mrq);
+
+	return 0;
+}
+
+static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
+{
+	struct meson_host *host = mmc_priv(mmc);
+	struct sd_emmc_desc *desc, desc_tmp;
+	u32 cfg;
+	u8 blk_len, cmd_cfg_timeout;
+	unsigned int xfer_bytes = 0;
+
+	/* Setup descriptors */
+	dma_rmb();
+	desc = &desc_tmp;
+	memset(desc, 0, sizeof(struct sd_emmc_desc));
+
+	desc->cmd_cfg |= (cmd->opcode & CMD_CFG_CMD_INDEX_MASK)	<<
+		CMD_CFG_CMD_INDEX_SHIFT;
+	desc->cmd_cfg |= CMD_CFG_OWNER;  /* owned by CPU */
+	desc->cmd_arg = cmd->arg;
+
+	/* Response */
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		desc->cmd_cfg &= ~CMD_CFG_NO_RESP;
+		if (cmd->flags & MMC_RSP_136)
+			desc->cmd_cfg |= CMD_CFG_RESP_128;
+		desc->cmd_cfg |= CMD_CFG_RESP_NUM;
+		desc->cmd_resp = 0;
+
+		if (!(cmd->flags & MMC_RSP_CRC))
+			desc->cmd_cfg |= CMD_CFG_RESP_NOCRC;
+
+		if (cmd->flags & MMC_RSP_BUSY)
+			desc->cmd_cfg |= CMD_CFG_R1B;
+	} else {
+		desc->cmd_cfg |= CMD_CFG_NO_RESP;
+	}
+
+	/* data? */
+	if (cmd->data) {
+		desc->cmd_cfg |= CMD_CFG_DATA_IO;
+		if (cmd->data->blocks > 1) {
+			desc->cmd_cfg |= CMD_CFG_BLOCK_MODE;
+			desc->cmd_cfg |=
+				(cmd->data->blocks & CMD_CFG_LENGTH_MASK) <<
+				CMD_CFG_LENGTH_SHIFT;
+
+			/* check if block-size matches, if not update */
+			cfg = readl(host->regs + SD_EMMC_CFG);
+			blk_len = cfg & (CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
+			blk_len >>= CFG_BLK_LEN_SHIFT;
+			if (blk_len != ilog2(cmd->data->blksz)) {
+				dev_warn(host->dev, "%s: update blk_len %d -> %d\n",
+					__func__, blk_len,
+					 ilog2(cmd->data->blksz));
+				blk_len = ilog2(cmd->data->blksz);
+				cfg &= ~(CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
+				cfg |= blk_len << CFG_BLK_LEN_SHIFT;
+				writel(cfg, host->regs + SD_EMMC_CFG);
+			}
+		} else {
+			desc->cmd_cfg &= ~CMD_CFG_BLOCK_MODE;
+			desc->cmd_cfg |=
+				(cmd->data->blksz & CMD_CFG_LENGTH_MASK) <<
+				CMD_CFG_LENGTH_SHIFT;
+		}
+
+		cmd->data->bytes_xfered = 0;
+		xfer_bytes = cmd->data->blksz * cmd->data->blocks;
+		if (cmd->data->flags & MMC_DATA_WRITE) {
+			desc->cmd_cfg |= CMD_CFG_DATA_WR;
+			WARN_ON(xfer_bytes > host->bounce_buf_size);
+			sg_copy_to_buffer(cmd->data->sg, cmd->data->sg_len,
+					  host->bounce_buf, xfer_bytes);
+			cmd->data->bytes_xfered = xfer_bytes;
+			dma_wmb();
+		} else {
+			desc->cmd_cfg &= ~CMD_CFG_DATA_WR;
+		}
+
+		if (xfer_bytes > 0) {
+			desc->cmd_cfg &= ~CMD_CFG_DATA_NUM;
+			desc->cmd_data = host->bounce_dma_addr & CMD_DATA_MASK;
+		} else {
+			/* write data to data_addr */
+			desc->cmd_cfg |= CMD_CFG_DATA_NUM;
+			desc->cmd_data = 0;
+		}
+
+		cmd_cfg_timeout = 12;
+	} else {
+		desc->cmd_cfg &= ~CMD_CFG_DATA_IO;
+		cmd_cfg_timeout = 10;
+	}
+	desc->cmd_cfg |= (cmd_cfg_timeout & CMD_CFG_TIMEOUT_MASK) <<
+		CMD_CFG_TIMEOUT_SHIFT;
+
+	host->cmd = cmd;
+
+	/* Last descriptor */
+	desc->cmd_cfg |= CMD_CFG_END_OF_CHAIN;
+	writel(desc->cmd_cfg, host->regs + SD_EMMC_CMD_CFG);
+	writel(desc->cmd_data, host->regs + SD_EMMC_CMD_DAT);
+	writel(desc->cmd_resp, host->regs + SD_EMMC_CMD_RSP);
+	wmb(); /* ensure descriptor is written before kicked */
+	writel(desc->cmd_arg, host->regs + SD_EMMC_CMD_ARG);
+}
+
+static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct meson_host *host = mmc_priv(mmc);
+
+	WARN_ON(host->mrq != NULL);
+
+	/* Stop execution */
+	writel(0, host->regs + SD_EMMC_START);
+
+	/* clear, ack, enable all interrupts */
+	writel(0, host->regs + SD_EMMC_IRQ_EN);
+	writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
+	writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN);
+
+	host->mrq = mrq;
+
+	if (mrq->sbc)
+		meson_mmc_start_cmd(mmc, mrq->sbc);
+	else
+		meson_mmc_start_cmd(mmc, mrq->cmd);
+}
+
+static int meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd)
+{
+	struct meson_host *host = mmc_priv(mmc);
+
+	if (cmd->flags & MMC_RSP_136) {
+		cmd->resp[0] = readl(host->regs + SD_EMMC_CMD_RSP3);
+		cmd->resp[1] = readl(host->regs + SD_EMMC_CMD_RSP2);
+		cmd->resp[2] = readl(host->regs + SD_EMMC_CMD_RSP1);
+		cmd->resp[3] = readl(host->regs + SD_EMMC_CMD_RSP);
+	} else if (cmd->flags & MMC_RSP_PRESENT) {
+		cmd->resp[0] = readl(host->regs + SD_EMMC_CMD_RSP);
+	}
+
+	return 0;
+}
+
+static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
+{
+	struct meson_host *host = dev_id;
+	struct mmc_request *mrq;
+	struct mmc_command *cmd = host->cmd;
+	u32 irq_en, status, raw_status;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	if (WARN_ON(!host))
+		return IRQ_NONE;
+
+	mrq = host->mrq;
+
+	if (WARN_ON(!mrq))
+		return IRQ_NONE;
+
+	if (WARN_ON(!cmd))
+		return IRQ_NONE;
+
+	spin_lock(&host->lock);
+	irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
+	raw_status = readl(host->regs + SD_EMMC_STATUS);
+	status = raw_status & irq_en;
+
+	if (!status) {
+		dev_warn(host->dev, "Spurious IRQ! status=0x%08x, irq_en=0x%08x\n",
+			 raw_status, irq_en);
+		ret = IRQ_NONE;
+		goto out;
+	}
+
+	cmd->error = 0;
+	if (status & IRQ_RXD_ERR_MASK) {
+		dev_dbg(host->dev, "Unhandled IRQ: RXD error\n");
+		cmd->error = -EILSEQ;
+	}
+	if (status & IRQ_TXD_ERR) {
+		dev_dbg(host->dev, "Unhandled IRQ: TXD error\n");
+		cmd->error = -EILSEQ;
+	}
+	if (status & IRQ_DESC_ERR)
+		dev_dbg(host->dev, "Unhandled IRQ: Descriptor error\n");
+	if (status & IRQ_RESP_ERR) {
+		dev_dbg(host->dev, "Unhandled IRQ: Response error\n");
+		cmd->error = -EILSEQ;
+	}
+	if (status & IRQ_RESP_TIMEOUT) {
+		dev_dbg(host->dev, "Unhandled IRQ: Response timeout\n");
+		cmd->error = -ETIMEDOUT;
+	}
+	if (status & IRQ_DESC_TIMEOUT) {
+		dev_dbg(host->dev, "Unhandled IRQ: Descriptor timeout\n");
+		cmd->error = -ETIMEDOUT;
+	}
+	if (status & IRQ_SDIO)
+		dev_dbg(host->dev, "Unhandled IRQ: SDIO.\n");
+
+	if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS))
+		ret = IRQ_WAKE_THREAD;
+	else  {
+		dev_warn(host->dev, "Unknown IRQ! status=0x%04x: MMC CMD%u arg=0x%08x flags=0x%08x stop=%d\n",
+			 status, cmd->opcode, cmd->arg,
+			 cmd->flags, mrq->stop ? 1 : 0);
+		if (cmd->data) {
+			struct mmc_data *data = cmd->data;
+
+			dev_warn(host->dev, "\tblksz %u blocks %u flags 0x%08x (%s%s)",
+				 data->blksz, data->blocks, data->flags,
+				 data->flags & MMC_DATA_WRITE ? "write" : "",
+				 data->flags & MMC_DATA_READ ? "read" : "");
+		}
+	}
+
+out:
+	/* ack all (enabled) interrupts */
+	writel(status, host->regs + SD_EMMC_STATUS);
+
+	if (ret == IRQ_HANDLED) {
+		meson_mmc_read_resp(host->mmc, cmd);
+		meson_mmc_request_done(host->mmc, cmd->mrq);
+	}
+
+	spin_unlock(&host->lock);
+	return ret;
+}
+
+static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
+{
+	struct meson_host *host = dev_id;
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_command *cmd = host->cmd;
+	struct mmc_data *data;
+	unsigned int xfer_bytes;
+	int ret = IRQ_HANDLED;
+
+	if (WARN_ON(!mrq))
+		ret = IRQ_NONE;
+
+	if (WARN_ON(!cmd))
+		ret = IRQ_NONE;
+
+	data = cmd->data;
+	if (data) {
+		xfer_bytes = data->blksz * data->blocks;
+		if (data->flags & MMC_DATA_READ) {
+			WARN_ON(xfer_bytes > host->bounce_buf_size);
+			sg_copy_from_buffer(data->sg, data->sg_len,
+					    host->bounce_buf, xfer_bytes);
+			data->bytes_xfered = xfer_bytes;
+		}
+	}
+
+	meson_mmc_read_resp(host->mmc, cmd);
+	if (!data || !data->stop || mrq->sbc)
+		meson_mmc_request_done(host->mmc, mrq);
+	else
+		meson_mmc_start_cmd(host->mmc, data->stop);
+
+	return ret;
+}
+
+/*
+ * NOTE: we only need this until the GPIO/pinctrl driver can handle
+ * interrupts.  For now, the MMC core will use this for polling.
+ */
+static int meson_mmc_get_cd(struct mmc_host *mmc)
+{
+	int status = mmc_gpio_get_cd(mmc);
+
+	if (status == -ENOSYS)
+		return 1; /* assume present */
+
+	return status;
+}
+
+static const struct mmc_host_ops meson_mmc_ops = {
+	.request	= meson_mmc_request,
+	.set_ios	= meson_mmc_set_ios,
+	.get_cd         = meson_mmc_get_cd,
+};
+
+static int meson_mmc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct meson_host *host;
+	struct mmc_host *mmc;
+	int ret;
+
+	mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev);
+	if (!mmc)
+		return -ENOMEM;
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, host);
+
+	spin_lock_init(&host->lock);
+
+	/* Get regulators and the supported OCR mask */
+	host->vqmmc_enabled = false;
+	ret = mmc_regulator_get_supply(mmc);
+	if (ret == -EPROBE_DEFER)
+		goto free_host;
+
+	ret = mmc_of_parse(mmc);
+	if (ret) {
+		dev_warn(&pdev->dev, "error parsing DT: %d\n", ret);
+		goto free_host;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(host->regs)) {
+		ret = PTR_ERR(host->regs);
+		goto free_host;
+	}
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq == 0) {
+		dev_err(&pdev->dev, "failed to get interrupt resource.\n");
+		ret = -EINVAL;
+		goto free_host;
+	}
+
+	host->core_clk = devm_clk_get(&pdev->dev, "core");
+	if (IS_ERR(host->core_clk)) {
+		ret = PTR_ERR(host->core_clk);
+		goto free_host;
+	}
+
+	ret = clk_prepare_enable(host->core_clk);
+	if (ret)
+		goto free_host;
+
+	ret = meson_mmc_clk_init(host);
+	if (ret)
+		goto free_host;
+
+	/* Stop execution */
+	writel(0, host->regs + SD_EMMC_START);
+
+	/* clear, ack, enable all interrupts */
+	writel(0, host->regs + SD_EMMC_IRQ_EN);
+	writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
+
+	ret = devm_request_threaded_irq(&pdev->dev, host->irq,
+					meson_mmc_irq, meson_mmc_irq_thread,
+					IRQF_SHARED, DRIVER_NAME, host);
+	if (ret)
+		goto free_host;
+
+	/* data bounce buffer */
+	host->bounce_buf_size = SZ_512K;
+	host->bounce_buf =
+		dma_alloc_coherent(host->dev, host->bounce_buf_size,
+				   &host->bounce_dma_addr, GFP_KERNEL);
+	if (host->bounce_buf == NULL) {
+		dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
+		ret = -ENOMEM;
+		goto free_host;
+	}
+
+	mmc->ops = &meson_mmc_ops;
+	mmc_add_host(mmc);
+
+	return 0;
+
+free_host:
+	clk_disable_unprepare(host->cfg_div_clk);
+	clk_disable_unprepare(host->core_clk);
+	mmc_free_host(mmc);
+	return ret;
+}
+
+static int meson_mmc_remove(struct platform_device *pdev)
+{
+	struct meson_host *host = dev_get_drvdata(&pdev->dev);
+
+	if (WARN_ON(!host))
+		return 0;
+
+	if (host->bounce_buf)
+		dma_free_coherent(host->dev, host->bounce_buf_size,
+				  host->bounce_buf, host->bounce_dma_addr);
+
+	clk_disable_unprepare(host->cfg_div_clk);
+	clk_disable_unprepare(host->core_clk);
+
+	mmc_free_host(host->mmc);
+	return 0;
+}
+
+static const struct of_device_id meson_mmc_of_match[] = {
+	{ .compatible = "amlogic,meson-gx-mmc", },
+	{ .compatible = "amlogic,meson-gxbb-mmc", },
+	{ .compatible = "amlogic,meson-gxl-mmc", },
+	{ .compatible = "amlogic,meson-gxm-mmc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, meson_mmc_of_match);
+
+static struct platform_driver meson_mmc_driver = {
+	.probe		= meson_mmc_probe,
+	.remove		= meson_mmc_remove,
+	.driver		= {
+		.name = DRIVER_NAME,
+		.of_match_table = of_match_ptr(meson_mmc_of_match),
+	},
+};
+
+module_platform_driver(meson_mmc_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("Amlogic S905/GXBB SD/eMMC driver");
+MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>");
+MODULE_LICENSE("GPL v2");
+
-- 
2.9.3

^ permalink raw reply related

* [PATCH v5 0/5] Add support for legacy SCPI protocol
From: Sudeep Holla @ 2016-10-19 16:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <7h1szc9vnp.fsf@baylibre.com>



On 19/10/16 16:59, Kevin Hilman wrote:
> Sudeep Holla <sudeep.holla@arm.com> writes:
>
>> 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].
>
> Sudeep, will this be an immutable branch? (or could you put a tag at an
> immutable place on this branch?)  I'd like to include this in my amlogic
> integration branch for broader testing.
>

If you plan to test SCPI(which is enabled in defconfig), then you need
all the patches in the branch[1]. I will tag once I get a build success
from kbuild robot and I do some testing. In short, immutable tag = PR
tag IMO. The only thing I can drop from the list is DT bindings patch.

Let me know if you are fine using the same tag ? Or you can propose any
other alternative, I am fine by that too.

-- 
Regards,
Sudeep

[1] git.kernel.org/sudeep.holla/linux/h/scpi-updates/for-next

^ permalink raw reply

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Linus Torvalds @ 2016-10-19 16:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019155658.GB4411@x4>

On Wed, Oct 19, 2016 at 8:56 AM, Markus Trippelsdorf
<markus@trippelsdorf.de> wrote:
> On 2016.10.19 at 08:55 -0700, Linus Torvalds wrote:
>>
>> Well, in the meantime we apparently have to live with it. Unless Will
>> is using some unreleased gcc version that nobody else is using and we
>> can just ignore it?
>
> Yes, he is using gcc-7 that is unreleased. (It will be released April
> next year.)

Ahh, self-built? So it's not part of some experimental ARM distro
setup and this will be annoying lots of people?

If so, still think that we could just get rid of the ____ilog2_NaN()
thing as it's not _that_ important, but it's certainly not very
high-priority. Will can do it in his tree too for testing, and it can
remind people to get the gcc problem fixed.

              Linus

^ permalink raw reply

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Ard Biesheuvel @ 2016-10-19 16:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019155658.GB4411@x4>

On 19 October 2016 at 16:56, Markus Trippelsdorf <markus@trippelsdorf.de> wrote:
> On 2016.10.19 at 08:55 -0700, Linus Torvalds wrote:
>> On Wed, Oct 19, 2016 at 8:37 AM, Markus Trippelsdorf
>> <markus@trippelsdorf.de> wrote:
>> >
>> > This is a gcc bug, see:
>> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72785
>>
>> Well, in the meantime we apparently have to live with it. Unless Will
>> is using some unreleased gcc version that nobody else is using and we
>> can just ignore it?
>
> Yes, he is using gcc-7 that is unreleased. (It will be released April
> next year.)
>

order_base_2() is still broken though, given that it is documented as

 * The first few values calculated by this routine:
 *  ob2(0) = 0
 *  ob2(1) = 0
 *  ob2(2) = 1
 *  ob2(3) = 2
 *  ob2(4) = 2
 *  ob2(5) = 3

whereas order_base_2(0) actually ends up invoking
roundup_pow_of_two(0), which is documented as being undefined.

^ permalink raw reply

* [STLinux Kernel] [PATCH -next] dmaengine: st_fdma: Fix the error return code in st_fdma_probe()
From: Peter Griffin @ 2016-10-19 15:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476883430-11970-1-git-send-email-weiyj.lk@gmail.com>

Hi Wei,

On Wed, 19 Oct 2016, Wei Yongjun wrote:

> From: Wei Yongjun <weiyongjun1@huawei.com>
> 
> In case of error, the function st_slim_rproc_alloc() returns ERR_PTR()
> and never returns NULL. The NULL test in the return value check should
> be replaced with IS_ERR().
> 
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
> ---

Good spot.

Acked-by: Peter Griffin <peter.griffin@linaro.org>

^ permalink raw reply

* [PATCH v5 0/5] Add support for legacy SCPI protocol
From: Kevin Hilman @ 2016-10-19 15:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <ff62da76-a7b9-6891-c198-f9049dfa7bb5@arm.com>

Sudeep Holla <sudeep.holla@arm.com> writes:

> 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].

Sudeep, will this be an immutable branch? (or could you put a tag at an
immutable place on this branch?)  I'd like to include this in my amlogic
integration branch for broader testing.

Thanks,

Kevin

^ permalink raw reply

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Russell King - ARM Linux @ 2016-10-19 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019133500.GQ9193@arm.com>

On Wed, Oct 19, 2016 at 02:35:00PM +0100, Will Deacon wrote:
> Hi Ard,
> 
> On Mon, Oct 17, 2016 at 08:43:19PM +0100, Ard Biesheuvel wrote:
> > 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;

In any case, Linus will have a rant about that: Linus has already been
concerned about the abuse of BUG().  BUG() should not be used as an
assert() replacement, but should be used where we have absolutely
no other option than to crash the kernel, because (eg) continuing
would result in the users' data being corrupted.

So no, BUG() is not the answer here.

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

^ permalink raw reply

* [PATCH] arm64: Add support for additional relocations in the kexec purgatory code
From: Catalin Marinas @ 2016-10-19 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

When compiling the kexec-tools with gcc6, the following additional
reolcations are generated in the purgatory.ro file:

R_AARCH64_ADR_PREL_PG_HI21
R_AARCH64_ADD_ABS_LO12_NC
R_AARCH64_LDST64_ABS_LO12_NC

This patch modifies the arm64 machine_apply_elf_rel() function to handle
these relocations.

Cc: Geoff Levand <geoff@infradead.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
 kexec/arch/arm64/kexec-arm64.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
index 2e8839a..e067a23 100644
--- a/kexec/arch/arm64/kexec-arm64.c
+++ b/kexec/arch/arm64/kexec-arm64.c
@@ -550,6 +550,14 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
 # define R_AARCH64_ADR_PREL_LO21 274
 #endif
 
+#if !defined(R_AARCH64_ADR_PREL_PG_HI21)
+# define R_AARCH64_ADR_PREL_PG_HI21 275
+#endif
+
+#if !defined(R_AARCH64_ADD_ABS_LO12_NC)
+# define R_AARCH64_ADD_ABS_LO12_NC 277
+#endif
+
 #if !defined(R_AARCH64_JUMP26)
 # define R_AARCH64_JUMP26 282
 #endif
@@ -558,10 +566,15 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
 # define R_AARCH64_CALL26 283
 #endif
 
+#if !defined(R_AARCH64_LDST64_ABS_LO12_NC)
+# define R_AARCH64_LDST64_ABS_LO12_NC 286
+#endif
+
 	uint64_t *loc64;
 	uint32_t *loc32;
 	uint64_t *location = (uint64_t *)ptr;
 	uint64_t data = *location;
+	uint64_t imm;
 	const char *type = NULL;
 
 	switch(r_type) {
@@ -585,6 +598,19 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
 		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
 			+ (((value - address) << 3) & 0xffffe0));
 		break;
+	case R_AARCH64_ADR_PREL_PG_HI21:
+		type = "ADR_PREL_PG_HI21";
+		imm = ((value & ~0xfff) - (address & ~0xfff)) >> 12;
+		loc32 = ptr;
+		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+			+ ((imm & 3) << 29) + ((imm & 0x1ffffc) << (5 - 2)));
+		break;
+	case R_AARCH64_ADD_ABS_LO12_NC:
+		type = "R_AARCH64_ADD_ABS_LO12_NC";
+		loc32 = ptr;
+		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+			+ ((value & 0xfff) << 10));
+		break;
 	case R_AARCH64_JUMP26:
 		type = "JUMP26";
 		loc32 = ptr;
@@ -597,6 +623,15 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
 		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
 			+ (((value - address) >> 2) & 0x3ffffff));
 		break;
+	case R_AARCH64_LDST64_ABS_LO12_NC:
+		if (value & 7)
+			die("%s: ERROR Unaligned value: %lx\n", __func__,
+				value);
+		type = "R_AARCH64_LDST64_ABS_LO12_NC";
+		loc32 = ptr;
+		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
+			+ ((value & 0xff8) << (10 - 3)));
+		break;
 	default:
 		die("%s: ERROR Unknown type: %lu\n", __func__, r_type);
 		break;
-- 
2.10.0

^ permalink raw reply related

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Markus Trippelsdorf @ 2016-10-19 15:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+55aFzSi4V9ZYDfxvZNfz1ogngTywW5Q9U_vQq3v83+0wgPrA@mail.gmail.com>

On 2016.10.19 at 08:55 -0700, Linus Torvalds wrote:
> On Wed, Oct 19, 2016 at 8:37 AM, Markus Trippelsdorf
> <markus@trippelsdorf.de> wrote:
> >
> > This is a gcc bug, see:
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72785
> 
> Well, in the meantime we apparently have to live with it. Unless Will
> is using some unreleased gcc version that nobody else is using and we
> can just ignore it?

Yes, he is using gcc-7 that is unreleased. (It will be released April
next year.) 

-- 
Markus

^ permalink raw reply

* [PATCH v5 0/5] Add support for legacy SCPI protocol
From: Kevin Hilman @ 2016-10-19 15:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <ff62da76-a7b9-6891-c198-f9049dfa7bb5@arm.com>

Sudeep Holla <sudeep.holla@arm.com> writes:

> 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.

Yes, I'll queue the DT changes through the amlogic tree (which then goes
through the arm-soc tree.)

Thanks,

Kevin

^ permalink raw reply

* [PATCH 1/3] ARM: socfpga: dtsi: add qspi node
From: Dinh Nguyen @ 2016-10-19 15:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018074304.6744-1-s.trumtrar@pengutronix.de>

On Tue, 18 Oct 2016, Steffen Trumtrar wrote:

> Add the qspi node to the socfpga dtsi file.
> 
> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> ---
>  arch/arm/boot/dts/socfpga.dtsi | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
> index 9f48141270b8..0dc96d2248a6 100644
> --- a/arch/arm/boot/dts/socfpga.dtsi
> +++ b/arch/arm/boot/dts/socfpga.dtsi
> @@ -705,6 +705,20 @@
>  			reg = <0xffff0000 0x10000>;
>  		};
>  
> +		qspi: spi at ff705000 {
> +			compatible = "cdns,qspi-nor";
> +                        #address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0xff705000 0x1000>,
> +			      <0xffa00000 0x1000>;

I think the QSPI data address space has a length of 0x100000. I've fixed it up locally.

BR,
Dinh

^ permalink raw reply

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Linus Torvalds @ 2016-10-19 15:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019153746.GA4411@x4>

On Wed, Oct 19, 2016 at 8:37 AM, Markus Trippelsdorf
<markus@trippelsdorf.de> wrote:
>
> This is a gcc bug, see:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72785

Well, in the meantime we apparently have to live with it. Unless Will
is using some unreleased gcc version that nobody else is using and we
can just ignore it?

I don't think the link-time check is so important that we need to
notice it, and the "____ilog2_NaN()" could just be replaced with "0".

                 Linus

^ permalink raw reply

* [PATCH] mtd: nand: Add OX820 NAND Support
From: Boris Brezillon @ 2016-10-19 15:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <0f5398bb-52f1-d5bb-834c-dead4f708fd3@baylibre.com>

On Wed, 19 Oct 2016 17:46:01 +0200
Neil Armstrong <narmstrong@baylibre.com> wrote:

> >> +/* 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);
> >   
> >> +}  
> 
> Hmm, except it's needed back in the oxnas_nand_write_buf() call (don't ask me why)
> so I don't see how to simplify more this function.

Are you sure? Can you add a WARN(oxnas->ctrl) in oxnas_nand_write_buf()
to check if it's ever the case? I'm almost sure there is a call to
->cmd_ctrl() with none of the CLE and ALE flags set before the
->write_buf() call.

^ permalink raw reply

* [PATCH] dmaengine: qcom_hidma: cleanup sysfs entries during remove
From: Sinan Kaya @ 2016-10-19 15:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019132622.GN2467@localhost>

On 10/19/2016 6:26 AM, Vinod Koul wrote:
>> -static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name,
>> > -				    int mode)
>> > +static int hidma_sysfs_uninit(struct hidma_dev *dev)
>> > +{
>> > +	if (!dev->chid_attrs)
>> > +		return -ENOMEM;
> why is this check required? Probe would fail in init case right.
> Second returning error doesnt help as you are calling this from remove and
> return is not checked so redundant!

Agreed, I'll get rid of the attrs and also the return value.

-- 
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

* [PATCH 2/3] ARM: convert to generated system call tables
From: Russell King - ARM Linux @ 2016-10-19 15:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <13702107.LdHY4HTXyY@wuerfel>

On Wed, Oct 19, 2016 at 05:30:49PM +0200, Arnd Bergmann wrote:
> 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.

Architecture maintainers like to verify that the system call works on
their architecture before they push it out into the wild; your idea
effectively bypasses architecture maintainer review and testing, so
is bad.  For something as critical as system call interfaces, that
step is critical: introducing a new system call across all architectures
that then fails to work correctly on a particular architecture invites
userspace to work around the problem, and the brokenness then becomes
user API which can't be fixed.

> > +# 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

You haven't quite understood if you think the second entry gets used
for OABI - but that's not surprising because the issues here are
quite complex.

For OABI-only, all the oabi and first entry in common gets used.
For EABI-only, all the eabi and first entry in common gets used.
For EABI with OABI compat, EABI uses eabi and the first entry in common,
but the OABI compat table uses the oabi and common entries, prefering
the second entry where present.

Yes, for the cases where we list the oabi and eabi together like you
quoted, currently there are no differences between the system calls,
and in my latest version, they've already been modified down to just
a single "common" entry, leaving us without any eabi entries.
However, I want to retain the ability to have separate eabi entries
if needs be.  Such a case would be a system call which needs a helper
for arguments passed in >4 registers on EABI but not OABI (eg, because
of an non-naturally aligned 64-bit quantity passed in r1/r2 on OABI
but r2/r3 in EABI.)

You'll find the latest version in the next linux-next, or my current
for-next branch.

> > 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.

The fileguard prefix would have to be specified as an additional
argument to achieve that, but I don't see that as a big problem.

The syscalltbl.sh script is particularly architecture specific, as
our "compat" isn't the same as x86's "compat" requirements.

The syscallnr.sh script kind-of looks like a candidate, but it has
ARM arch specifics to it (knowing that the number of system calls
needs to fit within the 8-bit value plus 4-bit shift constant
representation of ARM ALU instructions.)  Maybe a generic version
without that knowledge would work, provided architectures can
override it.

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

^ permalink raw reply

* [PATCH v20 10/10] fpga-manager: Add Socfpga Arria10 support
From: atull @ 2016-10-19 15:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018210159.GA1916@live.com>

On Tue, 18 Oct 2016, Moritz Fischer wrote:

> On Mon, Oct 17, 2016 at 11:09:41AM -0500, Alan Tull wrote:
> > Add low level driver to support reprogramming FPGAs for Altera
> > SoCFPGA Arria10.
> > 
> > Signed-off-by: Alan Tull <atull@opensource.altera.com>
> 
> Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com>

> > +
> > +MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
> > +MODULE_DESCRIPTION("SoCFPGA Arria10 FPGA Manager");
> > +MODULE_LICENSE("GPL v2");
> > -- 
> > 2.10.1
> > 
> 
> Looking good,
> 
> Moritz
> 

Hi Moritz,

Thanks!

Alan

^ permalink raw reply

* [PATCH] mtd: nand: Add OX820 NAND Support
From: Neil Armstrong @ 2016-10-19 15:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019173704.75592f52@bbrezillon>

On 10/19/2016 05:37 PM, Boris Brezillon wrote:
> On Wed, 19 Oct 2016 16:55:23 +0200
> Neil Armstrong <narmstrong@baylibre.com> wrote:

[...]

>> --- /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.

Indeed, I forgot that.

[...]

>> +
>> +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);
> 
>> +}

Hmm, except it's needed back in the oxnas_nand_write_buf() call (don't ask me why)
so I don't see how to simplify more this function.

^ permalink raw reply

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Arnd Bergmann @ 2016-10-19 15:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_100mM7EvaxAMoZvnr1Ce_EC=wzYkB80AjUmBx9exkGQ@mail.gmail.com>

On Wednesday, October 19, 2016 4:27:51 PM CEST Ard Biesheuvel wrote:
> >
> > 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.

Ah, right. I also noticed that order_base_2() is defined as
log2(1 << (log2(n-1)+1)), which seems a bit redundant.
Maybe we can simplify it to something like

#define order_base_2(n) ((n) <= 1) ? 0 : log2((n) - 1) + 1)

	Arnd

^ permalink raw reply

* Build failure with v4.9-rc1 and GCC trunk -- compiler weirdness
From: Markus Trippelsdorf @ 2016-10-19 15:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161017183806.GG5601@arm.com>

On 2016.10.17 at 19:38 +0100, Will Deacon wrote:
> Hi all,
> 
> 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
> 

This is a gcc bug, see:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72785

-- 
Markus

^ permalink raw reply

* [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


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