Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 02/28] [v2] mtd: mtk: avoid warning in mtk_ecc_encode
From: Boris Brezillon @ 2016-10-18 19:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476785552.24626.4.camel@mtkswgap22>

On Tue, 18 Oct 2016 18:12:32 +0800
RogerCC.Lin <rogercc.lin@mediatek.com> wrote:

> On Tue, 2016-10-18 at 07:19 +0200, Boris Brezillon wrote:
> > On Tue, 18 Oct 2016 00:05:31 +0200
> > Arnd Bergmann <arnd@arndb.de> wrote:
> >   
> > > When building with -Wmaybe-uninitialized, gcc produces a silly false positive
> > > warning for the mtk_ecc_encode function:
> > > 
> > > drivers/mtd/nand/mtk_ecc.c: In function 'mtk_ecc_encode':
> > > drivers/mtd/nand/mtk_ecc.c:402:15: error: 'val' may be used uninitialized in this function [-Werror=maybe-uninitialized]
> > > 
> > > The function for some reason contains a double byte swap on big-endian
> > > builds to get the OOB data into the correct order again, and is written
> > > in a slightly confusing way.
> > > 
> > > Using a simple memcpy32_fromio() to read the data simplifies it a lot
> > > so it becomes more readable and produces no warning. However, the
> > > output might not have 32-bit alignment, so we have to use another
> > > memcpy to avoid taking alignment faults or writing beyond the end
> > > of the array.
> > > 
> > > Signed-off-by: Arnd Bergmann <arnd@arndb.de>  
> > 
> > Jorge, RogerCC, can I have an Acked-by and/or Tested-by for this patch?  
> Tested, this patch is OK,
> Tested-by: RogerCC Lin <rogercc.lin@mediatek.com>

Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

Brian, can you take this patch for the next -rc?

> 
> >   
> > > ---
> > > v2: move temporary buffer into struct mtk_ecc instead of having it
> > >     on the stack, as suggested by Boris Brezillon
> > > ---
> > >  drivers/mtd/nand/mtk_ecc.c | 19 +++++++++----------
> > >  1 file changed, 9 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
> > > index d54f666..dbf2562 100644
> > > --- a/drivers/mtd/nand/mtk_ecc.c
> > > +++ b/drivers/mtd/nand/mtk_ecc.c
> > > @@ -86,6 +86,8 @@ struct mtk_ecc {
> > >  	struct completion done;
> > >  	struct mutex lock;
> > >  	u32 sectors;
> > > +
> > > +	u8 eccdata[112];
> > >  };
> > >  
> > >  static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
> > > @@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
> > >  		   u8 *data, u32 bytes)
> > >  {
> > >  	dma_addr_t addr;
> > > -	u8 *p;
> > > -	u32 len, i, val;
> > > -	int ret = 0;
> > > +	u32 len;
> > > +	int ret;
> > >  
> > >  	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
> > >  	ret = dma_mapping_error(ecc->dev, addr);
> > > @@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
> > >  
> > >  	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
> > >  	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
> > > -	p = data + bytes;
> > >  
> > > -	/* write the parity bytes generated by the ECC back to the OOB region */
> > > -	for (i = 0; i < len; i++) {
> > > -		if ((i % 4) == 0)
> > > -			val = readl(ecc->regs + ECC_ENCPAR(i / 4));
> > > -		p[i] = (val >> ((i % 4) * 8)) & 0xff;
> > > -	}
> > > +	/* write the parity bytes generated by the ECC back to temp buffer */
> > > +	__ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
> > > +
> > > +	/* copy into possibly unaligned OOB region with actual length */
> > > +	memcpy(data + bytes, ecc->eccdata, len);
> > >  timeout:
> > >  
> > >  	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);  
> >   
> 
> 

^ permalink raw reply

* [PATCH v4] MMC: meson: initial support for GX platforms
From: Kevin Hilman @ 2016-10-18 19:56 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 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 +
 MAINTAINERS                                        |   1 +
 drivers/mmc/host/Kconfig                           |  10 +
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/meson-gx.c                        | 853 +++++++++++++++++++++
 5 files changed, 898 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt
 create mode 100644 drivers/mmc/host/meson-gx.c

diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.txt
new file mode 100644
index 000000000000..a2fa9a1c26ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gxbb.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>;
+	};
+
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 1/2] mmc: sdhci-iproc: Add brcm, sdhci-iproc compat string in bindings document
From: Scott Branden @ 2016-10-18 20:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018131614.lskxbdir3ghun5md@rob-hp-laptop>

Hi Rob,

On 16-10-18 06:16 AM, Rob Herring wrote:
> On Wed, Oct 12, 2016 at 11:35:51AM -0700, Scott Branden wrote:
>> Adds brcm,sdhci-iproc compat string to DT bindings document for
>> the iProc SDHCI driver.
>>
>> Signed-off-by: Anup Patel <anup.patel@broadcom.com>
>> Signed-off-by: Scott Branden <scott.branden@broadcom.com>
>> ---
>>  Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
>> index be56d2b..aa58b94 100644
>> --- a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
>> @@ -7,6 +7,7 @@ Required properties:
>>  - compatible : Should be one of the following
>>  	       "brcm,bcm2835-sdhci"
>>  	       "brcm,sdhci-iproc-cygnus"
>> +	       "brcm,sdhci-iproc"
>
> Seems kind of generic. SoC specific compatible strings please.
>
The compatibility string is generic on purpose as it is not intended to 
be SoC specific but work on all new iproc SoCs that have the proper 
fixes in place for this block (unlike bcm2835 and cygnus class devices 
which can only do 32-bit accesses).  I could call it brcm,sdhci-iproc-v2 
if that is better or leave it as is.  Please let me know your preferences.

Regards,
Scott

^ permalink raw reply

* [RFC PATCH] mtd: nand: Add OX820 NAND Support
From: Boris Brezillon @ 2016-10-18 20:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018090927.1990-1-narmstrong@baylibre.com>

Hi Neil,

On Tue, 18 Oct 2016 11:09:27 +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                      | 144 +++++++++++++++++++++
>  4 files changed, 174 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
>  create mode 100644 drivers/mtd/nand/oxnas_nand.c
> 
> 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";
> +};

Can you switch to new DT representation for NAND controllers, with one
node for the NAND controller and NAND devices connected to this NAND
controller defined as sub-nodes of this NAND controller [1]?

> 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..ee402ab
> --- /dev/null
> +++ b/drivers/mtd/nand/oxnas_nand.c
> @@ -0,0 +1,144 @@
> +/*
> + * Oxford Semiconductor OXNAS NAND driver
> + *
> + * Heavily based on plat_nand.c :
> + * Author: Vitaly Wool <vitalywool@gmail.com>
> + *
> + * 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>
> +
> +/* nand commands */
> +#define NAND_CMD_ALE		BIT(18)
> +#define NAND_CMD_CLE		BIT(19)
> +#define NAND_CMD_CS		0

I guess this is zero here because you only support connecting a NAND to
CS0.
It's probably something like

OX820_NAND_CS(x)		((x) << CS_FIELD_SHIFT)

> +#define NAND_CMD_RESET		0xff

Why do you have to redefine it? it's already defined here [2].

> +#define NAND_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
> +#define NAND_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
> +#define NAND_DATA		(NAND_CMD_CS)

Please prefix those macros with OX820, has stated above, this can
conflict with generic definitions.
Also, I'm not sure you should pass the CS information here.

> +
> +struct oxnas_nand_data {
> +	struct nand_chip	chip;
> +	void __iomem		*io_base;
> +	struct clk		*clk;
> +};

Even if your driver does not seem to support connecting several chips
to the same controller, I'd like you to clearly separate the NAND
controller and NAND chip objects:

#define OXNAS_NAND_MAX_CHIPS	1

struct oxnas_nand_controller {
	struct nand_hw_control base;
	void __iomem *io_base;
	struct clk *clk;
	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
}

> +
> +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
> +				unsigned int ctrl)
> +{
> +	struct nand_chip *this = mtd->priv;
> +	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;

Please use the ->io_base field directly, and do not use ->IO_ADDR_W/R
(I'd like to get rid of them at some point).

Also, declare the nandaddr as a void __iomem *, and use the '+'
operator instead of '|'.

> +
> +	if (ctrl & NAND_CTRL_CHANGE) {
> +		nandaddr &= ~(NAND_CMD | NAND_ADDR);

This is not needed.

> +		if (ctrl & NAND_CLE)
> +			nandaddr |= NAND_CMD;
> +		else if (ctrl & NAND_ALE)
> +			nandaddr |= NAND_ADDR;
> +		this->IO_ADDR_W = (void __iomem *) nandaddr;

This is not needed, is it?

> +	}
> +
> +	if (cmd != NAND_CMD_NONE)
> +		writeb(cmd, (void __iomem *) nandaddr);
> +}
> +
> +/*
> + * Probe for the NAND device.
> + */
> +static int oxnas_nand_probe(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_data *data;
> +	struct mtd_info *mtd;
> +	struct resource *res;
> +	int err = 0;
> +
> +	/* Allocate memory for the device structure (and zero it) */
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->io_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->io_base))
> +		return PTR_ERR(data->io_base);
> +
> +	data->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(data->clk))
> +		data->clk = NULL;
> +
> +	nand_set_flash_node(&data->chip, pdev->dev.of_node);
> +	mtd = nand_to_mtd(&data->chip);
> +	mtd->dev.parent = &pdev->dev;
> +	mtd->priv = &data->chip;
> +
> +	data->chip.IO_ADDR_R = data->io_base;
> +	data->chip.IO_ADDR_W = data->io_base;

As I said above, don't use these fields.

> +	data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
> +	data->chip.chip_delay = 30;
> +	data->chip.ecc.mode = NAND_ECC_SOFT;
> +	data->chip.ecc.algo = NAND_ECC_HAMMING;

Probably a good idea to support soft ECC as well...

> +
> +	platform_set_drvdata(pdev, data);
> +
> +	clk_prepare_enable(data->clk);
> +	device_reset_optional(&pdev->dev);
> +
> +	/* Scan to find existence of the device */
> +	if (nand_scan(mtd, 1)) {

Why not returning nand_scan() error code?

> +		err = -ENXIO;
> +		goto out;

Return directly here.

> +	}
> +
> +	err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);

Use mtd_device_register() here.

> +	if (!err)
> +		return err;
> +
> +	nand_release(mtd);

Why not

	if (err)
		nand_release(mtd);

> +out:

Drop this label.

> +	return err;
> +}
> +
> +static int oxnas_nand_remove(struct platform_device *pdev)
> +{
> +	struct oxnas_nand_data *data = platform_get_drvdata(pdev);
> +
> +	nand_release(nand_to_mtd(&data->chip));
> +
> +	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("Vitaly Wool");
> +MODULE_DESCRIPTION("Oxnas NAND driver");
> +MODULE_ALIAS("platform:oxnas_nand");

Thanks,

Boris

[1]https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/mtd/nand.txt?id=refs/tags/v4.9-rc1#n57
[2]http://lxr.free-electrons.com/source/include/linux/mtd/nand.h#L90

^ permalink raw reply

* [PATCH v2] arm64: defconfig: enable EEPROM_AT25 config option
From: Scott Branden @ 2016-10-18 20:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOesGMhSic4k3K6oSxf+GMWVFZvvJYE4aZpmzS29qZLwakvLsA@mail.gmail.com>

Hi Olof,

On 16-10-17 05:04 PM, Olof Johansson wrote:
> On Mon, Oct 17, 2016 at 4:24 PM, Scott Branden
> <scott.branden@broadcom.com> wrote:
>> Hi Olof,
>>
>> On 16-10-17 02:58 PM, Olof Johansson wrote:
>>>
>>> Hi,
>>>
>>> On Wed, Oct 12, 2016 at 11:51 AM, Scott Branden
>>> <scott.branden@broadcom.com> wrote:
>>>>
>>>> Enable support for on board SPI EEPROM by turning on
>>>> CONFIG_EEPROM_AT25.  This needs to be on in order to
>>>> boot and test the kernel with a static rootfs image
>>>> that is not rebuilt everytime the kernel is rebuilt.
>>>
>>>
>>> If we did this for every kernel option we'd get a huge kernel.
>>>
>>> In general, we've said that static options for what's needed to boot
>>> to rootfs (i.e. storage and network drivers for nfsroot) are fine to
>>> enable statically.
>>>
>>> I doubt you need the EEPROM driver to boot to rootfs on your system,
>>> so please enable it as a module instead.
OK, I will upstream as module and need config fragments maintained 
locally in order to test defconfig on our test setup.
>>>
>>> Look into using config fragments in case you need to modify the
>>> options for local builds, it should be a convenient way to have a
>>> small delta to apply to fit your internal needs, instead of completely
>>> forking the config file.
>>
>>
>> Do you allow such config fragments to be upstreamed or do we need to
>> maintain these in our tree?
>
> There's no place for them upstream. Maintain locally or in a separate repo.
If that is the case - shall we cleanup arch/arm/configs and delete 
dram_0x00000000.config that was introduced in the 4.4 kernel?
>
>
> -Olof
>

Thanks,
  Scott

^ permalink raw reply

* [PATCH v3] arm64: defconfig: enable EEPROM_AT25 config option
From: Scott Branden @ 2016-10-18 20:40 UTC (permalink / raw)
  To: linux-arm-kernel

Enable support for on board SPI EEPROM by setting
CONFIG_EEPROM_AT25=m

Signed-off-by: Scott Branden <scott.branden@broadcom.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index eadf485..4c62662 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -136,6 +136,7 @@ CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
 CONFIG_VIRTIO_BLK=y
+CONFIG_EEPROM_AT25=m
 CONFIG_SRAM=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
-- 
2.5.0

^ permalink raw reply related

* [PATCH v2 21/58] exynos4-is: don't break long lines
From: Mauro Carvalho Chehab @ 2016-10-18 20:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1476822924.git.mchehab@s-opensource.com>

Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.

As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.

So, join those continuation lines.

The patch was generated via the script below, and manually
adjusted if needed.

</script>
use Text::Tabs;
while (<>) {
	if ($next ne "") {
		$c=$_;
		if ($c =~ /^\s+\"(.*)/) {
			$c2=$1;
			$next =~ s/\"\n$//;
			$n = expand($next);
			$funpos = index($n, '(');
			$pos = index($c2, '",');
			if ($funpos && $pos > 0) {
				$s1 = substr $c2, 0, $pos + 2;
				$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
				$s2 =~ s/^\s+//;

				$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");

				print unexpand("$next$s1\n");
				print unexpand("$s2\n") if ($s2 ne "");
			} else {
				print "$next$c2\n";
			}
			$next="";
			next;
		} else {
			print $next;
		}
		$next="";
	} else {
		if (m/\"$/) {
			if (!m/\\n\"$/) {
				$next=$_;
				next;
			}
		}
	}
	print $_;
}
</script>

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/platform/exynos4-is/media-dev.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 1a1154a9dfa4..e3a8709138fa 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -938,8 +938,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
 
 			csis = fmd->csis[pdata->mux_id].sd;
 			if (WARN(csis == NULL,
-				 "MIPI-CSI interface specified "
-				 "but s5p-csis module is not loaded!\n"))
+				 "MIPI-CSI interface specified but s5p-csis module is not loaded!\n"))
 				return -EINVAL;
 
 			pad = sensor->entity.num_pads - 1;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 25/58] s5p-mfc: don't break long lines
From: Mauro Carvalho Chehab @ 2016-10-18 20:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1476822924.git.mchehab@s-opensource.com>

Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.

As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.

So, join those continuation lines.

The patch was generated via the script below, and manually
adjusted if needed.

</script>
use Text::Tabs;
while (<>) {
	if ($next ne "") {
		$c=$_;
		if ($c =~ /^\s+\"(.*)/) {
			$c2=$1;
			$next =~ s/\"\n$//;
			$n = expand($next);
			$funpos = index($n, '(');
			$pos = index($c2, '",');
			if ($funpos && $pos > 0) {
				$s1 = substr $c2, 0, $pos + 2;
				$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
				$s2 =~ s/^\s+//;

				$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");

				print unexpand("$next$s1\n");
				print unexpand("$s2\n") if ($s2 ne "");
			} else {
				print "$next$c2\n";
			}
			$next="";
			next;
		} else {
			print $next;
		}
		$next="";
	} else {
		if (m/\"$/) {
			if (!m/\\n\"$/) {
				$next=$_;
				next;
			}
		}
	}
	print $_;
}
</script>

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/platform/s5p-mfc/s5p_mfc_dec.c    | 13 ++++++-------
 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c |  7 ++-----
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 52081ddc9bf2..cf787eae11b7 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -793,18 +793,17 @@ static int vidioc_g_crop(struct file *file, void *priv,
 		cr->c.top = top;
 		cr->c.width = ctx->img_width - left - right;
 		cr->c.height = ctx->img_height - top - bottom;
-		mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
-			"w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
-			cr->c.width, cr->c.height, right, bottom,
-			ctx->buf_width, ctx->buf_height);
+		mfc_debug(2, "Cropping info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n",
+			  left, top, cr->c.width, cr->c.height, right, bottom,
+			  ctx->buf_width, ctx->buf_height);
 	} else {
 		cr->c.left = 0;
 		cr->c.top = 0;
 		cr->c.width = ctx->img_width;
 		cr->c.height = ctx->img_height;
-		mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
-			"fh=%d\n", cr->c.width,	cr->c.height, ctx->buf_width,
-							ctx->buf_height);
+		mfc_debug(2, "Cropping info: w=%d h=%d fw=%d fh=%d\n",
+			  cr->c.width,	cr->c.height, ctx->buf_width,
+			  ctx->buf_height);
 	}
 	return 0;
 }
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 81e1e4ce6c24..f4301d5bbd32 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -1293,14 +1293,11 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
 	 * First set the output frame buffers
 	 */
 	if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
-		mfc_err("It seems that not all destionation buffers were "
-			"mmaped\nMFC requires that all destination are mmaped "
-			"before starting processing\n");
+		mfc_err("It seems that not all destionation buffers were mmaped\nMFC requires that all destination are mmaped before starting processing\n");
 		return -EAGAIN;
 	}
 	if (list_empty(&ctx->src_queue)) {
-		mfc_err("Header has been deallocated in the middle of"
-			" initialization\n");
+		mfc_err("Header has been deallocated in the middle of initialization\n");
 		return -EIO;
 	}
 	temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 26/58] c8sectpfe: don't break long lines
From: Mauro Carvalho Chehab @ 2016-10-18 20:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1476822924.git.mchehab@s-opensource.com>

Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.

As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.

So, join those continuation lines.

The patch was generated via the script below, and manually
adjusted if needed.

</script>
use Text::Tabs;
while (<>) {
	if ($next ne "") {
		$c=$_;
		if ($c =~ /^\s+\"(.*)/) {
			$c2=$1;
			$next =~ s/\"\n$//;
			$n = expand($next);
			$funpos = index($n, '(');
			$pos = index($c2, '",');
			if ($funpos && $pos > 0) {
				$s1 = substr $c2, 0, $pos + 2;
				$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
				$s2 =~ s/^\s+//;

				$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");

				print unexpand("$next$s1\n");
				print unexpand("$s2\n") if ($s2 ne "");
			} else {
				print "$next$c2\n";
			}
			$next="";
			next;
		} else {
			print $next;
		}
		$next="";
	} else {
		if (m/\"$/) {
			if (!m/\\n\"$/) {
				$next=$_;
				next;
			}
		}
	}
	print $_;
}
</script>

Acked-by: Peter Griffin <peter.griffin@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
index 30c148b9d65e..42b123ff2953 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
@@ -112,8 +112,7 @@ static void channel_swdemux_tsklet(unsigned long data)
 	buf = (u8 *) channel->back_buffer_aligned;
 
 	dev_dbg(fei->dev,
-		"chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\t"
-		"rp=0x%lx, wp=0x%lx\n",
+		"chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\trp=0x%lx, wp=0x%lx\n",
 		channel->tsin_id, channel, num_packets, buf, pos, rp, wp);
 
 	for (n = 0; n < num_packets; n++) {
@@ -789,8 +788,7 @@ static int c8sectpfe_probe(struct platform_device *pdev)
 		/* sanity check value */
 		if (tsin->tsin_id > fei->hw_stats.num_ib) {
 			dev_err(&pdev->dev,
-				"tsin-num %d specified greater than number\n\t"
-				"of input block hw in SoC! (%d)",
+				"tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)",
 				tsin->tsin_id, fei->hw_stats.num_ib);
 			ret = -EINVAL;
 			goto err_clk_disable;
@@ -855,8 +853,7 @@ static int c8sectpfe_probe(struct platform_device *pdev)
 		tsin->demux_mapping = index;
 
 		dev_dbg(fei->dev,
-			"channel=%p n=%d tsin_num=%d, invert-ts-clk=%d\n\t"
-			"serial-not-parallel=%d pkt-clk-valid=%d dvb-card=%d\n",
+			"channel=%p n=%d tsin_num=%d, invert-ts-clk=%d\n\tserial-not-parallel=%d pkt-clk-valid=%d dvb-card=%d\n",
 			fei->channel_data[index], index,
 			tsin->tsin_id, tsin->invert_ts_clk,
 			tsin->serial_not_parallel, tsin->async_not_sync,
@@ -1045,8 +1042,8 @@ static void load_imem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr,
 	 */
 
 	dev_dbg(fei->dev,
-		"Loading IMEM segment %d 0x%08x\n\t"
-		" (0x%x bytes) -> 0x%p (0x%x bytes)\n", seg_num,
+		"Loading IMEM segment %d 0x%08x\n\t (0x%x bytes) -> 0x%p (0x%x bytes)\n",
+seg_num,
 		phdr->p_paddr, phdr->p_filesz,
 		dest, phdr->p_memsz + phdr->p_memsz / 3);
 
@@ -1075,8 +1072,7 @@ static void load_dmem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr,
 	 */
 
 	dev_dbg(fei->dev,
-		"Loading DMEM segment %d 0x%08x\n\t"
-		"(0x%x bytes) -> 0x%p (0x%x bytes)\n",
+		"Loading DMEM segment %d 0x%08x\n\t(0x%x bytes) -> 0x%p (0x%x bytes)\n",
 		seg_num, phdr->p_paddr, phdr->p_filesz,
 		dst, phdr->p_memsz);
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/3] ARM: memory: da8xx-ddrctl: new driver
From: Laurent Pinchart @ 2016-10-18 20:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476721850-454-2-git-send-email-bgolaszewski@baylibre.com>

Hi Bartosz,

Thank you for the patch.

On Monday 17 Oct 2016 18:30:48 Bartosz Golaszewski wrote:
> Create a new driver for the da8xx DDR2/mDDR controller and implement
> support for writing to the Peripheral Bus Burst Priority Register.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  .../memory-controllers/ti-da8xx-ddrctl.txt         | 25 +++++++
>  drivers/memory/Kconfig                             |  8 +++
>  drivers/memory/Makefile                            |  1 +
>  drivers/memory/da8xx-ddrctl.c                      | 77 +++++++++++++++++++
>  4 files changed, 111 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> create mode 100644 drivers/memory/da8xx-ddrctl.c
> 
> diff --git
> a/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> new file mode 100644
> index 0000000..e340404
> --- /dev/null
> +++
> b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> @@ -0,0 +1,25 @@
> +* Device tree bindings for Texas Instruments da8xx DDR2/mDDR memory
> controller
> +
> +The DDR2/mDDR memory controller present on Texas Instruments da8xx SoCs
> memory
> +maps a set of registers which allow to tweak the controller's behavior.
> +
> +Documentation:
> +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf
> +
> +Required properties:
> +
> +- compatible:		"ti,da850-ddrctl"

Don't you need a reg property ?

> +Optional properties:
> +
> +- ti,pr-old-count:	Priority raise old counter. Specifies the number of
> +			memory transfers after which the DDR2/mDDR memory
> +			controller will elevate the priority of the oldest
> +			command in the command FIFO. Must be between 0-255.

Isn't this a system configuration more than a hardware description ?

> +Example for da850 shown below.
> +
> +ddrctl {
> +	compatible = "ti,da850-ddrctl";
> +	ti,pr-old-count = <0x20>;
> +};
> diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
> index 4b4c0c3..ec80e35 100644
> --- a/drivers/memory/Kconfig
> +++ b/drivers/memory/Kconfig
> @@ -134,6 +134,14 @@ config MTK_SMI
>  	  mainly help enable/disable iommu and control the power domain and
>  	  clocks for each local arbiter.
> 
> +config DA8XX_DDRCTL
> +	bool "Texas Instruments da8xx DDR2/mDDR driver"
> +	depends on ARCH_DAVINCI_DA8XX
> +	help
> +	  This driver is for the DDR2/mDDR Memory Controller present on
> +	  Texas Instruments da8xx SoCs. It's used to tweak various memory
> +	  controller configuration options.
> +
>  source "drivers/memory/samsung/Kconfig"
>  source "drivers/memory/tegra/Kconfig"
> 
> diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
> index b20ae38..e88097fb 100644
> --- a/drivers/memory/Makefile
> +++ b/drivers/memory/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_MVEBU_DEVBUS)	+= mvebu-devbus.o
>  obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
>  obj-$(CONFIG_JZ4780_NEMC)	+= jz4780-nemc.o
>  obj-$(CONFIG_MTK_SMI)		+= mtk-smi.o
> +obj-$(CONFIG_DA8XX_DDRCTL)	+= da8xx-ddrctl.o
> 
>  obj-$(CONFIG_SAMSUNG_MC)	+= samsung/
>  obj-$(CONFIG_TEGRA_MC)		+= tegra/
> diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c
> new file mode 100644
> index 0000000..dcd0a61
> --- /dev/null
> +++ b/drivers/memory/da8xx-ddrctl.c
> @@ -0,0 +1,77 @@
> +/*
> + * TI da8xx DDR2/mDDR controller driver
> + *
> + * Copyright (C) 2016 BayLibre SAS
> + *
> + * Author:
> + *   Bartosz Golaszewski <bgolaszewski@baylibre.com>
> + *
> + * 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/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +
> +#define DA8XX_DDR_CTL_BASE	0xB0000000
> +#define DA8XX_PBBPR_OFFSET	0x00000020
> +#define DA8XX_PBBPR_REG(p)	((p) + DA8XX_PBBPR_OFFSET)
> +
> +#define DA8XX_PBBPR_MAX		0xff
> +
> +static void da8xx_ddrctl_set_pbbpr(void __iomem *ddrctl, struct device
> *dev) +{
> +	struct device_node *node = dev->of_node;
> +	u32 pr_old_count;
> +	int ret;
> +
> +	ret = of_property_read_u32(node, "ti,pr-old-count", &pr_old_count);
> +	if (ret)
> +		return;
> +
> +	if (pr_old_count > DA8XX_PBBPR_MAX) {
> +		dev_warn(dev, "priority raise old counter value too high\n");
> +		return;
> +	}
> +
> +	__raw_writel(pr_old_count, DA8XX_PBBPR_REG(ddrctl));
> +}
> +
> +static int da8xx_ddrctl_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	void __iomem *ddrctl;
> +
> +	ddrctl = ioremap(DA8XX_DDR_CTL_BASE, SZ_256);
> +	if (!ddrctl) {
> +		dev_err(dev, "unable to map memory controller registers\n");
> +		return -EIO;
> +	}
> +
> +	da8xx_ddrctl_set_pbbpr(ddrctl, dev);
> +
> +	iounmap(ddrctl);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id da8xx_ddrctl_of_match[] = {
> +	{ .compatible = "ti,da850-ddrctl", },
> +	{ },
> +};
> +
> +static struct platform_driver da8xx_ddrctl_driver = {
> +	.probe = da8xx_ddrctl_probe,
> +	.driver = {
> +		.name = "da8xx-ddrctl",
> +		.of_match_table = da8xx_ddrctl_of_match,
> +	},
> +};
> +module_platform_driver(da8xx_ddrctl_driver);
> +
> +MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
> +MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver");
> +MODULE_LICENSE("GPL v2");

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH v2] arm64: defconfig: enable EEPROM_AT25 config option
From: Olof Johansson @ 2016-10-18 20:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <89501c0e-b544-8d5c-a158-7a3484af935d@broadcom.com>

On Tue, Oct 18, 2016 at 1:38 PM, Scott Branden
<scott.branden@broadcom.com> wrote:
> Hi Olof,
>
> On 16-10-17 05:04 PM, Olof Johansson wrote:
>>
>> On Mon, Oct 17, 2016 at 4:24 PM, Scott Branden
>> <scott.branden@broadcom.com> wrote:
>>>
>>> Hi Olof,
>>>
>>> On 16-10-17 02:58 PM, Olof Johansson wrote:
>>>>
>>>>
>>>> Hi,
>>>>
>>>> On Wed, Oct 12, 2016 at 11:51 AM, Scott Branden
>>>> <scott.branden@broadcom.com> wrote:
>>>>>
>>>>>
>>>>> Enable support for on board SPI EEPROM by turning on
>>>>> CONFIG_EEPROM_AT25.  This needs to be on in order to
>>>>> boot and test the kernel with a static rootfs image
>>>>> that is not rebuilt everytime the kernel is rebuilt.
>>>>
>>>>
>>>>
>>>> If we did this for every kernel option we'd get a huge kernel.
>>>>
>>>> In general, we've said that static options for what's needed to boot
>>>> to rootfs (i.e. storage and network drivers for nfsroot) are fine to
>>>> enable statically.
>>>>
>>>> I doubt you need the EEPROM driver to boot to rootfs on your system,
>>>> so please enable it as a module instead.
>
> OK, I will upstream as module and need config fragments maintained locally
> in order to test defconfig on our test setup.

Great.

>>>>
>>>>
>>>> Look into using config fragments in case you need to modify the
>>>> options for local builds, it should be a convenient way to have a
>>>> small delta to apply to fit your internal needs, instead of completely
>>>> forking the config file.
>>>
>>>
>>>
>>> Do you allow such config fragments to be upstreamed or do we need to
>>> maintain these in our tree?
>>
>>
>> There's no place for them upstream. Maintain locally or in a separate
>> repo.
>
> If that is the case - shall we cleanup arch/arm/configs and delete
> dram_0x00000000.config that was introduced in the 4.4 kernel?

That one is a bit different, in that it allows us to do defconfig
consolidation, and as such keeps the number of defconfigs needed down.

In particular, see the email from Arnd here:

http://marc.info/?l=linux-arm-kernel&m=145700132713703


-Olof

^ permalink raw reply

* [PATCH v2] ARM: bcm2835: Add names for the Raspberry Pi GPIO lines
From: Gottfried Haider @ 2016-10-18 20:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric, Linus,

I'll hopefully find time to look at the more recent changes to the
gpio subsystem (lsgpio?!), but since this patch is up for discussion
now - what I was wondering: how does this change relate to
/sys/class/gpio/gpio%d? Is this completely orthogonal - or would this
change the sysfs interface as well?

Regarding the proposed format using the header pin numbers: From what
I've seen in terms of existing educational materials, it seems the
overwhelming majority ends up using GPIO numbers instead of physical
pin header numbering. (e.g. [1] [2])
Would it be too confusing to try to pick GPIO 5 from an alphabetically
sorted list like this "P11_GPIO17", "P12_GPIO18"? (I know,
alphabetical sorting is an issue here already for a different reason.
But applications might do it, I guess?)

Best
Gottfried

[1] https://www.raspberrypi.org/learning/physical-computing-with-python/worksheet/
[2] https://pinout.xyz/pinout/

^ permalink raw reply

* [PATCH 2/3] ARM: bus: da8xx-syscfg: new driver
From: Laurent Pinchart @ 2016-10-18 20:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476721850-454-3-git-send-email-bgolaszewski@baylibre.com>

Hi Bartosz,

Thank you for the patch.

On Monday 17 Oct 2016 18:30:49 Bartosz Golaszewski wrote:
> Create the driver for the da8xx System Configuration and implement
> support for writing to the three Master Priority registers.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  .../devicetree/bindings/bus/ti,da850-syscfg.txt    |  63 +++++++
>  drivers/bus/Kconfig                                |   8 +
>  drivers/bus/Makefile                               |   2 +
>  drivers/bus/da8xx-syscfg.c                         | 206 ++++++++++++++++++
>  4 files changed, 279 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/bus/ti,da850-syscfg.txt create mode
> 100644 drivers/bus/da8xx-syscfg.c
> 
> diff --git a/Documentation/devicetree/bindings/bus/ti,da850-syscfg.txt
> b/Documentation/devicetree/bindings/bus/ti,da850-syscfg.txt new file mode
> 100644
> index 0000000..07e5c38
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bus/ti,da850-syscfg.txt
> @@ -0,0 +1,63 @@
> +* Device tree bindings for Texas Instruments da8xx system configuration
> driver
> +
> +The system configuration (SYSCFG) module is a system-level module
> containing
> +status and top level control logic required by the device. The system
> +configuration module consists of a set of memory-mapped status and control
> +registers, accessible by the CPU, supporting all of the following system
> +features, and miscellaneous functions and operations.
> +
> +Documentation:
> +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf
> +
> +Required properties:
> +
> +- compatible:		"ti,da850-syscfg"

Don't you need a reg property ?

> +Optional properties:
> +
> +The below properties are used to specify the priority of master
> peripherals.
> +They must be between 0-7 where 0 is the highest priority and 7 is the
> lowest.
> +
> +- ti,pri-arm-i:		ARM_I port priority.
> +
> +- ti,pri-arm-d:		ARM_D port priority.
> +
> +- ti,pri-upp:		uPP port priority.
> +
> +- ti,pri-sata:		SATA port priority.
> +
> +- ti,pri-pru0:		PRU0 port priority.
> +
> +- ti,pri-pru1:		PRU1 port priority.
> +
> +- ti,pri-edma30tc0:	EDMA3_0_TC0 port priority.
> +
> +- ti,pri-edma30tc1:	EDMA3_0_TC1 port priority.
> +
> +- ti,pri-edma31tc0:	EDMA3_1_TC0 port priority.
> +
> +- ti,pri-vpif-dma-0:	VPIF DMA0 port priority.
> +
> +- ti,pri-vpif-dma-1:	VPIF DMA1 port priority.
> +
> +- ti,pri-emac:		EMAC port priority.
> +
> +- ti,pri-usb0cfg:	USB0 CFG port priority.
> +
> +- ti,pri-usb0cdma:	USB0 CDMA port priority.
> +
> +- ti,pri-uhpi:		HPI port priority.
> +
> +- ti,pri-usb1:		USB1 port priority.
> +
> +- ti,pri-lcdc:		LCDC port priority.

I'm afraid this looks more like system configuration than hardware description 
to me.

There was a BoF session about how to support this kind of performance knobs at 
ELCE last week: https://openiotelceurope2016.sched.org/event/7rss/bof-linux-device-performance-framework-michael-turquette-baylibre :-)

> +If any of the above properties is absent, the default value will be used as
> +defined in the documentation.
> +
> +Example for da850-lcdk is shown below.
> +
> +mstpri {
> +	compatible = "ti,da850-mstpri";
> +	ti,pri-lcdc = 0;
> +};
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index 5a2d47c..6276132 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -165,4 +165,12 @@ config VEXPRESS_CONFIG
>  	help
>  	  Platform configuration infrastructure for the ARM Ltd.
>  	  Versatile Express.
> +
> +config DA8XX_SYSCFG
> +	bool "TI da8xx system configuration driver"
> +	depends on ARCH_DAVINCI_DA8XX
> +	help
> +	  Driver for Texas Instruments da8xx system configuration. Allows to
> +	  adjust various SoC configuration options.
> +
>  endmenu
> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
> index c6cfa6b..3cba66a 100644
> --- a/drivers/bus/Makefile
> +++ b/drivers/bus/Makefile
> @@ -21,3 +21,5 @@ obj-$(CONFIG_SIMPLE_PM_BUS)	+= simple-pm-bus.o
>  obj-$(CONFIG_TEGRA_ACONNECT)	+= tegra-aconnect.o
>  obj-$(CONFIG_UNIPHIER_SYSTEM_BUS)	+= uniphier-system-bus.o
>  obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
> +
> +obj-$(CONFIG_DA8XX_SYSCFG)	+= da8xx-syscfg.o
> diff --git a/drivers/bus/da8xx-syscfg.c b/drivers/bus/da8xx-syscfg.c
> new file mode 100644
> index 0000000..8a2cb4f
> --- /dev/null
> +++ b/drivers/bus/da8xx-syscfg.c
> @@ -0,0 +1,206 @@
> +/*
> + * TI da8xx System Configuration driver
> + *
> + * Copyright (C) 2016 BayLibre SAS
> + *
> + * Author:
> + *   Bartosz Golaszewski <bgolaszewski@baylibre.com.com>
> + *
> + * 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/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +
> +#define DA8XX_IO_PHYS			0x01c00000ul
> +#define DA8XX_SYSCFG0_BASE		(DA8XX_IO_PHYS + 0x14000)
> +
> +#define DA8XX_MSTPRI0_REG		0x110
> +#define DA8XX_MSTPRI1_REG		0x114
> +#define DA8XX_MSTPRI2_REG		0x118
> +
> +#define DA8XX_MSTPRI_MAX		7
> +
> +struct da8xx_mstpri_descr {
> +	const char *property;
> +	int reg;
> +	int shift;
> +	int mask;
> +};
> +
> +static const struct da8xx_mstpri_descr priorities[] = {
> +	{
> +		.property = "ti,pri-arm-i",
> +		.reg = DA8XX_MSTPRI0_REG,
> +		.shift = 0,
> +		.mask = 0xfffffff0,
> +	},
> +	{
> +		.property = "ti,pri-arm-d",
> +		.reg = DA8XX_MSTPRI0_REG,
> +		.shift = 4,
> +		.mask = 0xffffff0f,
> +	},
> +	{
> +		.property = "ti,pri-upp",
> +		.reg = DA8XX_MSTPRI0_REG,
> +		.shift = 16,
> +		.mask = 0xfff0ffff,
> +	},
> +	{
> +		.property = "ti,pri-sata",
> +		.reg = DA8XX_MSTPRI0_REG,
> +		.shift = 20,
> +		.mask = 0xff0fffff,
> +	},
> +	{
> +		.property = "ti,pri-pru0",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 0,
> +		.mask = 0xfffffff0,
> +	},
> +	{
> +		.property = "ti,pri-pru1",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 4,
> +		.mask = 0xffffff0f,
> +	},
> +	{
> +		.property = "ti,pri-edma30tc0",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 8,
> +		.mask = 0xfffff0ff,
> +	},
> +	{
> +		.property = "ti,pri-edma30tc1",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 12,
> +		.mask = 0xffff0fff,
> +	},
> +	{
> +		.property = "ti,pri-edma31tc0",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 16,
> +		.mask = 0xfff0ffff,
> +	},
> +	{
> +		.property = "ti,pri-vpif-dma-0",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 24,
> +		.mask = 0xf0ffffff,
> +	},
> +	{
> +		.property = "ti,pri-vpif-dma-1",
> +		.reg = DA8XX_MSTPRI1_REG,
> +		.shift = 28,
> +		.mask = 0x0fffffff,
> +	},
> +	{
> +		.property = "ti,pri-emac",
> +		.reg = DA8XX_MSTPRI2_REG,
> +		.shift = 0,
> +		.mask = 0xfffffff0,
> +	},
> +	{
> +		.property = "ti,pri-usb0cfg",
> +		.reg = DA8XX_MSTPRI2_REG,
> +		.shift = 8,
> +		.mask = 0xfffff0ff,
> +	},
> +	{
> +		.property = "ti,pri-usb0cdma",
> +		.reg = DA8XX_MSTPRI2_REG,
> +		.shift = 12,
> +		.mask = 0xffff0fff,
> +	},
> +	{
> +		.property = "ti,pri-uhpi",
> +		.reg = DA8XX_MSTPRI2_REG,
> +		.shift = 20,
> +		.mask = 0xff0fffff,
> +	},
> +	{
> +		.property = "ti,pri-usb1",
> +		.reg = DA8XX_MSTPRI2_REG,
> +		.shift = 24,
> +		.mask = 0xf0ffffff,
> +	},
> +	{
> +		.property = "ti,pri-lcdc",
> +		.reg = DA8XX_MSTPRI2_REG,
> +		.shift = 28,
> +		.mask = 0x0fffffff,
> +	},
> +};
> +
> +static void da8xx_syscfg_set_mstpri(void __iomem *syscfg0, struct device
> *dev) +{
> +	const struct da8xx_mstpri_descr *pri_descr;
> +	struct device_node *node = dev->of_node;
> +	void __iomem *mstpri;
> +	u32 old_pri, new_pri;
> +	int ret, i;
> +
> +	for (i = 0; i < ARRAY_SIZE(priorities); i++) {
> +		pri_descr = &priorities[i];
> +
> +		ret = of_property_read_u32(node, pri_descr->property, 
&new_pri);
> +		if (ret)
> +			continue;
> +
> +		if (new_pri > DA8XX_MSTPRI_MAX) {
> +			dev_warn(dev,
> +				 "omitting property '%s' - value too high\n",
> +				 pri_descr->property);
> +			continue;
> +		}
> +
> +		mstpri = syscfg0 + pri_descr->reg;
> +		old_pri = __raw_readl(mstpri);
> +		old_pri &= pri_descr->mask;
> +		new_pri <<= pri_descr->shift;
> +		new_pri |= old_pri;
> +
> +		__raw_writel(new_pri, mstpri);
> +	}
> +}
> +
> +static int da8xx_syscfg_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	void __iomem *syscfg0;
> +
> +	syscfg0 = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
> +	if (!syscfg0) {
> +		dev_err(dev, "unable to map syscfg0\n");
> +		return -EIO;
> +	}
> +
> +	da8xx_syscfg_set_mstpri(syscfg0, dev);
> +
> +	iounmap(syscfg0);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id da8xx_syscfg_of_match[] = {
> +	{ .compatible = "ti,da850-syscfg", },
> +	{ },
> +};
> +
> +static struct platform_driver da8xx_syscfg_driver = {
> +	.probe = da8xx_syscfg_probe,
> +	.driver = {
> +		.name = "da8xx-syscfg",
> +		.of_match_table = da8xx_syscfg_of_match,
> +	},
> +};
> +module_platform_driver(da8xx_syscfg_driver);
> +
> +MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
> +MODULE_DESCRIPTION("TI da8xx System Configuration driver");
> +MODULE_LICENSE("GPL v2");

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH v5 00/23] Support qcom's HSIC USB and rewrite USB2 HS support
From: Stephen Boyd @ 2016-10-18 20:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018093139.GB6294@b29397-desktop>

Quoting Peter Chen (2016-10-18 02:31:40)
> On Mon, Oct 17, 2016 at 06:56:13PM -0700, Stephen Boyd wrote:
> > I've also sent separate patches for other minor pieces to make this
> > all work. The full tree can be found here[2], hacks and all to get
> > things working. I've tested this on the db410c, apq8074 dragonboard,
> > and ifc6410 with configfs gadgets and otg cables.
> > 
> > Patches based on v4.8-rc1

Oops should be v4.9-rc1 here.

> > 
> > Changes from v4:
> >  * Picked up Acks from Rob
> >  * Updated HS phy init sequence DT property to restrict it to offsets
> 
> I remembered that you got all my acks for chipidea patches, right? I did
> not check for this series.

Sorry I've added in one more patch

   usb: chipidea: Emulate OTGSC interrupt enable path

to fix extcon interrupt emulation even further.

> 
> Besides, the patch "gpu: Remove depends on RESET_CONTROLLER when not a
> provider" [1]  still not be accepted, I need this patch to be merged
> first, then apply your chipidea part, otherwise, there is a building
> warning.
> 
> [1] https://patchwork.kernel.org/patch/9322583/

Yes, I'm going to resend that patch now. I hope that David will apply it
for -rc2.

^ permalink raw reply

* [PATCH] gpu: Remove depends on RESET_CONTROLLER when not a provider
From: Stephen Boyd @ 2016-10-18 20:57 UTC (permalink / raw)
  To: linux-arm-kernel

These GPU drivers only depend on the RESET_CONTROLLER config
option to fix build issues that existed when there weren't stub
reset APIs for reset controller consumers. Given that these
drivers aren't providing any reset controllers themselves, they
don't actually depend on the API to build (just to function) so
they don't need to depend on it. Remove the dependency to fix
recursive build errors like the following:

drivers/usb/Kconfig:39:error: recursive dependency detected!
drivers/usb/Kconfig:39: symbol USB is selected by MOUSE_APPLETOUCH
drivers/input/mouse/Kconfig:187:        symbol MOUSE_APPLETOUCH depends on INPUT
drivers/input/Kconfig:8:        symbol INPUT is selected by VT
drivers/tty/Kconfig:12: symbol VT is selected by FB_STI
drivers/video/fbdev/Kconfig:674:        symbol FB_STI depends on FB
drivers/video/fbdev/Kconfig:5:  symbol FB is selected by DRM_KMS_FB_HELPER
drivers/gpu/drm/Kconfig:42:     symbol DRM_KMS_FB_HELPER is selected by DRM_KMS_CMA_HELPER
drivers/gpu/drm/Kconfig:98:     symbol DRM_KMS_CMA_HELPER is selected by DRM_IMX
drivers/gpu/drm/imx/Kconfig:1:  symbol DRM_IMX depends on IMX_IPUV3_CORE
drivers/gpu/ipu-v3/Kconfig:1:   symbol IMX_IPUV3_CORE depends on RESET_CONTROLLER
drivers/reset/Kconfig:4:        symbol RESET_CONTROLLER is selected by USB_CHIPIDEA
drivers/usb/chipidea/Kconfig:1: symbol USB_CHIPIDEA depends on USB_EHCI_HCD
drivers/usb/host/Kconfig:84:    symbol USB_EHCI_HCD depends on USB

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: <dri-devel@lists.freedesktop.org>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Mark Yao <mark.yao@rock-chips.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
---

This has come out of some USB chipidea patches I've been working on. Please see
http://lkml.kernel.org/r/20160907213519.27340-1-stephen.boyd at linaro.org for
more details.

I'm resending with the ack from Philipp picked up.

 drivers/gpu/drm/rockchip/Kconfig | 1 -
 drivers/gpu/drm/tegra/Kconfig    | 1 -
 drivers/gpu/ipu-v3/Kconfig       | 1 -
 3 files changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 3c58669a06ce..6f7f9c59f05b 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -1,7 +1,6 @@
 config DRM_ROCKCHIP
 	tristate "DRM Support for Rockchip"
 	depends on DRM && ROCKCHIP_IOMMU
-	depends on RESET_CONTROLLER
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_HELPER
 	select DRM_PANEL
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index 63ebb154b9b5..bbf5a4b7e0b6 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -3,7 +3,6 @@ config DRM_TEGRA
 	depends on ARCH_TEGRA || (ARM && COMPILE_TEST)
 	depends on COMMON_CLK
 	depends on DRM
-	depends on RESET_CONTROLLER
 	select DRM_KMS_HELPER
 	select DRM_MIPI_DSI
 	select DRM_PANEL
diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig
index aefdff95356d..08766c6e7856 100644
--- a/drivers/gpu/ipu-v3/Kconfig
+++ b/drivers/gpu/ipu-v3/Kconfig
@@ -1,7 +1,6 @@
 config IMX_IPUV3_CORE
 	tristate "IPUv3 core support"
 	depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM
-	depends on RESET_CONTROLLER
 	select GENERIC_IRQ_CHIP
 	help
 	  Choose this if you have a i.MX5/6 system and want to use the Image
-- 
2.10.0.297.gf6727b0

^ permalink raw reply related

* [PATCH v2] ARM: dts: rockchip: temporarily remove emmc hs200 speed from rk3288-veyron-speedy.
From: Paul Kocialkowski @ 2016-10-18 21:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <12872023.2LumKfgYDl@diego>

Hi,

Le mardi 18 octobre 2016 ? 11:21 +0200, Heiko St?bner a ?crit?:
> Am Sonntag, 16. Oktober 2016, 21:49:43 schrieb Paul Kocialkowski:
> > 
> > Hi,
> > 
> > Le mardi 27 septembre 2016 ? 13:53 -0700, Vagrant Cascadian a ?crit :
> > > 
> > > This essentially mimics what was done with rk3288-veyron-minnie in
> > > commit 984926781122f034d5bc9962815d135b6c4a8e1d.
> > > 
> > > The eMMC of the speedy Chromebook also appears to need the same tuning
> > > workaround, as it frequently fails to recognize the eMMC without it.
> > 
> > I have a device where (without this patch) eMMC sometimes fails, with:
> > [????3.561010] dwmmc_rockchip ff0f0000.dwmmc: Successfully tuned phase to
> > 175 [????3.571742] mmc2: new HS200 MMC card at address 0001
> > [????3.571943] mmcblk2: mmc2:0001 HAG2e 14.7 GiB?
> > [????3.572026] mmcblk2boot0: mmc2:0001 HAG2e partition 1 4.00 MiB
> > [????3.572107] mmcblk2boot1: mmc2:0001 HAG2e partition 2 4.00 MiB
> > [????3.572181] mmcblk2rpmb: mmc2:0001 HAG2e partition 3 4.00 MiB
> > [????3.685647] mmcblk2: error -110 transferring data, sector 0, nr 8, cmd
> > response 0x900, card status 0x0
> > 
> > And sometimes works, with:
> > [????3.451058] dwmmc_rockchip ff0f0000.dwmmc: Successfully tuned phase to
> > 176 [????3.491093] mmc2: new HS200 MMC card at address 0001
> > [????3.491277] mmcblk2: mmc2:0001 HAG2e 14.7 GiB?
> > [????3.491345] mmcblk2boot0: mmc2:0001 HAG2e partition 1 4.00 MiB
> > [????3.491409] mmcblk2boot1: mmc2:0001 HAG2e partition 2 4.00 MiB
> > [????3.491474] mmcblk2rpmb: mmc2:0001 HAG2e partition 3 4.00 MiB
> > [????3.493548]??mmcblk2: p1 p2
> > 
> > However, with this change, it always fails, with:
> > [????3.322129] mmc_host mmc2: Bus speed (slot 0) = 50000000Hz (slot req
> > 52000000Hz, actual 50000000HZ div = 0) [????3.333174] mmc2: error -110
> > whilst initialising MMC card
> > 
> > I don't have so much time to investigate this issue, but it's clear that
> > this patch doesn't fix the issue (and actually worsens it) for my device.
> 
> thanks for the heads up.
> 
> As discussed on IRC we now have varying reports of the emmc working or not?
> working with and without that patch applied. So it's not really a bandaid fix?
> and I've thus dropped this patch again.

Thanks for dropping it! For the record, my eMMC shows up as:
mmcblk2: mmc2:0001 HAG2e 14.7 GiB

Maybe it could help to share what each tested device reports as eMMC model and
associate that with the current behavior, in spite of getting a clearer idea of
what issue affects what model.

> Still hoping someone will find the source of the problem somewhere :-)

I have started investigating the issue, but did not discover anything
significant yet. I hope I'll be able to figure it out!

Cheers!

-- 
Paul Kocialkowski, developer of free digital technology at the lower levels

Website: https://www.paulk.fr/
Coding blog: https://code.paulk.fr/
Git repositories: https://git.paulk.fr/ https://git.code.paulk.fr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/1250804a/attachment.sig>

^ permalink raw reply

* [PATCH 0/4] i2c: Fix module autoload for some i2c busses platform drivers
From: Javier Martinez Canillas @ 2016-10-18 21:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Wolfram,

I noticed that module autoload won't be working in some of the i2c
busses drivers. This patch series contains the fixes for these.

Best regards,
Javier


Javier Martinez Canillas (4):
  i2c: jz4780: Fix module autoload
  i2c: xlp9xx: Fix module autoload
  i2c: xlr: Fix module autoload for OF registration
  i2c: digicolor: Fix module autoload

 drivers/i2c/busses/i2c-digicolor.c | 1 +
 drivers/i2c/busses/i2c-jz4780.c    | 1 +
 drivers/i2c/busses/i2c-xlp9xx.c    | 1 +
 drivers/i2c/busses/i2c-xlr.c       | 1 +
 4 files changed, 4 insertions(+)

-- 
2.7.4

^ permalink raw reply

* [PATCH 4/4] i2c: digicolor: Fix module autoload
From: Javier Martinez Canillas @ 2016-10-18 21:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476824508-4679-1-git-send-email-javier@osg.samsung.com>

If the driver is built as a module, autoload won't work because the module
alias information is not filled. So user-space can't match the registered
device with the corresponding module.

Export the module alias information using the MODULE_DEVICE_TABLE() macro.

Before this patch:

$ modinfo drivers/i2c/busses/i2c-digicolor.ko | grep alias
$

After this patch:

$ modinfo drivers/i2c/busses/i2c-digicolor.ko | grep alias
alias:          of:N*T*Ccnxt,cx92755-i2cC*
alias:          of:N*T*Ccnxt,cx92755-i2c

Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>

---

 drivers/i2c/busses/i2c-digicolor.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
index 9604024e0eb0..49f2084f7bb5 100644
--- a/drivers/i2c/busses/i2c-digicolor.c
+++ b/drivers/i2c/busses/i2c-digicolor.c
@@ -368,6 +368,7 @@ static const struct of_device_id dc_i2c_match[] = {
 	{ .compatible = "cnxt,cx92755-i2c" },
 	{ },
 };
+MODULE_DEVICE_TABLE(of, dc_i2c_match);
 
 static struct platform_driver dc_i2c_driver = {
 	.probe   = dc_i2c_probe,
-- 
2.7.4

^ permalink raw reply related

* [PATCH v20 10/10] fpga-manager: Add Socfpga Arria10 support
From: Moritz Fischer @ 2016-10-18 21:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161017160941.4205-11-atull@opensource.altera.com>

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>
> ---
> v19: Added to this patchset as has been changed to use
>        fpga image information struct
>      a checkpatch fix of a block comment
>      do not use clk_put because we are using devm_clk_get
> v20: use regmap_read_poll_timeout
>      Add some macros/comments
>      remove some debug prints
> ---
>  drivers/fpga/Kconfig       |   6 +
>  drivers/fpga/Makefile      |   1 +
>  drivers/fpga/socfpga-a10.c | 556 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 563 insertions(+)
>  create mode 100644 drivers/fpga/socfpga-a10.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 8fe6a84..889e4c3 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -26,6 +26,12 @@ config FPGA_MGR_SOCFPGA
>  	help
>  	  FPGA manager driver support for Altera SOCFPGA.
>  
> +config FPGA_MGR_SOCFPGA_A10
> +	tristate "Altera SoCFPGA Arria10"
> +	depends on ARCH_SOCFPGA
> +	help
> +	  FPGA manager driver support for Altera Arria10 SoCFPGA.
> +
>  config FPGA_MGR_ZYNQ_FPGA
>  	tristate "Xilinx Zynq FPGA"
>  	depends on ARCH_ZYNQ || COMPILE_TEST
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index a6f874d..8df07bc 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_FPGA)			+= fpga-mgr.o
>  
>  # FPGA Manager Drivers
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
> +obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  
>  # FPGA Bridge Drivers
> diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c
> new file mode 100644
> index 0000000..ccd9fb2
> --- /dev/null
> +++ b/drivers/fpga/socfpga-a10.c
> @@ -0,0 +1,556 @@
> +/*
> + * FPGA Manager Driver for Altera Arria10 SoCFPGA
> + *
> + * Copyright (C) 2015-2016 Altera Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/regmap.h>
> +
> +#define A10_FPGAMGR_DCLKCNT_OFST				0x08
> +#define A10_FPGAMGR_DCLKSTAT_OFST				0x0c
> +#define A10_FPGAMGR_IMGCFG_CTL_00_OFST				0x70
> +#define A10_FPGAMGR_IMGCFG_CTL_01_OFST				0x74
> +#define A10_FPGAMGR_IMGCFG_CTL_02_OFST				0x78
> +#define A10_FPGAMGR_IMGCFG_STAT_OFST				0x80
> +
> +#define A10_FPGAMGR_DCLKSTAT_DCLKDONE				BIT(0)
> +
> +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG		BIT(0)
> +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS		BIT(1)
> +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE		BIT(2)
> +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG			BIT(8)
> +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE		BIT(16)
> +#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE		BIT(24)
> +
> +#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG		BIT(0)
> +#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST		BIT(16)
> +#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE			BIT(24)
> +
> +#define A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL			BIT(0)
> +#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK		(BIT(16) | BIT(17))
> +#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT			16
> +#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH			BIT(24)
> +#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT		24
> +
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR			BIT(0)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE		BIT(1)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE			BIT(2)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN			BIT(4)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN			BIT(6)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY			BIT(9)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE			BIT(10)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR			BIT(11)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN			BIT(12)
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK	(BIT(16) | BIT(17) | BIT(18))
> +#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT		        16
> +
> +/* FPGA CD Ratio Value */
> +#define CDRATIO_x1						0x0
> +#define CDRATIO_x2						0x1
> +#define CDRATIO_x4						0x2
> +#define CDRATIO_x8						0x3
> +
> +/* Configuration width 16/32 bit */
> +#define CFGWDTH_32						1
> +#define CFGWDTH_16						0
> +
> +/*
> + * struct a10_fpga_priv - private data for fpga manager
> + * @regmap: regmap for register access
> + * @fpga_data_addr: iomap for single address data register to FPGA
> + * @clk: clock
> + */
> +struct a10_fpga_priv {
> +	struct regmap *regmap;
> +	void __iomem *fpga_data_addr;
> +	struct clk *clk;
> +};
> +
> +static bool socfpga_a10_fpga_writeable_reg(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case A10_FPGAMGR_DCLKCNT_OFST:
> +	case A10_FPGAMGR_DCLKSTAT_OFST:
> +	case A10_FPGAMGR_IMGCFG_CTL_00_OFST:
> +	case A10_FPGAMGR_IMGCFG_CTL_01_OFST:
> +	case A10_FPGAMGR_IMGCFG_CTL_02_OFST:
> +		return true;
> +	}
> +	return false;
> +}
> +
> +static bool socfpga_a10_fpga_readable_reg(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case A10_FPGAMGR_DCLKCNT_OFST:
> +	case A10_FPGAMGR_DCLKSTAT_OFST:
> +	case A10_FPGAMGR_IMGCFG_CTL_00_OFST:
> +	case A10_FPGAMGR_IMGCFG_CTL_01_OFST:
> +	case A10_FPGAMGR_IMGCFG_CTL_02_OFST:
> +	case A10_FPGAMGR_IMGCFG_STAT_OFST:
> +		return true;
> +	}
> +	return false;
> +}
> +
> +static const struct regmap_config socfpga_a10_fpga_regmap_config = {
> +	.reg_bits = 32,
> +	.reg_stride = 4,
> +	.val_bits = 32,
> +	.writeable_reg = socfpga_a10_fpga_writeable_reg,
> +	.readable_reg = socfpga_a10_fpga_readable_reg,
> +	.max_register = A10_FPGAMGR_IMGCFG_STAT_OFST,
> +	.cache_type = REGCACHE_NONE,
> +};
> +
> +/*
> + * from the register map description of cdratio in imgcfg_ctrl_02:
> + *  Normal Configuration    : 32bit Passive Parallel
> + *  Partial Reconfiguration : 16bit Passive Parallel
> + */
> +static void socfpga_a10_fpga_set_cfg_width(struct a10_fpga_priv *priv,
> +					   int width)
> +{
> +	width <<= A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT;
> +
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH, width);
> +}
> +
> +static void socfpga_a10_fpga_generate_dclks(struct a10_fpga_priv *priv,
> +					    u32 count)
> +{
> +	u32 val;
> +
> +	/* Clear any existing DONE status. */
> +	regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST,
> +		     A10_FPGAMGR_DCLKSTAT_DCLKDONE);
> +
> +	/* Issue the DCLK regmap. */
> +	regmap_write(priv->regmap, A10_FPGAMGR_DCLKCNT_OFST, count);
> +
> +	/* wait till the dclkcnt done */
> +	regmap_read_poll_timeout(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, val,
> +				 val, 1, 100);
> +
> +	/* Clear DONE status. */
> +	regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST,
> +		     A10_FPGAMGR_DCLKSTAT_DCLKDONE);
> +}
> +
> +#define RBF_ENCRYPTION_MODE_OFFSET		69
> +#define RBF_DECOMPRESS_OFFSET			229
> +
> +static int socfpga_a10_fpga_encrypted(u32 *buf32, size_t buf32_size)
> +{
> +	if (buf32_size < RBF_ENCRYPTION_MODE_OFFSET + 1)
> +		return -EINVAL;
> +
> +	/* Is the bitstream encrypted? */
> +	return ((buf32[RBF_ENCRYPTION_MODE_OFFSET] >> 2) & 3) != 0;
> +}
> +
> +static int socfpga_a10_fpga_compressed(u32 *buf32, size_t buf32_size)
> +{
> +	if (buf32_size < RBF_DECOMPRESS_OFFSET + 1)
> +		return -EINVAL;
> +
> +	/* Is the bitstream compressed? */
> +	return !((buf32[RBF_DECOMPRESS_OFFSET] >> 1) & 1);
> +}
> +
> +static unsigned int socfpga_a10_fpga_get_cd_ratio(unsigned int cfg_width,
> +						  bool encrypt, bool compress)
> +{
> +	unsigned int cd_ratio;
> +
> +	/*
> +	 * cd ratio is dependent on cfg width and whether the bitstream
> +	 * is encrypted and/or compressed.
> +	 *
> +	 * | width | encr. | compr. | cd ratio |
> +	 * |  16   |   0   |   0    |     1    |
> +	 * |  16   |   0   |   1    |     4    |
> +	 * |  16   |   1   |   0    |     2    |
> +	 * |  16   |   1   |   1    |     4    |
> +	 * |  32   |   0   |   0    |     1    |
> +	 * |  32   |   0   |   1    |     8    |
> +	 * |  32   |   1   |   0    |     4    |
> +	 * |  32   |   1   |   1    |     8    |
> +	 */
> +	if (!compress && !encrypt)
> +		return CDRATIO_x1;
> +
> +	if (compress)
> +		cd_ratio = CDRATIO_x4;
> +	else
> +		cd_ratio = CDRATIO_x2;
> +
> +	/* If 32 bit, double the cd ratio by incrementing the field  */
> +	if (cfg_width == CFGWDTH_32)
> +		cd_ratio += 1;
> +
> +	return cd_ratio;
> +}
> +
> +static int socfpga_a10_fpga_set_cdratio(struct fpga_manager *mgr,
> +					unsigned int cfg_width,
> +					const char *buf, size_t count)
> +{
> +	struct a10_fpga_priv *priv = mgr->priv;
> +	unsigned int cd_ratio;
> +	int encrypt, compress;
> +
> +	encrypt = socfpga_a10_fpga_encrypted((u32 *)buf, count / 4);
> +	if (encrypt < 0)
> +		return -EINVAL;
> +
> +	compress = socfpga_a10_fpga_compressed((u32 *)buf, count / 4);
> +	if (compress < 0)
> +		return -EINVAL;
> +
> +	cd_ratio = socfpga_a10_fpga_get_cd_ratio(cfg_width, encrypt, compress);
> +
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK,
> +			   cd_ratio << A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT);
> +
> +	return 0;
> +}
> +
> +static u32 socfpga_a10_fpga_read_stat(struct a10_fpga_priv *priv)
> +{
> +	u32 val;
> +
> +	regmap_read(priv->regmap, A10_FPGAMGR_IMGCFG_STAT_OFST, &val);
> +
> +	return val;
> +}
> +
> +static int socfpga_a10_fpga_wait_for_pr_ready(struct a10_fpga_priv *priv)
> +{
> +	u32 reg, i;
> +
> +	for (i = 0; i < 10 ; i++) {
> +		reg = socfpga_a10_fpga_read_stat(priv);
> +
> +		if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR)
> +			return -EINVAL;
> +
> +		if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY)
> +			return 0;
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int socfpga_a10_fpga_wait_for_pr_done(struct a10_fpga_priv *priv)
> +{
> +	u32 reg, i;
> +
> +	for (i = 0; i < 10 ; i++) {
> +		reg = socfpga_a10_fpga_read_stat(priv);
> +
> +		if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR)
> +			return -EINVAL;
> +
> +		if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE)
> +			return 0;
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +/* Start the FPGA programming by initialize the FPGA Manager */
> +static int socfpga_a10_fpga_write_init(struct fpga_manager *mgr,
> +				       struct fpga_image_info *info,
> +				       const char *buf, size_t count)
> +{
> +	struct a10_fpga_priv *priv = mgr->priv;
> +	unsigned int cfg_width;
> +	u32 msel, stat, mask;
> +	int ret;
> +
> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG)
> +		cfg_width = CFGWDTH_16;
> +	else
> +		return -EINVAL;
> +
> +	/* Check for passive parallel (msel == 000 or 001) */
> +	msel = socfpga_a10_fpga_read_stat(priv);
> +	msel &= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK;
> +	msel >>= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT;
> +	if ((msel != 0) && (msel != 1)) {
> +		dev_dbg(&mgr->dev, "Fail: invalid msel=%d\n", msel);
> +		return -EINVAL;
> +	}
> +
> +	/* Make sure no external devices are interfering */
> +	stat = socfpga_a10_fpga_read_stat(priv);
> +	mask = A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN |
> +	       A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN;
> +	if ((stat & mask) != mask)
> +		return -EINVAL;
> +
> +	/* Set cfg width */
> +	socfpga_a10_fpga_set_cfg_width(priv, cfg_width);
> +
> +	/* Determine cd ratio from bitstream header and set cd ratio */
> +	ret = socfpga_a10_fpga_set_cdratio(mgr, cfg_width, buf, count);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Clear s2f_nce to enable chip select.  Leave pr_request
> +	 * unasserted and override disabled.
> +	 */
> +	regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST,
> +		     A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG);
> +
> +	/* Set cfg_ctrl to enable s2f dclk and data */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL,
> +			   A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL);
> +
> +	/*
> +	 * Disable overrides not needed for pr.
> +	 * s2f_config==1 leaves reset deasseted.
> +	 */
> +	regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_00_OFST,
> +		     A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG |
> +		     A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS |
> +		     A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE |
> +		     A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG);
> +
> +	/* Enable override for data, dclk, nce, and pr_request to CSS */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, 0);
> +
> +	/* Send some clocks to clear out any errors */
> +	socfpga_a10_fpga_generate_dclks(priv, 256);
> +
> +	/* Assert pr_request */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST);
> +
> +	/* Provide 2048 DCLKs before starting the config data streaming. */
> +	socfpga_a10_fpga_generate_dclks(priv, 0x7ff);
> +
> +	/* Wait for pr_ready */
> +	return socfpga_a10_fpga_wait_for_pr_ready(priv);
> +}
> +
> +/*
> + * write data to the FPGA data register
> + */
> +static int socfpga_a10_fpga_write(struct fpga_manager *mgr, const char *buf,
> +				  size_t count)
> +{
> +	struct a10_fpga_priv *priv = mgr->priv;
> +	u32 *buffer_32 = (u32 *)buf;
> +	size_t i = 0;
> +
> +	if (count <= 0)
> +		return -EINVAL;
> +
> +	/* Write out the complete 32-bit chunks */
> +	while (count >= sizeof(u32)) {
> +		writel(buffer_32[i++], priv->fpga_data_addr);
> +		count -= sizeof(u32);
> +	}
> +
> +	/* Write out remaining non 32-bit chunks */
> +	switch (count) {
> +	case 3:
> +		writel(buffer_32[i++] & 0x00ffffff, priv->fpga_data_addr);
> +		break;
> +	case 2:
> +		writel(buffer_32[i++] & 0x0000ffff, priv->fpga_data_addr);
> +		break;
> +	case 1:
> +		writel(buffer_32[i++] & 0x000000ff, priv->fpga_data_addr);
> +		break;
> +	case 0:
> +		break;
> +	default:
> +		/* This will never happen */
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int socfpga_a10_fpga_write_complete(struct fpga_manager *mgr,
> +					   struct fpga_image_info *info)
> +{
> +	struct a10_fpga_priv *priv = mgr->priv;
> +	u32 reg;
> +	int ret;
> +
> +	/* Wait for pr_done */
> +	ret = socfpga_a10_fpga_wait_for_pr_done(priv);
> +
> +	/* Clear pr_request */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 0);
> +
> +	/* Send some clocks to clear out any errors */
> +	socfpga_a10_fpga_generate_dclks(priv, 256);
> +
> +	/* Disable s2f dclk and data */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 0);
> +
> +	/* Deassert chip select */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE);
> +
> +	/* Disable data, dclk, nce, and pr_request override to CSS */
> +	regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG,
> +			   A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG);
> +
> +	/* Return any errors regarding pr_done or pr_error */
> +	if (ret)
> +		return ret;
> +
> +	/* Final check */
> +	reg = socfpga_a10_fpga_read_stat(priv);
> +
> +	if (((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) == 0) ||
> +	    ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN) == 0) ||
> +	    ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0)) {
> +		dev_dbg(&mgr->dev,
> +			"Timeout in final check. Status=%08xf\n", reg);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +static enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr)
> +{
> +	struct a10_fpga_priv *priv = mgr->priv;
> +	u32 reg = socfpga_a10_fpga_read_stat(priv);
> +
> +	if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE)
> +		return FPGA_MGR_STATE_OPERATING;
> +
> +	if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY)
> +		return FPGA_MGR_STATE_WRITE;
> +
> +	if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR)
> +		return FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
> +
> +	if ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0)
> +		return FPGA_MGR_STATE_RESET;
> +
> +	return FPGA_MGR_STATE_UNKNOWN;
> +}
> +
> +static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = {
> +	.state = socfpga_a10_fpga_state,
> +	.write_init = socfpga_a10_fpga_write_init,
> +	.write = socfpga_a10_fpga_write,
> +	.write_complete = socfpga_a10_fpga_write_complete,
> +};
> +
> +static int socfpga_a10_fpga_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct a10_fpga_priv *priv;
> +	void __iomem *reg_base;
> +	struct resource *res;
> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	/* First mmio base is for register access */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	reg_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(reg_base))
> +		return PTR_ERR(reg_base);
> +
> +	/* Second mmio base is for writing FPGA image data */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	priv->fpga_data_addr = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(priv->fpga_data_addr))
> +		return PTR_ERR(priv->fpga_data_addr);
> +
> +	/* regmap for register access */
> +	priv->regmap = devm_regmap_init_mmio(dev, reg_base,
> +					     &socfpga_a10_fpga_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return -ENODEV;
> +
> +	priv->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(priv->clk)) {
> +		dev_err(dev, "no clock specified\n");
> +		return PTR_ERR(priv->clk);
> +	}
> +
> +	ret = clk_prepare_enable(priv->clk);
> +	if (ret) {
> +		dev_err(dev, "could not enable clock\n");
> +		return -EBUSY;
> +	}
> +
> +	return fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager",
> +				 &socfpga_a10_fpga_mgr_ops, priv);
> +}
> +
> +static int socfpga_a10_fpga_remove(struct platform_device *pdev)
> +{
> +	struct fpga_manager *mgr = platform_get_drvdata(pdev);
> +	struct a10_fpga_priv *priv = mgr->priv;
> +
> +	fpga_mgr_unregister(&pdev->dev);
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id socfpga_a10_fpga_of_match[] = {
> +	{ .compatible = "altr,socfpga-a10-fpga-mgr", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match);
> +
> +static struct platform_driver socfpga_a10_fpga_driver = {
> +	.probe = socfpga_a10_fpga_probe,
> +	.remove = socfpga_a10_fpga_remove,
> +	.driver = {
> +		.name	= "socfpga_a10_fpga_manager",
> +		.of_match_table = socfpga_a10_fpga_of_match,
> +	},
> +};
> +
> +module_platform_driver(socfpga_a10_fpga_driver);
> +
> +MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
> +MODULE_DESCRIPTION("SoCFPGA Arria10 FPGA Manager");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.10.1
> 

Looking good,

Moritz

^ permalink raw reply

* [PATCH 3/3] ARM: socfpga: defconfig: enable qspi
From: Dinh Nguyen @ 2016-10-18 21:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018074304.6744-3-s.trumtrar@pengutronix.de>

On Tue, 18 Oct 2016, Steffen Trumtrar wrote:

> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> ---
>  arch/arm/configs/socfpga_defconfig | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig
> index 9f84be5b3ac5..466050663c86 100644
> --- a/arch/arm/configs/socfpga_defconfig
> +++ b/arch/arm/configs/socfpga_defconfig

Thanks Steffen, all patches applied. I'll fixup the commit header for the DTS
patches. The arm-soc maintainers prefer the DTS patches to be:

"ARM: dts: <platform>"

BR,
Dinh

^ permalink raw reply

* [PATCH] PM / AVS: rockchip-io: make the log more consistent
From: Kevin Hilman @ 2016-10-18 21:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1883054.D2Rm2X9N2G@phil>

Heiko Stuebner <heiko@sntech.de> writes:

> Am Montag, 10. Oktober 2016, 20:44:22 CEST schrieb Shawn Lin:
>> When testing SD hotplug automatically, I got bunch of
>> useless log like this:
>> 
>> [  588.357838] mmc0: card 0007 removed
>> [  589.492664] rockchip-iodomain ff770000.syscon:io-domains: Setting to
>> 3300000 done [  589.500698] vccio_sd: ramp_delay not set
>> [  589.504817] rockchip-iodomain ff770000.syscon:io-domains: Setting to
>> 3300000 done [  589.669705] rockchip-iodomain ff770000.syscon:io-domains:
>> Setting to 3300000 done [  589.677593] vccio_sd: ramp_delay not set
>> [  589.681581] rockchip-iodomain ff770000.syscon:io-domains: Setting to
>> 1800000 done [  590.032820] dwmmc_rockchip ff0c0000.dwmmc: Successfully
>> tuned phase to 140 [  590.039725] mmc0: new ultra high speed SDR50 SDHC
>> card at address 0007 [  590.046641] mmcblk0: mmc0:0007 SD32G 29.3 GiB
>> [  590.052163]  mmcblk0: p1
>> 
>> Moreover the code is intent to print the 'uV' for debug but
>> later print it using dev_info. It looks more like to me that
>> it should be the real intention of the code. Anyway, let's
>> mark this verbose log as debug message.
>> 
>> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
>
> reducing the amount of logs, especially for information not generally needed 
> looks sane
>
> Reviewed-by: Heiko Stuebner <heiko@sntech.de>

Acked-by: Kevin Hilman <khilman@baylibre.com>

Rafael, feel free to apply directly as a fix for v4.9-rc, or wait for
v4.10 if you prefer.

Kevin

^ permalink raw reply

* [PATCHv3 0/4] WX checking for arm64
From: Laura Abbott @ 2016-10-18 22:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is v3 of the implementation to check for writable and executable pages on
arm64. This is a basically a rebase + acks.

Laura Abbott (4):
  arm64: dump: Make ptdump debugfs a separate option
  arm64: dump: Make the page table dumping seq_file optional
  arm64: dump: Remove max_addr
  arm64: dump: Add checking for writable and exectuable pages

 arch/arm64/Kconfig.debug           |  35 ++++++++++++-
 arch/arm64/include/asm/ptdump.h    |  22 +++++---
 arch/arm64/mm/Makefile             |   3 +-
 arch/arm64/mm/dump.c               | 104 +++++++++++++++++++++++++++----------
 arch/arm64/mm/mmu.c                |   2 +
 arch/arm64/mm/ptdump_debugfs.c     |  31 +++++++++++
 drivers/firmware/efi/arm-runtime.c |   5 +-
 7 files changed, 163 insertions(+), 39 deletions(-)
 create mode 100644 arch/arm64/mm/ptdump_debugfs.c

-- 
2.7.4

^ permalink raw reply

* [PATCHv3 1/4] arm64: dump: Make ptdump debugfs a separate option
From: Laura Abbott @ 2016-10-18 22:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476828091-17802-1-git-send-email-labbott@redhat.com>


ptdump_register currently initializes a set of page table information and
registers debugfs. There are uses for the ptdump option without wanting the
debugfs options. Split this out to make it a separate option.

Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v3: Minor header guard fixup.

Mark Rutland pointed out that this needs to be reviewed by the EFI maintainers
so I'm explicitly adding appropriate people/lists.
---
 arch/arm64/Kconfig.debug           |  6 +++++-
 arch/arm64/include/asm/ptdump.h    | 15 +++++++++------
 arch/arm64/mm/Makefile             |  3 ++-
 arch/arm64/mm/dump.c               | 26 +++++---------------------
 arch/arm64/mm/ptdump_debugfs.c     | 31 +++++++++++++++++++++++++++++++
 drivers/firmware/efi/arm-runtime.c |  4 ++--
 6 files changed, 54 insertions(+), 31 deletions(-)
 create mode 100644 arch/arm64/mm/ptdump_debugfs.c

diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index b661fe7..21a5b74 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -2,9 +2,13 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config ARM64_PTDUMP
+config ARM64_PTDUMP_CORE
+	def_bool n
+
+config ARM64_PTDUMP_DEBUGFS
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
+	select ARM64_PTDUMP_CORE
 	select DEBUG_FS
         help
 	  Say Y here if you want to show the kernel pagetable layout in a
diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index 07b8ed0..16335da 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -16,9 +16,10 @@
 #ifndef __ASM_PTDUMP_H
 #define __ASM_PTDUMP_H
 
-#ifdef CONFIG_ARM64_PTDUMP
+#ifdef CONFIG_ARM64_PTDUMP_CORE
 
 #include <linux/mm_types.h>
+#include <linux/seq_file.h>
 
 struct addr_marker {
 	unsigned long start_address;
@@ -32,13 +33,15 @@ struct ptdump_info {
 	unsigned long			max_addr;
 };
 
-int ptdump_register(struct ptdump_info *info, const char *name);
-
+void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
+#ifdef CONFIG_ARM64_PTDUMP_DEBUGFS
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name);
 #else
-static inline int ptdump_register(struct ptdump_info *info, const char *name)
+static inline int ptdump_debugfs_register(struct ptdump_info *info,
+					const char *name)
 {
 	return 0;
 }
-#endif /* CONFIG_ARM64_PTDUMP */
-
+#endif
+#endif /* CONFIG_ARM64_PTDUMP_CORE */
 #endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 54bb209..e703fb9 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -3,7 +3,8 @@ obj-y				:= dma-mapping.o extable.o fault.o init.o \
 				   ioremap.o mmap.o pgd.o mmu.o \
 				   context.o proc.o pageattr.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
-obj-$(CONFIG_ARM64_PTDUMP)	+= dump.o
+obj-$(CONFIG_ARM64_PTDUMP_CORE)	+= dump.o
+obj-$(CONFIG_ARM64_PTDUMP_DEBUGFS)	+= ptdump_debugfs.o
 obj-$(CONFIG_NUMA)		+= numa.o
 
 obj-$(CONFIG_KASAN)		+= kasan_init.o
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index 9c3e75d..f0f0be7 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -304,9 +304,8 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
 	}
 }
 
-static int ptdump_show(struct seq_file *m, void *v)
+void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)
 {
-	struct ptdump_info *info = m->private;
 	struct pg_state st = {
 		.seq = m,
 		.marker = info->markers,
@@ -315,33 +314,16 @@ static int ptdump_show(struct seq_file *m, void *v)
 	walk_pgd(&st, info->mm, info->base_addr);
 
 	note_page(&st, 0, 0, 0);
-	return 0;
 }
 
-static int ptdump_open(struct inode *inode, struct file *file)
+static void ptdump_initialize(void)
 {
-	return single_open(file, ptdump_show, inode->i_private);
-}
-
-static const struct file_operations ptdump_fops = {
-	.open		= ptdump_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-int ptdump_register(struct ptdump_info *info, const char *name)
-{
-	struct dentry *pe;
 	unsigned i, j;
 
 	for (i = 0; i < ARRAY_SIZE(pg_level); i++)
 		if (pg_level[i].bits)
 			for (j = 0; j < pg_level[i].num; j++)
 				pg_level[i].mask |= pg_level[i].bits[j].mask;
-
-	pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
-	return pe ? 0 : -ENOMEM;
 }
 
 static struct ptdump_info kernel_ptdump_info = {
@@ -352,6 +334,8 @@ static struct ptdump_info kernel_ptdump_info = {
 
 static int ptdump_init(void)
 {
-	return ptdump_register(&kernel_ptdump_info, "kernel_page_tables");
+	ptdump_initialize();
+	return ptdump_debugfs_register(&kernel_ptdump_info,
+					"kernel_page_tables");
 }
 device_initcall(ptdump_init);
diff --git a/arch/arm64/mm/ptdump_debugfs.c b/arch/arm64/mm/ptdump_debugfs.c
new file mode 100644
index 0000000..eee4d86
--- /dev/null
+++ b/arch/arm64/mm/ptdump_debugfs.c
@@ -0,0 +1,31 @@
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptdump.h>
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+	struct ptdump_info *info = m->private;
+	ptdump_walk_pgd(m, info);
+	return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ptdump_show, inode->i_private);
+}
+
+static const struct file_operations ptdump_fops = {
+	.open		= ptdump_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name)
+{
+	struct dentry *pe;
+	pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
+	return pe ? 0 : -ENOMEM;
+
+}
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 7c75a8d..349dc3e 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -39,7 +39,7 @@ static struct mm_struct efi_mm = {
 	.mmlist			= LIST_HEAD_INIT(efi_mm.mmlist),
 };
 
-#ifdef CONFIG_ARM64_PTDUMP
+#ifdef CONFIG_ARM64_PTDUMP_DEBUGFS
 #include <asm/ptdump.h>
 
 static struct ptdump_info efi_ptdump_info = {
@@ -53,7 +53,7 @@ static struct ptdump_info efi_ptdump_info = {
 
 static int __init ptdump_init(void)
 {
-	return ptdump_register(&efi_ptdump_info, "efi_page_tables");
+	return ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables");
 }
 device_initcall(ptdump_init);
 
-- 
2.7.4

^ permalink raw reply related

* [PATCHv3 2/4] arm64: dump: Make the page table dumping seq_file optional
From: Laura Abbott @ 2016-10-18 22:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476828091-17802-1-git-send-email-labbott@redhat.com>


The page table dumping code always assumes it will be dumping to a
seq_file to userspace. Future code will be taking advantage of
the page table dumping code but will not need the seq_file. Make
the seq_file optional for these cases.

Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v3: No changes
---
 arch/arm64/mm/dump.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index f0f0be7..bb36649 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -50,6 +50,18 @@ static const struct addr_marker address_markers[] = {
 	{ -1,				NULL },
 };
 
+#define pt_dump_seq_printf(m, fmt, args...)	\
+({						\
+	if (m)					\
+		seq_printf(m, fmt, ##args);	\
+})
+
+#define pt_dump_seq_puts(m, fmt)	\
+({					\
+	if (m)				\
+		seq_printf(m, fmt);	\
+})
+
 /*
  * The page dumper groups page table entries of the same type into a single
  * description. It uses pg_state to track the range information while
@@ -186,7 +198,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
 			s = bits->clear;
 
 		if (s)
-			seq_printf(st->seq, " %s", s);
+			pt_dump_seq_printf(st->seq, " %s", s);
 	}
 }
 
@@ -200,14 +212,14 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
 		st->level = level;
 		st->current_prot = prot;
 		st->start_address = addr;
-		seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+		pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
 	} else if (prot != st->current_prot || level != st->level ||
 		   addr >= st->marker[1].start_address) {
 		const char *unit = units;
 		unsigned long delta;
 
 		if (st->current_prot) {
-			seq_printf(st->seq, "0x%016lx-0x%016lx   ",
+			pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx   ",
 				   st->start_address, addr);
 
 			delta = (addr - st->start_address) >> 10;
@@ -215,17 +227,17 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
 				delta >>= 10;
 				unit++;
 			}
-			seq_printf(st->seq, "%9lu%c %s", delta, *unit,
+			pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
 				   pg_level[st->level].name);
 			if (pg_level[st->level].bits)
 				dump_prot(st, pg_level[st->level].bits,
 					  pg_level[st->level].num);
-			seq_puts(st->seq, "\n");
+			pt_dump_seq_puts(st->seq, "\n");
 		}
 
 		if (addr >= st->marker[1].start_address) {
 			st->marker++;
-			seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+			pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
 		}
 
 		st->start_address = addr;
@@ -235,7 +247,7 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
 
 	if (addr >= st->marker[1].start_address) {
 		st->marker++;
-		seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+		pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
 	}
 
 }
-- 
2.7.4

^ permalink raw reply related

* [PATCHv3 3/4] arm64: dump: Remove max_addr
From: Laura Abbott @ 2016-10-18 22:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476828091-17802-1-git-send-email-labbott@redhat.com>


max_addr was added as part of struct ptdump_info but has never actually
been used. Remove it.

Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v3: No changes
---
 arch/arm64/include/asm/ptdump.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index 16335da..f72ee69 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -30,7 +30,6 @@ struct ptdump_info {
 	struct mm_struct		*mm;
 	const struct addr_marker	*markers;
 	unsigned long			base_addr;
-	unsigned long			max_addr;
 };
 
 void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
-- 
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