Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4] MMC: meson: initial support for GX platforms
From: Ulf Hansson @ 2016-10-19  7:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018195605.21145-1-khilman@baylibre.com>

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

Just realize this. You should split the DT doc into a separate patch,
such the DT maintainers can ack it.

Otherwise this looks good to me!

Kind regards
Uffe


>  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

* how to enable suspend to ram for arm-64 bits
From: yoma sophian @ 2016-10-19  7:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <95484b8f-58de-3588-ac91-5ec21e66ab05@arm.com>

hi Sudeep:

2016-10-18 18:59 GMT+08:00 Sudeep Holla <sudeep.holla@arm.com>:
>
>
> On 18/10/16 11:45, Mark Rutland wrote:
>>
>> On Tue, Oct 18, 2016 at 12:00:02PM +0200, Pavel Machek wrote:
>>>>>
>>>>> b. in arm64, if some platform has its own suspend flow,  couldn't it
>>>>> adopts arm/match-xxx to register its own global suspend method?
>>>>
>>>>
>>>> No, PSCI is highly recommended.
>>>
>>>
>>> Relying on firmware for suspend on x86 was a great disaster, lets not
>>> repeat
>>> that mistake. arm32 has better powermanagement than x86 ever will (see
>>> Nokia N900
>>> for example) -- feel free to copy that code from arm32.
>>
>>
>> Quite frankly, copying hundreds of lines of board-specific code
>> (including assembly that won't compile) is unlikely to help.
>>
>> So far arm64 requires well-defined, standard, reusable interfaces (e.g.
>> PSCI). That cleanly separates concerns (e.g. anyone can implement the
>> backend without mandatory changes to the kernel), and keeps things
>> maintainable.
>>
>> ARM publishes and maintains the ARM Trusted Firmware [1], which anyone
>> can use and build atop of. It's open source (three-clause BSD with DCO),
>> and accepts board ports. You can have a completely open stack,
>> regardless of whether part of that stack is firmware.
>>
>
> I think you missed to add the link[1]
> [1] https://github.com/ARM-software/arm-trusted-firmware
thanks for your kind information ^^

^ permalink raw reply

* [PATCH 2/2] iommu/mediatek: Convert M4Uv1 to iommu_fwspec
From: Honghui Zhang @ 2016-10-19  7:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <a40dbcc1ff40bf09483316354d2fdcb2d432eb81.1476704508.git.robin.murphy@arm.com>

On Mon, 2016-10-17 at 12:49 +0100, Robin Murphy wrote:
> Our per-device data consists of the M4U instance and firmware-provided
> list of LARB IDs, which is a perfect fit for the generic iommu_fwspec
> machinery. Use that directly instead of the custom archdata code - while
> we can't rely on the of_xlate() mechanism to initialise things until the
> 32-bit ARM DMA code learns about groups and default domains, it still
> results in a reasonable simplification overall.
> 
> CC: Honghui Zhang <honghui.zhang@mediatek.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>

Thanks Robin.
Tested-by: Honghui Zhang <honghui.zhang@mediatek.com>

> ---
>  drivers/iommu/mtk_iommu.h    |  6 ---
>  drivers/iommu/mtk_iommu_v1.c | 95 +++++++++++++++++---------------------------
>  2 files changed, 36 insertions(+), 65 deletions(-)
> 

^ permalink raw reply

* [PATCH] Revert "gpio/mvebu: convert to use irq_domain_add_simple()"
From: Gregory CLEMENT @ 2016-10-19  7:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476831396-24359-1-git-send-email-jgunthorpe@obsidianresearch.com>

Hi Jason,
 
 On mer., oct. 19 2016, Jason Gunthorpe <jgunthorpe@obsidianresearch.com> wrote:

> This reverts commit ce931f571b6dcf8534e8740e8cd16565cf362536.
>
> The only difference betwen _simple and _legacy is that _simple
> calls irq_alloc_descs, however mvebu_gpio_probe already called
> irq_alloc_descs a few lines above.

And what about removing the irq_alloc_descs ?

Going back to use the _legacy version seems wrong for me.

Gregory

>
> This fixes these kernel error messages from the double call
> to irq_alloc_descs:
>
>  irq: Cannot allocate irq_descs @ IRQ34, assuming pre-allocated
>  irq: Cannot allocate irq_descs @ IRQ66, assuming pre-allocated
>
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> Cc: Andrew Lunn <andrew@lunn.ch>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Fixes: ce931f571b6d ("gpio/mvebu: convert to use irq_domain_add_simple()")
> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
> ---
>  drivers/gpio/gpio-mvebu.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
> index cd5dc27320a2..2e0c8d8b7792 100644
> --- a/drivers/gpio/gpio-mvebu.c
> +++ b/drivers/gpio/gpio-mvebu.c
> @@ -807,8 +807,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
>  			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
>  
>  	/* Setup irq domain on top of the generic chip. */
> -	mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
> -					       mvchip->irqbase,
> +	mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
> +					       mvchip->irqbase, 0,
>  					       &irq_domain_simple_ops,
>  					       mvchip);
>  	if (!mvchip->domain) {
> -- 
> 2.1.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH] ARM: dts: am335x-baltos-ir5221: use both musb channels in host mode
From: yegorslists at googlemail.com @ 2016-10-19  7:09 UTC (permalink / raw)
  To: linux-arm-kernel

From: Yegor Yefremov <yegorslists@googlemail.com>

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
---
 arch/arm/boot/dts/am335x-baltos-ir5221.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/am335x-baltos-ir5221.dts b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
index d0faa7b..f599350 100644
--- a/arch/arm/boot/dts/am335x-baltos-ir5221.dts
+++ b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
@@ -114,7 +114,7 @@
 
 &usb1 {
 	status = "okay";
-	dr_mode = "otg";
+	dr_mode = "host";
 };
 
 &cpsw_emac0 {
-- 
2.1.4

^ permalink raw reply related

* [PATCH v9 2/2] ARM: dts: add TOPEET itop elite based board
From: Krzysztof Kozlowski @ 2016-10-19  5:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <58DB0A67-6C74-409B-80B2-9F02492D3A55@soulik.info>

On Wed, Oct 19, 2016 at 4:15 AM, Ayaka <ayaka@soulik.info> wrote:
>
>
> ??? iPad ??
>
>> Krzysztof Kozlowski <krzk@kernel.org> ? 2016?10?19? ??1:37 ???
>>
>>> On Wed, Oct 19, 2016 at 01:18:49AM +0800, Randy Li wrote:
>>> The TOPEET itop exynos 4412 have three versions base board. The
>>> Elite version is the cheap one without too much peripheral devices
>>> on it.
>>>
>>> Currently supported are serial console, wired networking(USB),
>>> USB OTG in peripheral mode, USB host, SD storage, GPIO buttons,
>>> PWM beeper, ADC and LEDs. The WM8960 analog audio codec is also
>>> enabled.
>>>
>>> The FIMC is not used for camera currently, I enabled it just for a
>>> colorspace converter.
>>>
>>> Signed-off-by: Randy Li <ayaka@soulik.info>
>>> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
>>
>> Thanks, applied, with missing Rob's ack, minor changes in commit msg and
>> fix in pin function (you used macro for pull up/down instead of
>> function).
> The last time I saw the other dts have applied that, but they are not now. A header file is also missed reported by kbuild, but I didn't meet that.

I wonder why I didn't encounter the build error on my machine... This
needs a follow up fix.

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH 3/3] ARM: socfpga: defconfig: enable qspi
From: Steffen Trumtrar @ 2016-10-19  5:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.02.1610181600570.27375@linux-builds1>

On Tue, Oct 18, 2016 at 04:03:01PM -0500, Dinh Nguyen wrote:
> 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>"

Oops.

Thanks,
Steffen


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH 4/4] i2c: digicolor: Fix module autoload
From: Baruch Siach @ 2016-10-19  5:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476824508-4679-5-git-send-email-javier@osg.samsung.com>

Hi Javier Martinez Canillas,

On Tue, Oct 18, 2016 at 06:01:48PM -0300, Javier Martinez Canillas wrote:
> 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>

Acked-by: Baruch Siach <baruch@tkos.co.il>

Thanks,
baruch

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

-- 
     http://baruch.siach.name/blog/                  ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -

^ permalink raw reply

* [PATCH 4/9] regulator: lp873x: Add support for populating input supply
From: Lokesh Vutla @ 2016-10-19  4:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018142743.xfgjuaw4wlssmoxq@rob-hp-laptop>



On Tuesday 18 October 2016 07:57 PM, Rob Herring wrote:
> On Fri, Oct 14, 2016 at 06:30:28PM +0530, Lokesh Vutla wrote:
>> In order to have a proper topology of regulators for a platform, each
>> registering regulator needs to populate supply_name field for identifying
>> its supply's name. Add supply_name field for lp873x regulators.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Keerthy <j-keerthy@ti.com>
>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>> ---
>>  Documentation/devicetree/bindings/mfd/lp873x.txt | 8 ++++++++
>>  drivers/regulator/lp873x-regulator.c             | 1 +
>>  2 files changed, 9 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/lp873x.txt b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> index 52766c2..936cba3 100644
>> --- a/Documentation/devicetree/bindings/mfd/lp873x.txt
>> +++ b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> @@ -7,6 +7,9 @@ Required properties:
>>    - #gpio-cells:	Should be two.  The first cell is the pin number and
>>  			the second cell is used to specify flags.
>>  			See ../gpio/gpio.txt for more information.
>> +  - xxx-supply:		Phandle to parent supply node of each regulator
>> +			populated under regulators node. xxx should match
>> +			the supply_name populated in driver.
> 
> xxx-in-supply?

Oops. Right. Ill update it and repost.

Thanks and regards,
Lokesh

^ permalink raw reply

* [PATCH] i2c: uniphier[-f]: fix bool logic calculation
From: Masahiro Yamada @ 2016-10-19  4:38 UTC (permalink / raw)
  To: linux-arm-kernel

This code is working, but it should not depend on how "bool" is
typedef'ed, or the bit position of I2C_M_RD.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/i2c/busses/i2c-uniphier-f.c | 2 +-
 drivers/i2c/busses/i2c-uniphier.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index db9105e..b54448e 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -309,7 +309,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
 					 struct i2c_msg *msg, bool stop)
 {
 	struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
-	bool is_read = msg->flags & I2C_M_RD;
+	bool is_read = !!(msg->flags & I2C_M_RD);
 	unsigned long time_left;
 
 	dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 56e92af..cc80bb2 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -177,7 +177,7 @@ static int uniphier_i2c_stop(struct i2c_adapter *adap)
 static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
 					struct i2c_msg *msg, bool stop)
 {
-	bool is_read = msg->flags & I2C_M_RD;
+	bool is_read = !!(msg->flags & I2C_M_RD);
 	bool recovery = false;
 	int ret;
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH] ARM: dts: socfpga: enable qspi on the Cyclone5 devkit
From: dinguyen at opensource.altera.com @ 2016-10-19  4:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@opensource.altera.com>

Enable the qspi controller on the devkit and add the flash chip.

Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
---
 arch/arm/boot/dts/socfpga_cyclone5_socdk.dts |   32 ++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
index 15e43f4..a0868e9 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
@@ -87,6 +87,38 @@
 	status = "okay";
 };
 
+&qspi {
+	status = "okay";
+
+	flash0: n25q00 at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "n25q00";
+		reg = <0>;	/* chip select */
+		spi-max-frequency = <100000000>;
+
+		cdns,page-size = <256>;
+		cdns,block-size = <16>;
+		cdns,read-delay = <4>;
+		cdns,tshsl-ns = <50>;
+		cdns,tsd2d-ns = <50>;
+		cdns,tchsh-ns = <4>;
+		cdns,tslch-ns = <4>;
+
+		partition at qspi-boot {
+			/* 8MB for raw data. */
+			label = "Flash 0 Raw Data";
+			reg = <0x0 0x800000>;
+		};
+
+		partition at qspi-rootfs {
+			/* 120MB for jffs2 data. */
+			label = "Flash 0 jffs2 Filesystem";
+			reg = <0x800000 0x7800000>;
+		};
+	};
+};
+
 &usb1 {
 	status = "okay";
 };
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Jiancheng Xue @ 2016-10-19  3:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAL_JsqK18RHFhDSWA_j+v_pJL6vk+a=GD7oo6O3JJaV4hHHEBg@mail.gmail.com>



? 2016/10/19 10:45, Rob Herring ??:
> On Tue, Oct 18, 2016 at 9:38 PM, Jiancheng Xue
> <xuejiancheng@hisilicon.com> wrote:
>>
>>
>> ? 2016/10/18 23:58, Rob Herring ??:
>>> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>>>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>>>> Generator) module generates clock and reset signals used
>>>> by other module blocks on SoC.
>>>>
>>>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>>>> ---
>>>>  .../devicetree/bindings/clock/hisi-crg.txt         |  50 ++++
>>>>  drivers/clk/hisilicon/Kconfig                      |   8 +
>>>>  drivers/clk/hisilicon/Makefile                     |   1 +
>>>>  drivers/clk/hisilicon/crg-hi3516cv300.c            | 330 +++++++++++++++++++++
>>>>  drivers/clk/hisilicon/crg.h                        |  34 +++
>>>>  include/dt-bindings/clock/hi3516cv300-clock.h      |  48 +++
>>>>  6 files changed, 471 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>>  create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>>>>  create mode 100644 drivers/clk/hisilicon/crg.h
>>>>  create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> new file mode 100644
>>>> index 0000000..cc60b3d
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> @@ -0,0 +1,50 @@
>>>> +* HiSilicon Clock and Reset Generator(CRG)
>>>
>>> Seems kind of generic given there's already various HiSi clock bindings
>>> documented.
>>>
>>>> +
>>>> +The CRG module provides clock and reset signals to various
>>>> +modules within the SoC.
>>>> +
>>>> +This binding uses the following bindings:
>>>> +    Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>> +    Documentation/devicetree/bindings/reset/reset.txt
>>>> +
>>>> +Required Properties:
>>>> +
>>>> +- compatible: should be one of the following.
>>>> +  - "hisilicon,hi3516cv300-crg"
>>>> +  - "hisilicon,hi3516cv300-sysctrl"
>>>> +  - "hisilicon,hi3519-crg"
>>>
>>> There is already a binding for this. Please merge them.
>>>
>> Hi Rob,
>>
>> Pan Wen and I work together. There's really a same file included in the patch
>> https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
>> But that patch has not been acked. This binding file will be merged if that
>> patch is accepted first. Could you give me more comments on that patch or
>> help me to ack it?  Thank you very much.
> 
> If I haven't commented, then likely it was not sent to the DT list.
Hi,

I'm pretty sure that the patch was sent to the DT list devicetree at vger.kernel.org.
You had asked a question about "hi3798cv200-sysctrl" and I replied (https://lkml.org/lkml/2016/10/10/517).
I'm waiting for your new comments. If there's some misunderstatnding, please let me know.

Thanks,
Jiancheng

> 
> Rob
> 
> .
> 

^ permalink raw reply

* [PATCH v2] ARM: dts: rockchip: temporarily remove emmc hs200 speed from rk3288-veyron-speedy.
From: Vagrant Cascadian @ 2016-10-19  3:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476824417.1031.9.camel@paulk.fr>

On 2016-10-18, Paul Kocialkowski wrote:
> Le mardi 18 octobre 2016 ? 11:21 +0200, Heiko St?bner a ?crit?:
>> Am Sonntag, 16. Oktober 2016, 21:49:43 schrieb Paul Kocialkowski:
>> > 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

This is similar behavior to my veyron-speedy. Here are several boot logs
>From running 4.8.0-rc7, with some failures and some successes:

  https://cascadia.aikidev.net/~vagrant/veyron-speedy/


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

Well, that makes things more complicated.


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

Mine looks similar, although reporting as mmc0:

  [    3.166550] mmcblk0: mmc0: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.

FWIW, I'm using a veyron-speedy with 4GB of ram, not sure what other
information might be useful to distinguish between different models.

On the bottom of the case, it claims to be a C201P. Near the serial,
it's marked as C201PA-DS02-LG.


live well,
  vagrant
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/643b245b/attachment.sig>

^ permalink raw reply

* [PATCH v2] ARM: bcm2835: Add names for the Raspberry Pi GPIO lines
From: Eric Anholt @ 2016-10-19  3:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPoCmYJC1TebBrspD_=mTETULSjg9or5a0Yda8p945y6ZWL99Q@mail.gmail.com>

Gottfried Haider <gottfried.haider@gmail.com> writes:

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

I added the pin numbers because it was a consistent response to the
first version.  I do think the GPIO numbers without pin numbers would be
the most clear.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/cae67ff7/attachment.sig>

^ permalink raw reply

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

On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  .../devicetree/bindings/mtd/oxnas-nand.txt         |  24 ++++

Acked-by: Rob Herring <robh@kernel.org>

>  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

^ permalink raw reply

* [PATCH v2 0/8] crypto: ARM/arm64 - big endian fixes
From: Herbert Xu @ 2016-10-19  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu9wuXnrq77a3Zk0GnHgnkpURh=EegwgP+vAwMC=rdm3qA@mail.gmail.com>

On Tue, Oct 18, 2016 at 01:14:38PM +0100, Ard Biesheuvel wrote:
> On 18 October 2016 at 12:49, Catalin Marinas <catalin.marinas@arm.com> wrote:
> > On Tue, Oct 11, 2016 at 07:15:12PM +0100, Ard Biesheuvel wrote:
> >> As it turns out, none of the accelerated crypto routines under arch/arm64/crypto
> >> currently work, or have ever worked correctly when built for big endian. So this
> >> series fixes all of them. This v2 now includes a similar fix for 32-bit ARM as
> >> well, and an additional fix for XTS which escaped my attention before.
> >>
> >> Each of these patches carries a fixes tag, and could be backported to stable.
> >> However, for patches #1 and #5, the fixes tag denotes the oldest commit that the
> >> fix is compatible with, not the patch that introduced the algorithm.
> >
> > I think for future reference, the Fixes tag should denote the commit
> > that introduced the issue. An explicit Cc: stable tag would state how
> > far back it should be applied.
> >
> 
> OK, that sounds reasonable.
> 
> >> Ard Biesheuvel (8):
> >>   crypto: arm64/aes-ce - fix for big endian
> >>   crypto: arm64/ghash-ce - fix for big endian
> >>   crypto: arm64/sha1-ce - fix for big endian
> >>   crypto: arm64/sha2-ce - fix for big endian
> >>   crypto: arm64/aes-ccm-ce: fix for big endian
> >>   crypto: arm64/aes-neon - fix for big endian
> >>   crypto: arm64/aes-xts-ce: fix for big endian
> >>   crypto: arm/aes-ce - fix for big endian
> >
> > The changes look fine to me but I can't claim I fully understand these
> > algorithms. FWIW:
> >
> > Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> >
> > (Will may pick them up for 4.9-rcX)
> 
> Thanks, although I was kind of expecting Herbert to pick these up,
> given that #8 affects ARM not arm64.
> 
> But if you (or Will) can pick up #1 to #7, that is also fine, then I
> can drop #8 into rmk's patch database.

I was planning merging these for 4.10.  But I'm fine with them
going through the arm tree.  Let me know what you guys want to
do.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [PATCH] mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading
From: Sebastian Reichel @ 2016-10-19  2:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019025154.rmw56aoh27wbrene@earth>

Hi,

On Wed, Oct 19, 2016 at 04:51:55AM +0200, Sebastian Reichel wrote:
> > diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
> > index b1b8658..d35a5fe 100644
> > --- a/drivers/mfd/axp20x-i2c.c
> > +++ b/drivers/mfd/axp20x-i2c.c
> > @@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
> >  };
> >  MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
> >  
> > -/*
> > - * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> > - */
> >  static const struct i2c_device_id axp20x_i2c_id[] = {
> > +	{ "axp152", 0 },
> > +	{ "axp202", 0 },
> > +	{ "axp209", 0 },
> > +	{ "axp221", 0 },
> >  	{ },
> >  };
> >  MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
> 
> Thanks, queued.

My mistake. It should obviously go through mfd. So take this instead:

Acked-By: Sebastian Reichel <sre@kernel.org>

-- Sebastian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161019/aa748c19/attachment.sig>

^ permalink raw reply

* [PATCH] mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading
From: Sebastian Reichel @ 2016-10-19  2:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161005155112.13774-2-hdegoede@redhat.com>

Hi,

On Wed, Oct 05, 2016 at 05:51:12PM +0200, Hans de Goede wrote:
> The i2c subsys does not load modules by compatible, only by
> i2c-id, with e.g. a modalias of: "i2c:axp209".
> 
> Populate the axp20x_i2c_id[] table with supported ids, so that
> module auto-loading will work.
> 
> Reported-by: Dennis Gilmore <dennis@ausil.us>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  drivers/mfd/axp20x-i2c.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
> index b1b8658..d35a5fe 100644
> --- a/drivers/mfd/axp20x-i2c.c
> +++ b/drivers/mfd/axp20x-i2c.c
> @@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
>  };
>  MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
>  
> -/*
> - * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> - */
>  static const struct i2c_device_id axp20x_i2c_id[] = {
> +	{ "axp152", 0 },
> +	{ "axp202", 0 },
> +	{ "axp209", 0 },
> +	{ "axp221", 0 },
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);

Thanks, queued.

-- Sebastian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161019/fe135abd/attachment.sig>

^ permalink raw reply

* [PATCH v2] arm64: kernel: numa: fix ACPI boot cpu numa node mapping
From: Leizhen (ThunderTown) @ 2016-10-19  2:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <728ef882-b1ee-9518-d291-ee475e9006eb@linaro.org>



On 2016/10/18 16:39, Hanjun Guo wrote:
> On 2016/10/17 22:56, Lorenzo Pieralisi wrote:
>> Commit 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must
>> bind to node0") removed the numa cpu<->node mapping restriction whereby
>> logical cpu 0 always corresponds to numa node 0; removing the
>> restriction was correct, in that it does not really exist in practice
>> but the commit only updated the early mapping of logical cpu 0 to its
>> real numa node for the DT boot path, missing the ACPI one, leading to
>> boot failures on ACPI systems owing to missing cpu<->node map for
>> logical cpu 0.
>>
>> Fix the issue by updating the ACPI boot path with code that carries out
>> the early cpu<->node mapping also for the boot cpu (ie cpu 0), mirroring
>> what is currently done in the DT boot path.
>>
>> Fixes: 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must bind to node0")
>> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Tested-by: Laszlo Ersek <lersek@redhat.com>
>> Reported-by: Laszlo Ersek <lersek@redhat.com>
>> Cc: Will Deacon <will.deacon@arm.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Hanjun Guo <hanjun.guo@linaro.org>
> 
> Thanks for the quick response and fix,
> 
> Acked-by: Hanjun Guo <hanjun.guo@linaro.org>
> 
> By the way, I got another boot failure [1] when we have multi
> NUMA nodes system with some memory-less nodes (only one node
> have memory), we are looking into it now, this patch needs
> to be merged first.
You should apply my numa MEMORYLESS patches first, because the two patches have not been upstreamed yet.
I just tested it base on 4.9-rc1 for dt numa, it worked well. I will connect you to check what's wrong on ACPI numa.

> 
> Thanks
> Hanjun
> 
> [1]: boot failure log:
> [    0.000000] NUMA: Adding memblock [0x0 - 0x3fffffff] on node 0
> [    0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x00000000-0x3fffffff]
> [    0.000000] NUMA: Adding memblock [0x1400000000 - 0x17ffffffff] on node 1
> [    0.000000] ACPI: SRAT: Node 1 PXM 1 [mem 0x1400000000-0x17ffffffff]
> [    0.000000] NUMA: Adding memblock [0x1000000000 - 0x13ffffffff] on node 0
> [    0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x1000000000-0x13ffffffff]
> [    0.000000] NUMA: Initmem setup node 0 [mem 0x00000000-0x13fbffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x13fbffe500-0x13fbffffff]
> [    0.000000] NUMA: Initmem setup node 1 [mem 0x1400000000-0x17fbffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfec500-0x17fbfedfff]
> [    0.000000] NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfeaa00-0x17fbfec4ff]
> [    0.000000] NUMA: NODE_DATA(2) on node 1
> [    0.000000] NUMA: Initmem setup node 3 [mem 0x00000000-0xffffffffffffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfe8f00-0x17fbfea9ff]
> [    0.000000] NUMA: NODE_DATA(3) on node 1
> [    0.000000] Zone ranges:
> [    0.000000]   DMA      [mem 0x0000000000000000-0x00000000ffffffff]
> [    0.000000]   Normal   [mem 0x0000000100000000-0x00000017fbffffff]
> [    0.000000] Movable zone start for each node
> [    0.000000] Early memory node ranges
> [    0.000000]   node   0: [mem 0x0000000000000000-0x0000000000024fff]
> [    0.000000]   node   0: [mem 0x0000000000026000-0x00000000319dffff]
> [    0.000000]   node   0: [mem 0x00000000319e0000-0x0000000031a4ffff]
> [    0.000000]   node   0: [mem 0x0000000031a50000-0x0000000031b2ffff]
> [    0.000000]   node   0: [mem 0x0000000031b30000-0x0000000031b3ffff]
> [    0.000000]   node   0: [mem 0x0000000031b40000-0x0000000039baffff]
> [    0.000000]   node   0: [mem 0x0000000039bb0000-0x000000003a143fff]
> [    0.000000]   node   0: [mem 0x000000003a144000-0x000000003f12ffff]
> [    0.000000]   node   0: [mem 0x000000003f130000-0x000000003f15ffff]
> [    0.000000]   node   0: [mem 0x000000003f160000-0x000000003fbfffff]
> [    0.000000]   node   0: [mem 0x0000001040000000-0x00000013fbffffff]
> [    0.000000]   node   1: [mem 0x0000001400000000-0x00000017fbffffff]
> [    0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x00000013fbffffff]
> [    0.000000] Initmem setup node 1 [mem 0x0000001400000000-0x00000017fbffffff]
> [    0.000000] Could not find start_pfn for node 2
> [    0.000000] Initmem setup node 2 [mem 0x0000000000000000-0x0000000000000000]
> [    0.000000] Could not find start_pfn for node 3
> [    0.000000] Initmem setup node 3 [mem 0x0000000000000000-0x0000000000000000]
> [    0.000000] psci: probing for conduit method from ACPI.
> [    0.000000] ------------[ cut here ]------------
> [    0.000000] kernel BUG at mm/percpu.c:1916!
> [    0.000000] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
> [    0.000000] Modules linked in:
> [    0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 4.9.0-rc1-00083-g3dd62e5 #680
> [    0.000000] Hardware name: Hisilicon Hi1616 Evaluation Board (DT)
> [    0.000000] task: ffff000008d5e980 task.stack: ffff000008d50000
> [    0.000000] PC is at pcpu_embed_first_chunk+0x464/0x754
> [    0.000000] LR is at pcpu_embed_first_chunk+0x3f8/0x754
> [    0.000000] pc : [<ffff000008c65af0>] lr : [<ffff000008c65a84>] pstate: 200000c5
> [    0.000000] sp : ffff000008d53e90
> [    0.000000] x29: ffff000008d53e90 [    0.000000] x28: 0000000000000000
> [    0.000000]
> [    0.000000] x27: ffff000008d55e50 [    0.000000] x26: 0000000000000042
> [    0.000000]
> [    0.000000] x25: ffff000008d55d28 [    0.000000] x24: 0000000000000046
> [    0.000000]
> [    0.000000] x23: 0000000000000040 [    0.000000] x22: ffff8017fbfcff00
> [    0.000000]
> [    0.000000] x21: ffff000008ca6e20 [    0.000000] x20: ffff8017fbfd0518
> [    0.000000]
> [    0.000000] x19: 0000000000000042 [    0.000000] x18: ffff000008e3fb60
> [    0.000000]
> [    0.000000] x17: 000000000000001b [    0.000000] x16: 000000000000000b
> [    0.000000]
> [    0.000000] x15: 0000001400000000 [    0.000000] x14: 0000000000000004
> [    0.000000]
> [    0.000000] x13: 0000000000000000 [    0.000000] x12: 0000000000000069
> [    0.000000]
> [    0.000000] x11: 00000017fbffff00 [    0.000000] x10: 0000000000000004
> [    0.000000]
> [    0.000000] x9 : 0000000000000000 [    0.000000] x8 : ffff8017fbfd0f00
> [    0.000000]
> [    0.000000] x7 : 0000000000000000 [    0.000000] x6 : 0000000000000000
> [    0.000000]
> [    0.000000] x5 : 0000000000000000 [    0.000000] x4 : 000000000000003f
> [    0.000000]
> [    0.000000] x3 : 0000000000000040 [    0.000000] x2 : 0000000000000040
> [    0.000000]
> [    0.000000] x1 : 0000000000000001 [    0.000000] x0 : ffff000008ca7328
> [    0.000000]
> [    0.000000]
> [    0.000000] Process swapper (pid: 0, stack limit = 0xffff000008d50020)
> [    0.000000] Stack: (0xffff000008d53e90 to 0xffff000008d54000)
> [    0.000000] 3e80:                                   ffff000008d53f60 ffff000008c5616c
> [    0.000000] 3ea0: ffff000008ca5a08 ffff000008e2a000 ffff000008e2a000 ffff000008d55000
> [    0.000000] 3ec0: ffff000008ca5a08 ffff8017fbfffe80 0000000000000168 000000003c96a518
> [    0.000000] 3ee0: 000000003c971b98 0000000000c50018 ffff000008d53f60 ffff000008c56078
> [    0.000000] 3f00: ffff000008d1f000 ffff000008d14000 0000000000007480 0000000000002000
> [    0.000000] 3f20: ffff000008c560b0 0000000000001000 ffff000008d55e50 ffff000008d55d28
> [    0.000000] 3f40: ffff000008ca6000 0000000000000040 0000000000000001 0000000000000040
> [    0.000000] 3f60: ffff000008d53fa0 ffff000008c508d4 ffff000008ca5a08 ffff000008e2a000
> [    0.000000] 3f80: ffff000008e2a000 ffff000008d55000 ffff000008ca5a08 ffff000008c508d0
> [    0.000000] 3fa0: ffff000008d53ff0 ffff000008c501d8 000000003c94fa98 000000001e400000
> [    0.000000] 3fc0: 000000001e400000 000000025497ba19 0000000000000000 000000003f198a08
> [    0.000000] 3fe0: 0000000000000000 ffff000008ca5a08 0000000000000000 00000000008a325c
> [    0.000000] Call trace:
> [    0.000000] Exception stack(0xffff000008d53cc0 to 0xffff000008d53df0)
> [    0.000000] 3cc0: 0000000000000042 0001000000000000 ffff000008d53e90 ffff000008c65af0
> [    0.000000] 3ce0: ffff000008d53d30 ffff0000081aa024 0000000000000001 0000000000001000
> [    0.000000] 3d00: ffff000008d53d30 ffff0000081aa034 0000000000000001 0000000000001000
> [    0.000000] 3d20: 00000017fbfcff00 0000000000000004 ffff000008d53d90 ffff0000081aa2c8
> [    0.000000] 3d40: 00000017fbfcff00 0000000000001000 0000000000000000 0000000000000000
> [    0.000000] 3d60: ffff000008ca7328 0000000000000001 0000000000000040 0000000000000040
> [    0.000000] 3d80: 000000000000003f 0000000000000000 0000000000000000 0000000000000000
> [    0.000000] 3da0: ffff8017fbfd0f00 0000000000000000 0000000000000004 00000017fbffff00
> [    0.000000] 3dc0: 0000000000000069 0000000000000000 0000000000000004 0000001400000000
> [    0.000000] 3de0: 000000000000000b 000000000000001b
> [    0.000000] [<ffff000008c65af0>] pcpu_embed_first_chunk+0x464/0x754
> [    0.000000] [<ffff000008c5616c>] setup_per_cpu_areas+0x3c/0xcc
> [    0.000000] [<ffff000008c508d4>] start_kernel+0x10c/0x398
> [    0.000000] [<ffff000008c501d8>] __primary_switched+0x5c/0x64
> [    0.000000] Code: 0b000318 17ffffd8 6b17031f 54000080 (d4210000)
> [    0.000000] ---[ end trace 0000000000000000 ]---
> [    0.000000] Kernel panic - not syncing: Attempted to kill the idle task!
> [    0.000000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task!
> 
> 
> .
> 

^ permalink raw reply

* [v12, 0/8] Fix eSDHC host version register bug
From: Y.B. Lu @ 2016-10-19  2:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPDyKFoit0sTPpfi2=AHcdZsDwOJxbBX68O-1jBFL=5JN0m6_w@mail.gmail.com>

+ Greg

Hi Greg,

I submitted this patchset for a MMC bug fix, and introduce the below patch which needs your ACK.
> > Arnd Bergmann (1):
> >   base: soc: introduce soc_device_match() interface
https://patchwork.kernel.org/patch/9342913/

Could you help to review it and give some comments or ACK.
Thank you very much.



Best regards,
Yangbo Lu


> -----Original Message-----
> From: Ulf Hansson [mailto:ulf.hansson at linaro.org]
> Sent: Tuesday, October 18, 2016 6:48 PM
> To: Y.B. Lu
> Cc: linux-mmc; Scott Wood; Arnd Bergmann; linuxppc-dev at lists.ozlabs.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; linux-clk; linux-i2c at vger.kernel.org;
> iommu at lists.linux-foundation.org; netdev at vger.kernel.org; Mark Rutland;
> Rob Herring; Russell King; Jochen Friedrich; Joerg Roedel; Claudiu Manoil;
> Bhupesh Sharma; Qiang Zhao; Kumar Gala; Santosh Shilimkar; Leo Li; X.B.
> Xie; M.H. Lian
> Subject: Re: [v12, 0/8] Fix eSDHC host version register bug
> 
> On 21 September 2016 at 08:57, Yangbo Lu <yangbo.lu@nxp.com> wrote:
> > This patchset is used to fix a host version register bug in the
> > T4240-R1.0-R2.0 eSDHC controller. To match the SoC version and
> > revision, 10 previous version patchsets had tried many methods but all
> of them were rejected by reviewers.
> > Such as
> >         - dts compatible method
> >         - syscon method
> >         - ifdef PPC method
> >         - GUTS driver getting SVR method Anrd suggested a
> > soc_device_match method in v10, and this is the only available method
> > left now. This v11 patchset introduces the soc_device_match interface
> > in soc driver.
> >
> > The first six patches of Yangbo are to add the GUTS driver. This is
> > used to register a soc device which contain soc version and revision
> information.
> > The other two patches introduce the soc_device_match method in soc
> > driver and apply it on esdhc driver to fix this bug.
> >
> > Arnd Bergmann (1):
> >   base: soc: introduce soc_device_match() interface
> >
> > Yangbo Lu (7):
> >   dt: bindings: update Freescale DCFG compatible
> >   ARM64: dts: ls2080a: add device configuration node
> >   dt: bindings: move guts devicetree doc out of powerpc directory
> >   powerpc/fsl: move mpc85xx.h to include/linux/fsl
> >   soc: fsl: add GUTS driver for QorIQ platforms
> >   MAINTAINERS: add entry for Freescale SoC drivers
> >   mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
> >
> >  Documentation/devicetree/bindings/arm/fsl.txt      |   6 +-
> >  .../bindings/{powerpc => soc}/fsl/guts.txt         |   3 +
> >  MAINTAINERS                                        |  11 +-
> >  arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |   6 +
> >  arch/powerpc/kernel/cpu_setup_fsl_booke.S          |   2 +-
> >  arch/powerpc/sysdev/fsl_pci.c                      |   2 +-
> >  drivers/base/Kconfig                               |   1 +
> >  drivers/base/soc.c                                 |  66 ++++++
> >  drivers/clk/clk-qoriq.c                            |   3 +-
> >  drivers/i2c/busses/i2c-mpc.c                       |   2 +-
> >  drivers/iommu/fsl_pamu.c                           |   3 +-
> >  drivers/mmc/host/Kconfig                           |   1 +
> >  drivers/mmc/host/sdhci-of-esdhc.c                  |  20 ++
> >  drivers/net/ethernet/freescale/gianfar.c           |   2 +-
> >  drivers/soc/Kconfig                                |   2 +-
> >  drivers/soc/fsl/Kconfig                            |  19 ++
> >  drivers/soc/fsl/Makefile                           |   1 +
> >  drivers/soc/fsl/guts.c                             | 257
> +++++++++++++++++++++
> >  include/linux/fsl/guts.h                           | 125 ++++++----
> >  .../asm/mpc85xx.h => include/linux/fsl/svr.h       |   4 +-
> >  include/linux/sys_soc.h                            |   3 +
> >  21 files changed, 478 insertions(+), 61 deletions(-)  rename
> > Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
> > create mode 100644 drivers/soc/fsl/Kconfig  create mode 100644
> > drivers/soc/fsl/guts.c  rename arch/powerpc/include/asm/mpc85xx.h =>
> > include/linux/fsl/svr.h (97%)
> >
> > --
> > 2.1.0.27.g96db324
> >
> 
> This looks good to me! I am not sure which tree you want this to be
> picked up through, but unless no other volunteers I can take it through
> my mmc tree.
> 
> Although, before considering to apply, I need an ack from Scott/Arnd for
> the guts driver in patch 5/8 and I need an ack from Greg for patch 7/8,
> where the soc_device_match() interface is added (seems like you didn't
> add him on cc/to).
> 
> Kind regards
> Uffe

^ permalink raw reply

* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Rob Herring @ 2016-10-19  2:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <7ce2e35b-19e1-9493-90a7-15b321fee2cc@hisilicon.com>

On Tue, Oct 18, 2016 at 9:38 PM, Jiancheng Xue
<xuejiancheng@hisilicon.com> wrote:
>
>
> ? 2016/10/18 23:58, Rob Herring ??:
>> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>>> Generator) module generates clock and reset signals used
>>> by other module blocks on SoC.
>>>
>>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>>> ---
>>>  .../devicetree/bindings/clock/hisi-crg.txt         |  50 ++++
>>>  drivers/clk/hisilicon/Kconfig                      |   8 +
>>>  drivers/clk/hisilicon/Makefile                     |   1 +
>>>  drivers/clk/hisilicon/crg-hi3516cv300.c            | 330 +++++++++++++++++++++
>>>  drivers/clk/hisilicon/crg.h                        |  34 +++
>>>  include/dt-bindings/clock/hi3516cv300-clock.h      |  48 +++
>>>  6 files changed, 471 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>  create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>>>  create mode 100644 drivers/clk/hisilicon/crg.h
>>>  create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>>
>>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>> new file mode 100644
>>> index 0000000..cc60b3d
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>> @@ -0,0 +1,50 @@
>>> +* HiSilicon Clock and Reset Generator(CRG)
>>
>> Seems kind of generic given there's already various HiSi clock bindings
>> documented.
>>
>>> +
>>> +The CRG module provides clock and reset signals to various
>>> +modules within the SoC.
>>> +
>>> +This binding uses the following bindings:
>>> +    Documentation/devicetree/bindings/clock/clock-bindings.txt
>>> +    Documentation/devicetree/bindings/reset/reset.txt
>>> +
>>> +Required Properties:
>>> +
>>> +- compatible: should be one of the following.
>>> +  - "hisilicon,hi3516cv300-crg"
>>> +  - "hisilicon,hi3516cv300-sysctrl"
>>> +  - "hisilicon,hi3519-crg"
>>
>> There is already a binding for this. Please merge them.
>>
> Hi Rob,
>
> Pan Wen and I work together. There's really a same file included in the patch
> https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
> But that patch has not been acked. This binding file will be merged if that
> patch is accepted first. Could you give me more comments on that patch or
> help me to ack it?  Thank you very much.

If I haven't commented, then likely it was not sent to the DT list.

Rob

^ permalink raw reply

* [v12, 0/8] Fix eSDHC host version register bug
From: Y.B. Lu @ 2016-10-19  2:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPDyKFoit0sTPpfi2=AHcdZsDwOJxbBX68O-1jBFL=5JN0m6_w@mail.gmail.com>

> -----Original Message-----
> From: Ulf Hansson [mailto:ulf.hansson at linaro.org]
> Sent: Tuesday, October 18, 2016 6:48 PM
> To: Y.B. Lu
> Cc: linux-mmc; Scott Wood; Arnd Bergmann; linuxppc-dev at lists.ozlabs.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; linux-clk; linux-i2c at vger.kernel.org;
> iommu at lists.linux-foundation.org; netdev at vger.kernel.org; Mark Rutland;
> Rob Herring; Russell King; Jochen Friedrich; Joerg Roedel; Claudiu Manoil;
> Bhupesh Sharma; Qiang Zhao; Kumar Gala; Santosh Shilimkar; Leo Li; X.B.
> Xie; M.H. Lian
> Subject: Re: [v12, 0/8] Fix eSDHC host version register bug
> 
> On 21 September 2016 at 08:57, Yangbo Lu <yangbo.lu@nxp.com> wrote:
> > This patchset is used to fix a host version register bug in the
> > T4240-R1.0-R2.0 eSDHC controller. To match the SoC version and
> > revision, 10 previous version patchsets had tried many methods but all
> of them were rejected by reviewers.
> > Such as
> >         - dts compatible method
> >         - syscon method
> >         - ifdef PPC method
> >         - GUTS driver getting SVR method Anrd suggested a
> > soc_device_match method in v10, and this is the only available method
> > left now. This v11 patchset introduces the soc_device_match interface
> > in soc driver.
> >
> > The first six patches of Yangbo are to add the GUTS driver. This is
> > used to register a soc device which contain soc version and revision
> information.
> > The other two patches introduce the soc_device_match method in soc
> > driver and apply it on esdhc driver to fix this bug.
> >
> > Arnd Bergmann (1):
> >   base: soc: introduce soc_device_match() interface
> >
> > Yangbo Lu (7):
> >   dt: bindings: update Freescale DCFG compatible
> >   ARM64: dts: ls2080a: add device configuration node
> >   dt: bindings: move guts devicetree doc out of powerpc directory
> >   powerpc/fsl: move mpc85xx.h to include/linux/fsl
> >   soc: fsl: add GUTS driver for QorIQ platforms
> >   MAINTAINERS: add entry for Freescale SoC drivers
> >   mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
> >
> >  Documentation/devicetree/bindings/arm/fsl.txt      |   6 +-
> >  .../bindings/{powerpc => soc}/fsl/guts.txt         |   3 +
> >  MAINTAINERS                                        |  11 +-
> >  arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |   6 +
> >  arch/powerpc/kernel/cpu_setup_fsl_booke.S          |   2 +-
> >  arch/powerpc/sysdev/fsl_pci.c                      |   2 +-
> >  drivers/base/Kconfig                               |   1 +
> >  drivers/base/soc.c                                 |  66 ++++++
> >  drivers/clk/clk-qoriq.c                            |   3 +-
> >  drivers/i2c/busses/i2c-mpc.c                       |   2 +-
> >  drivers/iommu/fsl_pamu.c                           |   3 +-
> >  drivers/mmc/host/Kconfig                           |   1 +
> >  drivers/mmc/host/sdhci-of-esdhc.c                  |  20 ++
> >  drivers/net/ethernet/freescale/gianfar.c           |   2 +-
> >  drivers/soc/Kconfig                                |   2 +-
> >  drivers/soc/fsl/Kconfig                            |  19 ++
> >  drivers/soc/fsl/Makefile                           |   1 +
> >  drivers/soc/fsl/guts.c                             | 257
> +++++++++++++++++++++
> >  include/linux/fsl/guts.h                           | 125 ++++++----
> >  .../asm/mpc85xx.h => include/linux/fsl/svr.h       |   4 +-
> >  include/linux/sys_soc.h                            |   3 +
> >  21 files changed, 478 insertions(+), 61 deletions(-)  rename
> > Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
> > create mode 100644 drivers/soc/fsl/Kconfig  create mode 100644
> > drivers/soc/fsl/guts.c  rename arch/powerpc/include/asm/mpc85xx.h =>
> > include/linux/fsl/svr.h (97%)
> >
> > --
> > 2.1.0.27.g96db324
> >
> 
> This looks good to me! I am not sure which tree you want this to be
> picked up through, but unless no other volunteers I can take it through
> my mmc tree.
> 
> Although, before considering to apply, I need an ack from Scott/Arnd for
> the guts driver in patch 5/8 and I need an ack from Greg for patch 7/8,
> where the soc_device_match() interface is added (seems like you didn't
> add him on cc/to).
> 

[Lu Yangbo-B47093] Thanks a lot for your clarifying, Uffe.
This patchset was based on mmc tree, and needed your picking up.
But I think it needs to be rebased now since I saw qbman driver was in drivers/soc/fsl/ now.
I will do that after collecting others' ACKs or comments.

Hi Scott and Arnd,
Could I get your ACTs if there're no other changes needed?
Thanks a lot.

> Kind regards
> Uffe

^ permalink raw reply

* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Jiancheng Xue @ 2016-10-19  2:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161018155835.qyoffwznacdac46y@rob-hp-laptop>



? 2016/10/18 23:58, Rob Herring ??:
> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>> Generator) module generates clock and reset signals used
>> by other module blocks on SoC.
>>
>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>> ---
>>  .../devicetree/bindings/clock/hisi-crg.txt         |  50 ++++
>>  drivers/clk/hisilicon/Kconfig                      |   8 +
>>  drivers/clk/hisilicon/Makefile                     |   1 +
>>  drivers/clk/hisilicon/crg-hi3516cv300.c            | 330 +++++++++++++++++++++
>>  drivers/clk/hisilicon/crg.h                        |  34 +++
>>  include/dt-bindings/clock/hi3516cv300-clock.h      |  48 +++
>>  6 files changed, 471 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>>  create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>>  create mode 100644 drivers/clk/hisilicon/crg.h
>>  create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>
>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>> new file mode 100644
>> index 0000000..cc60b3d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>> @@ -0,0 +1,50 @@
>> +* HiSilicon Clock and Reset Generator(CRG)
> 
> Seems kind of generic given there's already various HiSi clock bindings 
> documented.
> 
>> +
>> +The CRG module provides clock and reset signals to various
>> +modules within the SoC.
>> +
>> +This binding uses the following bindings:
>> +    Documentation/devicetree/bindings/clock/clock-bindings.txt
>> +    Documentation/devicetree/bindings/reset/reset.txt
>> +
>> +Required Properties:
>> +
>> +- compatible: should be one of the following.
>> +  - "hisilicon,hi3516cv300-crg"
>> +  - "hisilicon,hi3516cv300-sysctrl"
>> +  - "hisilicon,hi3519-crg"
> 
> There is already a binding for this. Please merge them.
> 
Hi Rob,

Pan Wen and I work together. There's really a same file included in the patch
https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
But that patch has not been acked. This binding file will be merged if that
patch is accepted first. Could you give me more comments on that patch or
help me to ack it?  Thank you very much.

Regards,
Jiancheng


>> +  - "hisilicon,hi3798cv200-crg"
>> +  - "hisilicon,hi3798cv200-sysctrl"
>> +
>> +- reg: physical base address of the controller and length of memory mapped
>> +  region.
>> +
>> +- #clock-cells: should be 1.
>> +
>> +Each clock is assigned an identifier and client nodes use this identifier
>> +to specify the clock which they consume.
>> +
>> +All these identifier could be found in <dt-bindings/clock/hi3519-clock.h>.
>> +
>> +- #reset-cells: should be 2.
>> +
>> +A reset signal can be controlled by writing a bit register in the CRG module.
>> +The reset specifier consists of two cells. The first cell represents the
>> +register offset relative to the base address. The second cell represents the
>> +bit index in the register.
>> +
>> +Example: CRG nodes
>> +CRG: clock-reset-controller at 12010000 {
>> +	compatible = "hisilicon,hi3519-crg";
>> +	reg = <0x12010000 0x10000>;
>> +	#clock-cells = <1>;
>> +	#reset-cells = <2>;
>> +};
>> +
>> +Example: consumer nodes
>> +i2c0: i2c at 12110000 {
>> +	compatible = "hisilicon,hi3519-i2c";
>> +	reg = <0x12110000 0x1000>;
>> +	clocks = <&CRG HI3519_I2C0_RST>;
>> +	resets = <&CRG 0xe4 0>;
>> +};
> 
> .
> 

^ permalink raw reply

* [PATCH v7, 8/8] arm64: dts: mediatek: add USB3 DRD driver
From: Chunfeng Yun @ 2016-10-19  2:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476844107-31087-1-git-send-email-chunfeng.yun@mediatek.com>

USB3 DRD driver is added for MT8173-EVB, and xHCI driver
becomes its subnode

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173-evb.dts |   63 ++++++++++++++++++++++-----
 arch/arm64/boot/dts/mediatek/mt8173.dtsi    |   29 +++++++++---
 2 files changed, 74 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 2a7f731..0ecaad4 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -34,15 +34,6 @@
 
 	chosen { };
 
-	usb_p1_vbus: regulator at 0 {
-		compatible = "regulator-fixed";
-		regulator-name = "usb_vbus";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-		gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
 	connector {
 		compatible = "hdmi-connector";
 		label = "hdmi";
@@ -54,6 +45,29 @@
 			};
 		};
 	};
+
+	extcon_usb: extcon_iddig {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&pio 16 GPIO_ACTIVE_HIGH>;
+	};
+
+	usb_p1_vbus: regulator at 0 {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p0_vbus: regulator at 1 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 9 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
 };
 
 &cec {
@@ -243,6 +257,20 @@
 			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
 		};
 	};
+
+	usb_id_pins_float: usb_iddig_pull_up {
+		pins_iddig {
+			pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
+			bias-pull-up;
+		};
+	};
+
+	usb_id_pins_ground: usb_iddig_pull_down {
+		pins_iddig {
+			pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
+			bias-pull-down;
+		};
+	};
 };
 
 &pwm0 {
@@ -469,12 +497,25 @@
 	status = "okay";
 };
 
+&ssusb {
+	vusb33-supply = <&mt6397_vusb_reg>;
+	vbus-supply = <&usb_p0_vbus>;
+	extcon = <&extcon_usb>;
+	dr_mode = "otg";
+	mediatek,enable-wakeup;
+	pinctrl-names = "default", "id_float", "id_ground";
+	pinctrl-0 = <&usb_id_pins_float>;
+	pinctrl-1 = <&usb_id_pins_float>;
+	pinctrl-2 = <&usb_id_pins_ground>;
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
 
-&usb30 {
+&usb_host {
 	vusb33-supply = <&mt6397_vusb_reg>;
 	vbus-supply = <&usb_p1_vbus>;
-	mediatek,wakeup-src = <1>;
+	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 1c71e25..c2d588c 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -707,11 +707,14 @@
 			status = "disabled";
 		};
 
-		usb30: usb at 11270000 {
-			compatible = "mediatek,mt8173-xhci";
-			reg = <0 0x11270000 0 0x1000>,
+		ssusb: usb at 11271000 {
+			compatible = "mediatek,mt8173-mtu3";
+			reg = <0 0x11271000 0 0x3000>,
 			      <0 0x11280700 0 0x0100>;
-			interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+			reg-names = "mac", "ippc";
+			interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>;
+			phys = <&phy_port0 PHY_TYPE_USB3>,
+			       <&phy_port1 PHY_TYPE_USB2>;
 			power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
 			clocks = <&topckgen CLK_TOP_USB30_SEL>,
 				 <&pericfg CLK_PERI_USB0>,
@@ -719,10 +722,22 @@
 			clock-names = "sys_ck",
 				      "wakeup_deb_p0",
 				      "wakeup_deb_p1";
-			phys = <&phy_port0 PHY_TYPE_USB3>,
-			       <&phy_port1 PHY_TYPE_USB2>;
 			mediatek,syscon-wakeup = <&pericfg>;
-			status = "okay";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			status = "disabled";
+
+			usb_host: xhci at 11270000 {
+				compatible = "mediatek,mt8173-xhci";
+				reg = <0 0x11270000 0 0x1000>;
+				reg-names = "mac";
+				interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+				power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+				clocks = <&topckgen CLK_TOP_USB30_SEL>;
+				clock-names = "sys_ck";
+				status = "disabled";
+			};
 		};
 
 		u3phy: usb-phy at 11290000 {
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v7, 7/8] usb: mtu3: dual-role mode support
From: Chunfeng Yun @ 2016-10-19  2:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476844107-31087-1-git-send-email-chunfeng.yun@mediatek.com>

support dual-role mode; there are two ways to switch between
host and device modes, one is by idpin, another is by debugfs
which depends on user input.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
 drivers/usb/mtu3/Kconfig       |   15 +-
 drivers/usb/mtu3/Makefile      |   11 +-
 drivers/usb/mtu3/mtu3.h        |   34 +++-
 drivers/usb/mtu3/mtu3_core.c   |   14 +-
 drivers/usb/mtu3/mtu3_dr.c     |  379 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/mtu3/mtu3_dr.h     |   27 ++-
 drivers/usb/mtu3/mtu3_gadget.c |    6 +-
 drivers/usb/mtu3/mtu3_host.c   |    6 +
 drivers/usb/mtu3/mtu3_plat.c   |   86 ++++++++-
 9 files changed, 557 insertions(+), 21 deletions(-)
 create mode 100644 drivers/usb/mtu3/mtu3_dr.c

diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
index 59e3f6f..25cd619 100644
--- a/drivers/usb/mtu3/Kconfig
+++ b/drivers/usb/mtu3/Kconfig
@@ -2,7 +2,7 @@
 
 config USB_MTU3
 	tristate "MediaTek USB3 Dual Role controller"
-	depends on (USB || USB_GADGET) && HAS_DMA
+	depends on EXTCON && (USB || USB_GADGET) && HAS_DMA
 	depends on ARCH_MEDIATEK || COMPILE_TEST
 	select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD
 	help
@@ -19,6 +19,7 @@ config USB_MTU3
 if USB_MTU3
 choice
 	bool "MTU3 Mode Selection"
+	default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET)
 	default USB_MTU3_HOST if (USB && !USB_GADGET)
 	default USB_MTU3_GADGET if (!USB && USB_GADGET)
 
@@ -36,6 +37,18 @@ config USB_MTU3_GADGET
 	  Select this when you want to use MTU3 in gadget mode only,
 	  thereby the host feature will be regressed.
 
+config USB_MTU3_DUAL_ROLE
+	bool "Dual Role mode"
+	depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3))
+	help
+	  This is the default mode of working of MTU3 controller where
+	  both host and gadget features are enabled.
+
 endchoice
 
+config USB_MTU3_DEBUG
+	bool "Enable Debugging Messages"
+	help
+	  Say Y here to enable debugging messages in the MTU3 Driver.
+
 endif
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
index 41e45e9..60e0fff 100644
--- a/drivers/usb/mtu3/Makefile
+++ b/drivers/usb/mtu3/Makefile
@@ -1,11 +1,18 @@
+
+ccflags-$(CONFIG_USB_MTU3_DEBUG)	+= -DDEBUG
+
 obj-$(CONFIG_USB_MTU3)	+= mtu3.o
 
 mtu3-y	:= mtu3_plat.o
 
-ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST)),)
+ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
 	mtu3-y	+= mtu3_host.o
 endif
 
-ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET)),)
+ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
 	mtu3-y	+= mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o
 endif
+
+ifneq ($(CONFIG_USB_MTU3_DUAL_ROLE),)
+	mtu3-y	+= mtu3_dr.o
+endif
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index a7c0ce8..ba9df71 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -21,6 +21,7 @@
 
 #include <linux/device.h>
 #include <linux/dmapool.h>
+#include <linux/extcon.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/phy/phy.h>
@@ -172,15 +173,44 @@ struct mtu3_gpd_ring {
 	struct qmu_gpd *enqueue;
 	struct qmu_gpd *dequeue;
 };
+
+/**
+* @vbus: vbus 5V used by host mode
+* @edev: external connector used to detect vbus and iddig changes
+* @vbus_nb: notifier for vbus detection
+* @vbus_nb: notifier for iddig(idpin) detection
+* @extcon_reg_dwork: delay work for extcon notifier register, waiting for
+*		xHCI driver initialization, it's necessary for system bootup
+*		as device.
+* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
+* @id_*: used to maually switch between host and device modes by idpin
+* @manual_drd_enabled: it's true when supports dual-role device by debugfs
+*		to switch host/device modes depending on user input.
+*/
+struct otg_switch_mtk {
+	struct regulator *vbus;
+	struct extcon_dev *edev;
+	struct notifier_block vbus_nb;
+	struct notifier_block id_nb;
+	struct delayed_work extcon_reg_dwork;
+	bool is_u3_drd;
+	/* dual-role switch by debugfs */
+	struct pinctrl *id_pinctrl;
+	struct pinctrl_state *id_float;
+	struct pinctrl_state *id_ground;
+	bool manual_drd_enabled;
+};
+
 /**
  * @mac_base: register base address of device MAC, exclude xHCI's
- * @ippc_base: register base address of ip port controller interface (IPPC)
+ * @ippc_base: register base address of IP Power and Clock interface (IPPC)
  * @vusb33: usb3.3V shared by device/host IP
  * @sys_clk: system clock of mtu3, shared by device/host IP
  * @dr_mode: works in which mode:
  *		host only, device only or dual-role mode
  * @u2_ports: number of usb2.0 host ports
  * @u3_ports: number of usb3.0 host ports
+ * @dbgfs_root: only used when supports manual dual-role switch via debugfs
  * @wakeup_en: it's true when supports remote wakeup in host mode
  * @wk_deb_p0: port0's wakeup debounce clock
  * @wk_deb_p1: it's optional, and depends on port1 is supported or not
@@ -196,10 +226,12 @@ struct ssusb_mtk {
 	struct regulator *vusb33;
 	struct clk *sys_clk;
 	/* otg */
+	struct otg_switch_mtk otg_switch;
 	enum usb_dr_mode dr_mode;
 	bool is_host;
 	int u2_ports;
 	int u3_ports;
+	struct dentry *dbgfs_root;
 	/* usb wakeup for host mode */
 	bool wakeup_en;
 	struct clk *wk_deb_p0;
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 2eef972..520e55a 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -150,7 +150,6 @@ static void mtu3_intr_disable(struct mtu3 *mtu)
 
 	/* Disable level 1 interrupts */
 	mtu3_writel(mbase, U3D_LV1IECR, ~0x0);
-
 	/* Disable endpoint interrupts */
 	mtu3_writel(mbase, U3D_EPIECR, ~0x0);
 }
@@ -161,13 +160,10 @@ static void mtu3_intr_status_clear(struct mtu3 *mtu)
 
 	/* Clear EP0 and Tx/Rx EPn interrupts status */
 	mtu3_writel(mbase, U3D_EPISR, ~0x0);
-
 	/* Clear U2 USB common interrupts status */
 	mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);
-
 	/* Clear U3 LTSSM interrupts status */
 	mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);
-
 	/* Clear speed change interrupt status */
 	mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
 }
@@ -268,7 +264,6 @@ void mtu3_start(struct mtu3 *mtu)
 
 	/* Initialize the default interrupts */
 	mtu3_intr_enable(mtu);
-
 	mtu->is_active = 1;
 
 	if (mtu->softconnect)
@@ -516,7 +511,6 @@ static int mtu3_mem_alloc(struct mtu3 *mtu)
 	mtu->out_eps = &ep_array[mtu->num_eps];
 	/* ep0 uses in_eps[0], out_eps[0] is reserved */
 	mtu->ep0 = mtu->in_eps;
-
 	mtu->ep0->mtu = mtu;
 	mtu->ep0->epnum = 0;
 
@@ -560,6 +554,7 @@ static void mtu3_set_speed(struct mtu3 *mtu)
 		/* HS/FS detected by HW */
 		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
 	}
+
 	dev_info(mtu->dev, "max_speed: %s\n",
 		usb_speed_string(mtu->max_speed));
 }
@@ -586,13 +581,10 @@ static void mtu3_regs_init(struct mtu3 *mtu)
 
 	/* delay about 0.1us from detecting reset to send chirp-K */
 	mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
-
 	/* U2/U3 detected by HW */
 	mtu3_writel(mbase, U3D_DEVICE_CONF, 0);
-
 	/* enable QMU 16B checksum */
 	mtu3_setbits(mbase, U3D_QCR0, QMU_CS16B_EN);
-
 	/* vbus detected by HW */
 	mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
 }
@@ -838,6 +830,10 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
 		goto gadget_err;
 	}
 
+	/* init as host mode, power down device IP for power saving */
+	if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
+		mtu3_stop(mtu);
+
 	dev_dbg(dev, " %s() done...\n", __func__);
 
 	return 0;
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
new file mode 100644
index 0000000..1a8987e
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -0,0 +1,379 @@
+/*
+ * mtu3_dr.c - dual role switch and host glue layer
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+#define USB2_PORT 2
+#define USB3_PORT 3
+
+enum mtu3_vbus_id_state {
+	MTU3_ID_FLOAT = 1,
+	MTU3_ID_GROUND,
+	MTU3_VBUS_OFF,
+	MTU3_VBUS_VALID,
+};
+
+static void toggle_opstate(struct ssusb_mtk *ssusb)
+{
+	if (!ssusb->otg_switch.is_u3_drd) {
+		mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION);
+		mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN);
+	}
+}
+
+/* only port0 supports dual-role mode */
+static int ssusb_port0_switch(struct ssusb_mtk *ssusb,
+	int version, bool tohost)
+{
+	void __iomem *ibase = ssusb->ippc_base;
+	u32 value;
+
+	dev_dbg(ssusb->dev, "%s (switch u%d port0 to %s)\n", __func__,
+		version, tohost ? "host" : "device");
+
+	if (version == USB2_PORT) {
+		/* 1. power off and disable u2 port0 */
+		value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
+		value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
+		mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
+
+		/* 2. power on, enable u2 port0 and select its mode */
+		value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
+		value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
+		value = tohost ? (value | SSUSB_U2_PORT_HOST_SEL) :
+			(value & (~SSUSB_U2_PORT_HOST_SEL));
+		mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
+	} else {
+		/* 1. power off and disable u3 port0 */
+		value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
+		value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
+		mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
+
+		/* 2. power on, enable u3 port0 and select its mode */
+		value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
+		value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
+		value = tohost ? (value | SSUSB_U3_PORT_HOST_SEL) :
+			(value & (~SSUSB_U3_PORT_HOST_SEL));
+		mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
+	}
+
+	return 0;
+}
+
+static void switch_port_to_host(struct ssusb_mtk *ssusb)
+{
+	u32 check_clk = 0;
+
+	dev_dbg(ssusb->dev, "%s\n", __func__);
+
+	ssusb_port0_switch(ssusb, USB2_PORT, true);
+
+	if (ssusb->otg_switch.is_u3_drd) {
+		ssusb_port0_switch(ssusb, USB3_PORT, true);
+		check_clk = SSUSB_U3_MAC_RST_B_STS;
+	}
+
+	ssusb_check_clocks(ssusb, check_clk);
+
+	/* after all clocks are stable */
+	toggle_opstate(ssusb);
+}
+
+static void switch_port_to_device(struct ssusb_mtk *ssusb)
+{
+	u32 check_clk = 0;
+
+	dev_dbg(ssusb->dev, "%s\n", __func__);
+
+	ssusb_port0_switch(ssusb, USB2_PORT, false);
+
+	if (ssusb->otg_switch.is_u3_drd) {
+		ssusb_port0_switch(ssusb, USB3_PORT, false);
+		check_clk = SSUSB_U3_MAC_RST_B_STS;
+	}
+
+	ssusb_check_clocks(ssusb, check_clk);
+}
+
+int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
+{
+	struct ssusb_mtk *ssusb =
+		container_of(otg_sx, struct ssusb_mtk, otg_switch);
+	struct regulator *vbus = otg_sx->vbus;
+	int ret;
+
+	/* vbus is optional */
+	if (!vbus)
+		return 0;
+
+	dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, is_on ? "on" : "off");
+
+	if (is_on) {
+		ret = regulator_enable(vbus);
+		if (ret) {
+			dev_err(ssusb->dev, "vbus regulator enable failed\n");
+			return ret;
+		}
+	} else {
+		regulator_disable(vbus);
+	}
+
+	return 0;
+}
+
+/*
+ * switch to host: -> MTU3_VBUS_OFF --> MTU3_ID_GROUND
+ * switch to device: -> MTU3_ID_FLOAT --> MTU3_VBUS_VALID
+ */
+static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
+	enum mtu3_vbus_id_state status)
+{
+	struct ssusb_mtk *ssusb =
+		container_of(otg_sx, struct ssusb_mtk, otg_switch);
+	struct mtu3 *mtu = ssusb->u3d;
+
+	dev_dbg(ssusb->dev, "mailbox state(%d)\n", status);
+
+	switch (status) {
+	case MTU3_ID_GROUND:
+		switch_port_to_host(ssusb);
+		ssusb_set_vbus(otg_sx, 1);
+		ssusb->is_host = true;
+		break;
+	case MTU3_ID_FLOAT:
+		ssusb->is_host = false;
+		ssusb_set_vbus(otg_sx, 0);
+		switch_port_to_device(ssusb);
+		break;
+	case MTU3_VBUS_OFF:
+		mtu3_stop(mtu);
+		pm_relax(ssusb->dev);
+		break;
+	case MTU3_VBUS_VALID:
+		/* avoid suspend when works as device */
+		pm_stay_awake(ssusb->dev);
+		mtu3_start(mtu);
+		break;
+	default:
+		dev_err(ssusb->dev, "invalid state\n");
+	}
+}
+
+static int ssusb_id_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct otg_switch_mtk *otg_sx =
+		container_of(nb, struct otg_switch_mtk, id_nb);
+
+	if (event)
+		ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
+	else
+		ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+
+	return NOTIFY_DONE;
+}
+
+static int ssusb_vbus_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct otg_switch_mtk *otg_sx =
+		container_of(nb, struct otg_switch_mtk, vbus_nb);
+
+	if (event)
+		ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+	else
+		ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+
+	return NOTIFY_DONE;
+}
+
+static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
+{
+	struct ssusb_mtk *ssusb =
+		container_of(otg_sx, struct ssusb_mtk, otg_switch);
+	struct extcon_dev *edev = otg_sx->edev;
+	int ret;
+
+	/* extcon is optional */
+	if (!edev)
+		return 0;
+
+	otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
+	ret = extcon_register_notifier(edev, EXTCON_USB,
+					&otg_sx->vbus_nb);
+	if (ret < 0)
+		dev_err(ssusb->dev, "failed to register notifier for USB\n");
+
+	otg_sx->id_nb.notifier_call = ssusb_id_notifier;
+	ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+					&otg_sx->id_nb);
+	if (ret < 0)
+		dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
+
+	dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
+		extcon_get_cable_state_(edev, EXTCON_USB),
+		extcon_get_cable_state_(edev, EXTCON_USB_HOST));
+
+	/* default as host, switch to device mode if needed */
+	if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == false)
+		ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+	if (extcon_get_cable_state_(edev, EXTCON_USB) == true)
+		ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+
+	return 0;
+}
+
+static void extcon_register_dwork(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct otg_switch_mtk *otg_sx =
+	    container_of(dwork, struct otg_switch_mtk, extcon_reg_dwork);
+
+	ssusb_extcon_register(otg_sx);
+}
+
+/*
+ * We provide an interface via debugfs to switch between host and device modes
+ * depending on user input.
+ * This is useful in special cases, such as uses TYPE-A receptacle but also
+ * wants to support dual-role mode.
+ * It generates cable state changes by pulling up/down IDPIN and
+ * notifies driver to switch mode by "extcon-usb-gpio".
+ * NOTE: when use MICRO receptacle, should not enable this interface.
+ */
+static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
+{
+	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+	if (to_host)
+		pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
+	else
+		pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
+}
+
+
+static int ssusb_mode_show(struct seq_file *sf, void *unused)
+{
+	struct ssusb_mtk *ssusb = sf->private;
+
+	seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
+		ssusb->is_host ? "host" : "device",
+		ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
+
+	return 0;
+}
+
+static int ssusb_mode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ssusb_mode_show, inode->i_private);
+}
+
+static ssize_t ssusb_mode_write(struct file *file,
+	const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file *sf = file->private_data;
+	struct ssusb_mtk *ssusb = sf->private;
+	char buf[16];
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
+		ssusb_mode_manual_switch(ssusb, 1);
+	} else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
+		ssusb_mode_manual_switch(ssusb, 0);
+	} else {
+		dev_err(ssusb->dev, "wrong or duplicated setting\n");
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static const struct file_operations ssusb_mode_fops = {
+	.open = ssusb_mode_open,
+	.write = ssusb_mode_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void ssusb_debugfs_init(struct ssusb_mtk *ssusb)
+{
+	struct dentry *root;
+	struct dentry *file;
+
+	root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
+	if (IS_ERR_OR_NULL(root)) {
+		if (!root)
+			dev_err(ssusb->dev, "create debugfs root failed\n");
+		return;
+	}
+	ssusb->dbgfs_root = root;
+
+	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+			ssusb, &ssusb_mode_fops);
+	if (!file)
+		dev_dbg(ssusb->dev, "create debugfs mode failed\n");
+}
+
+static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
+{
+	debugfs_remove_recursive(ssusb->dbgfs_root);
+}
+
+int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
+{
+	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+	INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
+
+	if (otg_sx->manual_drd_enabled)
+		ssusb_debugfs_init(ssusb);
+
+	/* It is enough to delay 1s for waiting for host initialization */
+	schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
+
+	return 0;
+}
+
+void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
+{
+	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+	cancel_delayed_work(&otg_sx->extcon_reg_dwork);
+
+	if (otg_sx->edev) {
+		extcon_unregister_notifier(otg_sx->edev,
+			EXTCON_USB, &otg_sx->vbus_nb);
+		extcon_unregister_notifier(otg_sx->edev,
+			EXTCON_USB_HOST, &otg_sx->id_nb);
+	}
+
+	if (otg_sx->manual_drd_enabled)
+		ssusb_debugfs_exit(ssusb);
+}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
index 07066f4..9b228b5 100644
--- a/drivers/usb/mtu3/mtu3_dr.h
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -19,7 +19,7 @@
 #ifndef _MTU3_DR_H_
 #define _MTU3_DR_H_
 
-#if IS_ENABLED(CONFIG_USB_MTU3_HOST)
+#if IS_ENABLED(CONFIG_USB_MTU3_HOST) || IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
 
 int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn);
 void ssusb_host_exit(struct ssusb_mtk *ssusb);
@@ -69,7 +69,7 @@ static inline void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
 #endif
 
 
-#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
+#if IS_ENABLED(CONFIG_USB_MTU3_GADGET) || IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
 int ssusb_gadget_init(struct ssusb_mtk *ssusb);
 void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
 #else
@@ -82,4 +82,27 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
 {}
 #endif
 
+
+#if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
+int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
+void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
+int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
+
+#else
+
+static inline int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
+{
+	return 0;
+}
+
+static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
+{}
+
+static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
+{
+	return 0;
+}
+
+#endif
+
 #endif		/* _MTU3_DR_H_ */
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 84f3fe1..9dd2441 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -522,7 +522,8 @@ static int mtu3_gadget_start(struct usb_gadget *gadget,
 	mtu->softconnect = 0;
 	mtu->gadget_driver = driver;
 
-	mtu3_start(mtu);
+	if (mtu->ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
+		mtu3_start(mtu);
 
 	spin_unlock_irqrestore(&mtu->lock, flags);
 
@@ -575,7 +576,8 @@ static int mtu3_gadget_stop(struct usb_gadget *g)
 	stop_activity(mtu);
 	mtu->gadget_driver = NULL;
 
-	mtu3_stop(mtu);
+	if (mtu->ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
+		mtu3_stop(mtu);
 
 	spin_unlock_irqrestore(&mtu->lock, flags);
 
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index 361d6d8..cd4d010 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -230,10 +230,16 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
 	 * if support OTG, gadget driver will switch port0 to device mode
 	 */
 	ssusb_host_enable(ssusb);
+
+	/* if port0 supports dual-role, works as host mode by default */
+	ssusb_set_vbus(&ssusb->otg_switch, 1);
 }
 
 static void ssusb_host_cleanup(struct ssusb_mtk *ssusb)
 {
+	if (ssusb->is_host)
+		ssusb_set_vbus(&ssusb->otg_switch, 0);
+
 	ssusb_host_disable(ssusb, false);
 }
 
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index facb76c..7833678 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -142,13 +142,10 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
 
 phy_err:
 	ssusb_phy_exit(ssusb);
-
 phy_init_err:
 	clk_disable_unprepare(ssusb->sys_clk);
-
 clk_err:
 	regulator_disable(ssusb->vusb33);
-
 vusb33_err:
 
 	return ret;
@@ -170,10 +167,39 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
 	mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
 }
 
+static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
+{
+	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+	otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
+	if (IS_ERR(otg_sx->id_pinctrl)) {
+		dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
+		return PTR_ERR(otg_sx->id_pinctrl);
+	}
+
+	otg_sx->id_float =
+		pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
+	if (IS_ERR(otg_sx->id_float)) {
+		dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
+		return PTR_ERR(otg_sx->id_float);
+	}
+
+	otg_sx->id_ground =
+		pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
+	if (IS_ERR(otg_sx->id_ground)) {
+		dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
+		return PTR_ERR(otg_sx->id_ground);
+	}
+
+	return 0;
+}
+
 static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
 {
 	struct device_node *node = pdev->dev.of_node;
+	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
 	struct device *dev = &pdev->dev;
+	struct regulator *vbus;
 	struct resource *res;
 	int i;
 	int ret;
@@ -230,6 +256,37 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
 	if (ret)
 		return ret;
 
+	if (ssusb->dr_mode != USB_DR_MODE_OTG)
+		return 0;
+
+	/* if dual-role mode is supported */
+	vbus = devm_regulator_get(&pdev->dev, "vbus");
+	if (IS_ERR(vbus)) {
+		dev_err(dev, "failed to get vbus\n");
+		return PTR_ERR(vbus);
+	}
+	otg_sx->vbus = vbus;
+
+	otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
+	otg_sx->manual_drd_enabled =
+		of_property_read_bool(node, "enable-manual-drd");
+
+	if (of_property_read_bool(node, "extcon")) {
+		otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
+		if (IS_ERR(otg_sx->edev)) {
+			dev_err(ssusb->dev, "couldn't get extcon device\n");
+			return -EPROBE_DEFER;
+		}
+		if (otg_sx->manual_drd_enabled) {
+			ret = get_iddig_pinctrl(ssusb);
+			if (ret)
+				return ret;
+		}
+	}
+
+	dev_info(dev, "dr_mode: %d, is_u3_dr: %d\n",
+		ssusb->dr_mode, otg_sx->is_u3_drd);
+
 	return 0;
 }
 
@@ -292,6 +349,21 @@ static int mtu3_probe(struct platform_device *pdev)
 			goto comm_exit;
 		}
 		break;
+	case USB_DR_MODE_OTG:
+		ret = ssusb_gadget_init(ssusb);
+		if (ret) {
+			dev_err(dev, "failed to initialize gadget\n");
+			goto comm_exit;
+		}
+
+		ret = ssusb_host_init(ssusb, node);
+		if (ret) {
+			dev_err(dev, "failed to initialize host\n");
+			goto gadget_exit;
+		}
+
+		ssusb_otg_switch_init(ssusb);
+		break;
 	default:
 		dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode);
 		ret = -EINVAL;
@@ -300,9 +372,10 @@ static int mtu3_probe(struct platform_device *pdev)
 
 	return 0;
 
+gadget_exit:
+	ssusb_gadget_exit(ssusb);
 comm_exit:
 	ssusb_rscs_exit(ssusb);
-
 comm_init_err:
 	pm_runtime_put_sync(dev);
 	pm_runtime_disable(dev);
@@ -321,6 +394,11 @@ static int mtu3_remove(struct platform_device *pdev)
 	case USB_DR_MODE_HOST:
 		ssusb_host_exit(ssusb);
 		break;
+	case USB_DR_MODE_OTG:
+		ssusb_otg_switch_exit(ssusb);
+		ssusb_gadget_exit(ssusb);
+		ssusb_host_exit(ssusb);
+		break;
 	default:
 		return -EINVAL;
 	}
-- 
1.7.9.5

^ 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