[U-Boot] [PATCH v4 00/21] Add support for 96boards Dragonboard410C board

Hi All,
This is next last version of Dragonboard410c series ;) It should apply cleanly to latest master (080c499d).
I welcome all improvement ideas but please bear in mind I will probably implement them after this series is merged.
Very little updates this time: - Added ACKs - Added MMU configuration (I did that in mach code as it's shared for all devices using this SoC) - Fixed missing renames (ehci-fsl.h -> ehci-ci.h) - sorry for that! - Moved CONFIG_OF_LIBFDT to defconfig and cleaned it up with savedefconfig
As for testing - I've manually tested it on dragonboard and did buildman test for all ARM targets (~540 boards, hopefuly I catched all that are affected by this series in any way).
@Marek, Joe, Tom: thanks for the input!
Regards, Mateusz
V3 cover contents:
Sorry for longer delay, but I had too many things to do recently.
As always - for "simplicity" this series is available on my github: https://github.com/hallor/u-boot/tree/dragonboard-for-mainline-v3
There are almost no changes + one bugfix: - Bugfix: small rework of serial driver - U-Boot was interrupted when no serial converter was attached. - Updated dragonboard readme.txt with info on how to stop @ fastboot - Added SPMI entries into test.dts (so automatic DM tests would not fail) - Added Tested-by and Reviewed-by Simon (from v2 comments) - Rebased to recent master - Fixed warnings in ASIX and ULPI code - Added comments to head.S, little updates suggested by Daniel
@Simon: Thanks for the tests of v2!
Daniel Glöckner, Tom Rini, Jagan Teki: Thanks for the comments!
V2 cover contents:
This is updated series. 99% of review changes are applied, specific changes are (as always) include in each patch.
You can find this series on my github (if anyone just want to try it - that branch has also wait_for_bit applied): https://github.com/hallor/u-boot/tree/dragonboard-for-mainline-v2
I did target tests on Dragonboard410c, and build tested platforms that may be affected by ULPI changes.
@Simon: I decided not to rewrite pm8916_gpio for now, but for sake of "cleannes" moved offending bindings to separate file (and they are now properly childs of pm8916_gpio). I will update it during rework of SoC gpio driver (I will have to create proper pinmux/pinctrl drivers to get rid of Little Kernel eventually).
This series still needs wait_for_bit series that is not included (yet).
V1 cover contents:
I finally managed to cleanup RFC for submission. I've included changes in each patch, there is a bit of them, but all are needed :)
This series requires wait_for_bit patch that I send few days ago: https://patchwork.ozlabs.org/patch/561185/
RFC cover contents: http://lists.denx.de/pipermail/u-boot/2015-December/237365.html
Changes in v4: - Add Ack from Marek - Add Ack from Marek - Add Ack from Marek - Add Ack from Marek and Joe - Add missing renames (arch/* and board/*) - Add sysmap for apq8016 (required to enable MMU) - Move CONFIG_OF_LIBFDT to defconfig and cleaned it up with savedefconfig
Changes in v3: - Add msm_serial_fetch that tries to fetch characters from FIFO - Decrease no of characters requested in RX transaction - Try to fetch characters from FIFO when tstc()/pending() is called - New patch - New patch - New patch - Updated test.dts to include SPMI like sandbox.dts does - readme: Added info on how to enter fastboot mode and that dtbTool is also part of skales. Added more explanation on image generation. - head: Add comment why it's needed, drop MZ EFI signature that makes no sense on this particular SoC, fix confusing entry point name (+update .lds file)
Changes in v2: - Added newline before return... (globally) - Renamed p to priv (priv data) - it required some rewrapping - Added Reviewed-by - Reordered includes (again) - Added newlines between returns - Fixed error handling in msm_gpio_probe - Added reviewed-by - Add reviewed-by - Add Reviewed-by (sjg) - Add better (any) descriptions for Kconfig items. - New patch, independent of the rest - Should compile cleanly on all affected platforms - Is orthogonal to series (i.e. if get's NAK will not break rest of series) - Add acked-by - Add reviewed-by - Add Acked-by - Use PORT_... macro to write to portsc - Remove extra whitespace in probe() - Add acked-by - Use proper entry order in Kconfig - Rename CONFIG_DM_SPMI -> CONFIG_SPMI - Fix header ordering - Add reviewed-by - Rename CONFIG_DM_SPMI -> CONFIG_SPMI - Rename r -> regs, p -> priv - Add reviewed-by - Update binding doc (drop unused bindig) - Rename DM_SPMI -> SPMI - Rename p -> priv (in write/read) - Fix header ordering (again) - Add reviewed-by - Add reviewed-by - Reordered Kconfig & Makefile (to keep alphabetical ordering) - Added link to dt binding @ help - Add Reviewed-by - Rename DM_SPMI -> SPMI - Make MND divider comments more compact :) - p -> priv - Add reviewed-by - Reordered Kconfig to keep alphabetical order - Renamed reset_sandbox -> msm_reset (typo in reset.c) - Renamed CONFIG_DM_SPMI -> CONFIG_SPMI - Removed extra enter in dragonboard file - Added ULPI* to defconfig - Added MAINTAINERS to board - Cleaned up config file - use distro defaults/environment: - Dropped multiple CONFIG_CMD* and other CONFIG_* - Added distro env/config - Dropped old boot commands - Split dts - pm8916_gpio entries are taken directly from Linux Dragonboard dts; Add handles for u-boot in -uboot.dtsi; They will be removed once gpio drivers are converted to pinctrl. - Renamed some pmic nodes, fixed dragonboard.c to find them properly. - Added header and converted comments to c98-style in head.S - Print error if pmic gpio node is not found. - New patch
Changes in v1: - Added (better) help to KConfig - Added dt binding documentation - Fixed include ordering - Reworked msm_serial_getc - Added error handling to msm_uart_clk_init (that is ignored later for now) - Dropped unneeded DM_FLAG_PRE_RELOC - Added dt binding documentation - Added help to KConfig - Use clrsetbits() to switch direction - Fixed include order - Added #defines for registers/register fields - Added secondary compatible string - Added commit message - Added DT binding documentation - Added Kconfig help - Reordered includes - Dropped redundant fields from msm_sdhc - Cleaned up clock init code (+ added error handling) - Dropped mdelay - use wait_for_bit instead in reset code - Added missing newline after declarations - Added error handling if "reg" is missing - Converted base address to pointer - No changes, just added Acked-by, Reviewed-by - Reordered header files - Removed braces around constant - Added more verbose help to KConfig - Added ULPI dependency to Kconfig - Drop register #defines - use ehci-ci.h instead - Create fixed ulpi viewport for device - Use setbits/clearbits where possible - Use wait_for_bit to reset controller - Add dt binding documents - Reorder includes - Add read/write arguments documentation - add binding documentation and better Kconfig help - Changed a bit mapping - Change include order - Use clrsetbits* where possible - Add one more supported dts id - Handle missing fields in dt properly - Added dt bindings - Reoder includes - Replaced extract_* macros with ordinary shift/mask - Added error checking and whitespaces in probe - Add binding doc - Fixed inlcude ordering - Merged direction_input and direction_output functions - gpio_get: use switch instead of stacked if - use pmic_clrsetbits - add possibility to change prwkey bank name - Handle invalid bindings - Sanity HW check (i.e. check type/subtype registers) - Fix include order - Cleanup defines (added spaces for readibility) - Base address is integer to avoid casting - Use setbits_* family where possible - Drop unneded comments, added newlines where needed - Check return value of dev_get_addr - Add binding for apq8016 - Cleaned up divider calculation - Drop most of gpio.h (only empty file is needed) - Add better help for dragonboard - Move static structures to board_prepare_usb - Add DM_SPMI to defconfig
Mateusz Kulikowski (21): serial: Add support for Qualcomm serial port gpio: Add support for Qualcomm gpio controller mmc: Add support for Qualcomm SDHCI controller ehci-hcd: Add init_after_reset usb: ulpi: Add Kconfig options for ULPI Migrate CONFIG_ULPI* to Kconfig usb: ulpi: Fix viewport_addr type usb: ulpi: Fix compile warning in read/write on 64-bit machines. eth: asix88179: Print packet length properly usb: Rename ehci-fsl.h to ehci-ci.h usb: ehci-ci: Add missing registers. ehci-ci.h: drop generic USBCMD fields ehci: Add support for Qualcomm EHCI drivers: Add SPMI bus uclass spmi: Add sandbox test driver drivers: spmi: Add support for Qualcomm SPMI bus driver pmic: Add support for Qualcomm PM8916 PMIC gpio: Add support for Qualcomm PM8916 gpios arm: Add support for Qualcomm Snapdragon family board: Add Qualcomm Dragonboard 410C support Add myself as Snapdragon and SPMI maintainer
MAINTAINERS | 11 + arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/dts/Makefile | 2 + arch/arm/dts/dragonboard410c-uboot.dtsi | 28 ++ arch/arm/dts/dragonboard410c.dts | 148 ++++++++++ arch/arm/mach-snapdragon/Kconfig | 26 ++ arch/arm/mach-snapdragon/Makefile | 9 + arch/arm/mach-snapdragon/clock-apq8016.c | 262 ++++++++++++++++++ arch/arm/mach-snapdragon/include/mach/gpio.h | 9 + .../mach-snapdragon/include/mach/sysmap-apq8016.h | 14 + arch/arm/mach-snapdragon/reset.c | 40 +++ arch/arm/mach-snapdragon/sysmap-apq8016.c | 30 ++ arch/powerpc/cpu/mpc83xx/cpu_init.c | 2 +- arch/sandbox/dts/sandbox.dts | 20 ++ arch/sandbox/dts/test.dts | 20 ++ board/boundary/nitrogen6x/nitrogen6x.c | 2 +- board/denx/m53evk/m53evk.c | 2 +- board/freescale/mx51evk/mx51evk.c | 2 +- board/freescale/mx6slevk/mx6slevk.c | 2 +- board/freescale/mx6sxsabreauto/mx6sxsabreauto.c | 2 +- board/freescale/mx6sxsabresd/mx6sxsabresd.c | 2 +- board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c | 2 +- board/freescale/mx7dsabresd/mx7dsabresd.c | 2 +- board/qualcomm/dragonboard410c/Kconfig | 15 + board/qualcomm/dragonboard410c/MAINTAINERS | 6 + board/qualcomm/dragonboard410c/Makefile | 8 + board/qualcomm/dragonboard410c/dragonboard410c.c | 131 +++++++++ board/qualcomm/dragonboard410c/head.S | 34 +++ board/qualcomm/dragonboard410c/readme.txt | 71 +++++ board/qualcomm/dragonboard410c/u-boot.lds | 90 ++++++ board/solidrun/mx6cuboxi/mx6cuboxi.c | 2 +- configs/colibri_t20_defconfig | 2 + configs/dragonboard410c_defconfig | 26 ++ configs/harmony_defconfig | 2 + configs/mcx_defconfig | 3 + configs/mt_ventoux_defconfig | 3 + configs/sandbox_defconfig | 4 + configs/twister_defconfig | 3 + configs/zynq_picozed_defconfig | 2 + configs/zynq_zc702_defconfig | 2 + configs/zynq_zc706_defconfig | 2 + configs/zynq_zed_defconfig | 2 + configs/zynq_zybo_defconfig | 2 + doc/device-tree-bindings/gpio/gpio-msm.txt | 22 ++ doc/device-tree-bindings/gpio/pm8916_gpio.txt | 48 ++++ doc/device-tree-bindings/mmc/msm_sdhci.txt | 25 ++ doc/device-tree-bindings/pmic/pm8916.txt | 18 ++ doc/device-tree-bindings/serial/msm-serial.txt | 6 + doc/device-tree-bindings/spmi/spmi-msm.txt | 26 ++ doc/device-tree-bindings/spmi/spmi-sandbox.txt | 31 +++ doc/device-tree-bindings/usb/ehci-msm.txt | 10 + doc/git-mailrc | 3 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/gpio/Kconfig | 24 ++ drivers/gpio/Makefile | 2 + drivers/gpio/msm_gpio.c | 135 +++++++++ drivers/gpio/pm8916_gpio.c | 302 +++++++++++++++++++++ drivers/mmc/Kconfig | 9 + drivers/mmc/Makefile | 1 + drivers/mmc/msm_sdhci.c | 180 ++++++++++++ drivers/power/pmic/Kconfig | 16 ++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pm8916.c | 96 +++++++ drivers/serial/Kconfig | 8 + drivers/serial/Makefile | 1 + drivers/serial/serial_msm.c | 217 +++++++++++++++ drivers/spmi/Kconfig | 23 ++ drivers/spmi/Makefile | 9 + drivers/spmi/spmi-msm.c | 189 +++++++++++++ drivers/spmi/spmi-sandbox.c | 157 +++++++++++ drivers/spmi/spmi-uclass.c | 48 ++++ drivers/usb/Kconfig | 2 + drivers/usb/eth/asix88179.c | 2 +- drivers/usb/host/Kconfig | 11 + drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-fsl.c | 2 +- drivers/usb/host/ehci-hcd.c | 6 + drivers/usb/host/ehci-mpc512x.c | 6 +- drivers/usb/host/ehci-msm.c | 178 ++++++++++++ drivers/usb/host/ehci-mx5.c | 2 +- drivers/usb/host/ehci-mx6.c | 2 +- drivers/usb/host/ehci-mxc.c | 2 +- drivers/usb/host/ehci-vf.c | 2 +- drivers/usb/host/ehci-zynq.c | 2 +- drivers/usb/host/ehci.h | 1 + drivers/usb/ulpi/Kconfig | 33 +++ drivers/usb/ulpi/ulpi-viewport.c | 5 +- include/configs/colibri_t20.h | 3 +- include/configs/dragonboard410c.h | 150 ++++++++++ include/configs/harmony.h | 2 - include/configs/mcx.h | 2 - include/configs/tam3517-common.h | 2 - include/configs/zynq-common.h | 2 - include/dm/uclass-id.h | 1 + include/spmi/spmi.h | 47 ++++ include/usb/{ehci-fsl.h => ehci-ci.h} | 16 +- include/usb/ulpi.h | 4 +- test/dm/Makefile | 1 + test/dm/spmi.c | 115 ++++++++ 101 files changed, 3231 insertions(+), 41 deletions(-) create mode 100644 arch/arm/dts/dragonboard410c-uboot.dtsi create mode 100644 arch/arm/dts/dragonboard410c.dts create mode 100644 arch/arm/mach-snapdragon/Kconfig create mode 100644 arch/arm/mach-snapdragon/Makefile create mode 100644 arch/arm/mach-snapdragon/clock-apq8016.c create mode 100644 arch/arm/mach-snapdragon/include/mach/gpio.h create mode 100644 arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h create mode 100644 arch/arm/mach-snapdragon/reset.c create mode 100644 arch/arm/mach-snapdragon/sysmap-apq8016.c create mode 100644 board/qualcomm/dragonboard410c/Kconfig create mode 100644 board/qualcomm/dragonboard410c/MAINTAINERS create mode 100644 board/qualcomm/dragonboard410c/Makefile create mode 100644 board/qualcomm/dragonboard410c/dragonboard410c.c create mode 100644 board/qualcomm/dragonboard410c/head.S create mode 100644 board/qualcomm/dragonboard410c/readme.txt create mode 100644 board/qualcomm/dragonboard410c/u-boot.lds create mode 100644 configs/dragonboard410c_defconfig create mode 100644 doc/device-tree-bindings/gpio/gpio-msm.txt create mode 100644 doc/device-tree-bindings/gpio/pm8916_gpio.txt create mode 100644 doc/device-tree-bindings/mmc/msm_sdhci.txt create mode 100644 doc/device-tree-bindings/pmic/pm8916.txt create mode 100644 doc/device-tree-bindings/serial/msm-serial.txt create mode 100644 doc/device-tree-bindings/spmi/spmi-msm.txt create mode 100644 doc/device-tree-bindings/spmi/spmi-sandbox.txt create mode 100644 doc/device-tree-bindings/usb/ehci-msm.txt create mode 100644 drivers/gpio/msm_gpio.c create mode 100644 drivers/gpio/pm8916_gpio.c create mode 100644 drivers/mmc/msm_sdhci.c create mode 100644 drivers/power/pmic/pm8916.c create mode 100644 drivers/serial/serial_msm.c create mode 100644 drivers/spmi/Kconfig create mode 100644 drivers/spmi/Makefile create mode 100644 drivers/spmi/spmi-msm.c create mode 100644 drivers/spmi/spmi-sandbox.c create mode 100644 drivers/spmi/spmi-uclass.c create mode 100644 drivers/usb/host/ehci-msm.c create mode 100644 drivers/usb/ulpi/Kconfig create mode 100644 include/configs/dragonboard410c.h create mode 100644 include/spmi/spmi.h rename include/usb/{ehci-fsl.h => ehci-ci.h} (96%) create mode 100644 test/dm/spmi.c

This driver works in "new" Data Mover UART mode, so will be compatible with modern Qualcomm chips only.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: - Add msm_serial_fetch that tries to fetch characters from FIFO - Decrease no of characters requested in RX transaction - Try to fetch characters from FIFO when tstc()/pending() is called
Changes in v2: - Added newline before return... (globally) - Renamed p to priv (priv data) - it required some rewrapping - Added Reviewed-by
Changes in v1: - Added (better) help to KConfig - Added dt binding documentation - Fixed include ordering - Reworked msm_serial_getc - Added error handling to msm_uart_clk_init (that is ignored later for now) - Dropped unneeded DM_FLAG_PRE_RELOC
doc/device-tree-bindings/serial/msm-serial.txt | 6 + drivers/serial/Kconfig | 8 + drivers/serial/Makefile | 1 + drivers/serial/serial_msm.c | 217 +++++++++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 doc/device-tree-bindings/serial/msm-serial.txt create mode 100644 drivers/serial/serial_msm.c
diff --git a/doc/device-tree-bindings/serial/msm-serial.txt b/doc/device-tree-bindings/serial/msm-serial.txt new file mode 100644 index 0000000..48b8428 --- /dev/null +++ b/doc/device-tree-bindings/serial/msm-serial.txt @@ -0,0 +1,6 @@ +Qualcomm UART (Data Mover mode) + +Required properties: +- compatible: must be "qcom,msm-uartdm-v1.4" +- reg: start address and size of the registers +- clock: interface clock (must accept baudrate as a frequency) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 2a770a1..a9a5d47 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -320,4 +320,12 @@ config XILINX_UARTLITE If you have a Xilinx based board and want to use the uartlite serial ports, say Y to this option. If unsure, say N.
+config MSM_SERIAL + bool "Qualcomm on-chip UART" + depends on DM_SERIAL + help + Support Data Mover UART used on Qualcomm Snapdragon SoCs. + It should support all Qualcomm devices with UARTDM version 1.4, + for example APQ8016 and MSM8916. + Single baudrate is supported in current implementation (115200). endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index ee7147a..b0ac9d8 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o obj-$(CONFIG_STM32X7_SERIAL) += serial_stm32x7.o obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o +obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c new file mode 100644 index 0000000..80fb89e --- /dev/null +++ b/drivers/serial/serial_msm.c @@ -0,0 +1,217 @@ +/* + * Qualcomm UART driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * UART will work in Data Mover mode. + * Based on Linux driver. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/io.h> +#include <linux/compiler.h> + +/* Serial registers - this driver works in uartdm mode*/ + +#define UARTDM_DMRX 0x34 /* Max RX transfer length */ +#define UARTDM_NCF_TX 0x40 /* Number of chars to TX */ + +#define UARTDM_RXFS 0x50 /* RX channel status register */ +#define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */ +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_SR 0xA4 /* Status register */ +#define UARTDM_SR_RX_READY (1 << 0) /* Word is the receiver FIFO */ +#define UARTDM_SR_TX_EMPTY (1 << 3) /* Transmitter underrun */ +#define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */ + +#define UARTDM_CR 0xA8 /* Command register */ +#define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */ +#define UARTDM_CR_CMD_RESET_STALE_INT (8 << 4) /* Clears stale irq */ +#define UARTDM_CR_CMD_RESET_TX_READY (3 << 8) /* Clears TX Ready irq*/ +#define UARTDM_CR_CMD_FORCE_STALE (4 << 8) /* Causes stale event */ +#define UARTDM_CR_CMD_STALE_EVENT_DISABLE (6 << 8) /* Disable stale event */ + +#define UARTDM_IMR 0xB0 /* Interrupt mask register */ +#define UARTDM_ISR 0xB4 /* Interrupt status register */ +#define UARTDM_ISR_TX_READY 0x80 /* TX FIFO empty */ + +#define UARTDM_TF 0x100 /* UART Transmit FIFO register */ +#define UARTDM_RF 0x140 /* UART Receive FIFO register */ + + +DECLARE_GLOBAL_DATA_PTR; + +struct msm_serial_data { + phys_addr_t base; + unsigned chars_cnt; /* number of buffered chars */ + uint32_t chars_buf; /* buffered chars */ +}; + +static int msm_serial_fetch(struct udevice *dev) +{ + struct msm_serial_data *priv = dev_get_priv(dev); + unsigned sr; + + if (priv->chars_cnt) + return priv->chars_cnt; + + /* Clear error in case of buffer overrun */ + if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN) + writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR); + + /* We need to fetch new character */ + sr = readl(priv->base + UARTDM_SR); + + if (sr & UARTDM_SR_RX_READY) { + /* There are at least 4 bytes in fifo */ + priv->chars_buf = readl(priv->base + UARTDM_RF); + priv->chars_cnt = 4; + } else { + /* Check if there is anything in fifo */ + priv->chars_cnt = readl(priv->base + UARTDM_RXFS); + /* Extract number of characters in UART packing buffer*/ + priv->chars_cnt = (priv->chars_cnt >> + UARTDM_RXFS_BUF_SHIFT) & + UARTDM_RXFS_BUF_MASK; + if (!priv->chars_cnt) + return 0; + + /* There is at least one charcter, move it to fifo */ + writel(UARTDM_CR_CMD_FORCE_STALE, + priv->base + UARTDM_CR); + + priv->chars_buf = readl(priv->base + UARTDM_RF); + writel(UARTDM_CR_CMD_RESET_STALE_INT, + priv->base + UARTDM_CR); + writel(0x7, priv->base + UARTDM_DMRX); + } + + return priv->chars_cnt; +} + +static int msm_serial_getc(struct udevice *dev) +{ + struct msm_serial_data *priv = dev_get_priv(dev); + char c; + + if (!msm_serial_fetch(dev)) + return -EAGAIN; + + c = priv->chars_buf & 0xFF; + priv->chars_buf >>= 8; + priv->chars_cnt--; + + return c; +} + +static int msm_serial_putc(struct udevice *dev, const char ch) +{ + struct msm_serial_data *priv = dev_get_priv(dev); + + if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) && + !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY)) + return -EAGAIN; + + writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR); + + writel(1, priv->base + UARTDM_NCF_TX); + writel(ch, priv->base + UARTDM_TF); + + return 0; +} + +static int msm_serial_pending(struct udevice *dev, bool input) +{ + if (input) { + if (msm_serial_fetch(dev)) + return 1; + } + + return 0; +} + +static const struct dm_serial_ops msm_serial_ops = { + .putc = msm_serial_putc, + .pending = msm_serial_pending, + .getc = msm_serial_getc, +}; + +static int msm_uart_clk_init(struct udevice *dev) +{ + uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + "clock-frequency", 115200); + uint clkd[2]; /* clk_id and clk_no */ + int clk_offset; + struct udevice *clk; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, + 2); + if (ret) + return ret; + + clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]); + if (clk_offset < 0) + return clk_offset; + + ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk); + if (ret) + return ret; + + ret = clk_set_periph_rate(clk, clkd[1], clk_rate); + if (ret < 0) + return ret; + + return 0; +} + +static int msm_serial_probe(struct udevice *dev) +{ + struct msm_serial_data *priv = dev_get_priv(dev); + + msm_uart_clk_init(dev); /* Ignore return value and hope clock was + properly initialized by earlier loaders */ + + if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN) + writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR); + + writel(0, priv->base + UARTDM_IMR); + writel(UARTDM_CR_CMD_STALE_EVENT_DISABLE, priv->base + UARTDM_CR); + msm_serial_fetch(dev); + + return 0; +} + +static int msm_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct msm_serial_data *priv = dev_get_priv(dev); + + priv->base = dev_get_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static const struct udevice_id msm_serial_ids[] = { + { .compatible = "qcom,msm-uartdm-v1.4" }, + { } +}; + +U_BOOT_DRIVER(serial_msm) = { + .name = "serial_msm", + .id = UCLASS_SERIAL, + .of_match = msm_serial_ids, + .ofdata_to_platdata = msm_serial_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct msm_serial_data), + .probe = msm_serial_probe, + .ops = &msm_serial_ops, +};

On Thu, Mar 31, 2016 at 11:12:14PM +0200, Mateusz Kulikowski wrote:
This driver works in "new" Data Mover UART mode, so will be compatible with modern Qualcomm chips only.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Add support for gpio controllers on Qualcomm Snapdragon devices. This devices are usually called Top Level Mode Multiplexing in Qualcomm documentation.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Reordered includes (again) - Added newlines between returns - Fixed error handling in msm_gpio_probe - Added reviewed-by
Changes in v1: - Added dt binding documentation - Added help to KConfig - Use clrsetbits() to switch direction - Fixed include order - Added #defines for registers/register fields - Added secondary compatible string
doc/device-tree-bindings/gpio/gpio-msm.txt | 22 +++++ drivers/gpio/Kconfig | 14 +++ drivers/gpio/Makefile | 1 + drivers/gpio/msm_gpio.c | 135 +++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 doc/device-tree-bindings/gpio/gpio-msm.txt create mode 100644 drivers/gpio/msm_gpio.c
diff --git a/doc/device-tree-bindings/gpio/gpio-msm.txt b/doc/device-tree-bindings/gpio/gpio-msm.txt new file mode 100644 index 0000000..966ce0a --- /dev/null +++ b/doc/device-tree-bindings/gpio/gpio-msm.txt @@ -0,0 +1,22 @@ +Qualcomm Snapdragon GPIO controller + +Required properties: +- compatible : "qcom,msm8916-pinctrl" or "qcom,apq8016-pinctrl" +- reg : Physical base address and length of the controller's registers. + This controller is called "Top Level Mode Multiplexing" in + Qualcomm documentation. +- #gpio-cells : Should be one (pin number). +- gpio-controller : Marks the device node as a GPIO controller. +- gpio-count: Number of GPIO pins. +- gpio-bank-name: (optional) name of gpio bank. As default "soc" is used. + +Example: + +soc_gpios: pinctrl@1000000 { + compatible = "qcom,msm8916-pinctrl"; + reg = <0x1000000 0x300000>; + gpio-controller; + gpio-count = <122>; + gpio-bank-name="soc"; + #gpio-cells = <1>; +}; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2311309..4d9e74c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -55,6 +55,20 @@ config LPC32XX_GPIO help Support for the LPC32XX GPIO driver.
+config MSM_GPIO + bool "Qualcomm GPIO driver" + depends on DM_GPIO + default n + help + Support GPIO controllers on Qualcomm Snapdragon family of SoCs. + This controller have single bank (default name "soc"), every + gpio has it's own set of registers. + Only simple GPIO operations are supported (get/set, change of + direction and checking pin function). + Supported devices: + - APQ8016 + - MSM8916 + config ROCKCHIP_GPIO bool "Rockchip GPIO driver" depends on DM_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ea6e2ed..4162c3c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -50,3 +50,4 @@ obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o +obj-$(CONFIG_MSM_GPIO) += msm_gpio.o diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c new file mode 100644 index 0000000..950f309 --- /dev/null +++ b/drivers/gpio/msm_gpio.c @@ -0,0 +1,135 @@ +/* + * Qualcomm GPIO driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/gpio.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Register offsets */ +#define GPIO_CONFIG_OFF(no) ((no) * 0x1000) +#define GPIO_IN_OUT_OFF(no) ((no) * 0x1000 + 0x4) + +/* OE */ +#define GPIO_OE_DISABLE (0x0 << 9) +#define GPIO_OE_ENABLE (0x1 << 9) +#define GPIO_OE_MASK (0x1 << 9) + +/* GPIO_IN_OUT register shifts. */ +#define GPIO_IN 0 +#define GPIO_OUT 1 + +struct msm_gpio_bank { + phys_addr_t base; +}; + +static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) +{ + struct msm_gpio_bank *priv = dev_get_priv(dev); + phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio); + + /* Disable OE bit */ + clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_DISABLE); + + return 0; +} + +static int msm_gpio_set_value(struct udevice *dev, unsigned gpio, int value) +{ + struct msm_gpio_bank *priv = dev_get_priv(dev); + + value = !!value; + /* set value */ + writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio)); + + return 0; +} + +static int msm_gpio_direction_output(struct udevice *dev, unsigned gpio, + int value) +{ + struct msm_gpio_bank *priv = dev_get_priv(dev); + phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio); + + value = !!value; + /* set value */ + writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio)); + /* switch direction */ + clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_ENABLE); + + return 0; +} + +static int msm_gpio_get_value(struct udevice *dev, unsigned gpio) +{ + struct msm_gpio_bank *priv = dev_get_priv(dev); + + return !!(readl(priv->base + GPIO_IN_OUT_OFF(gpio)) >> GPIO_IN); +} + +static int msm_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct msm_gpio_bank *priv = dev_get_priv(dev); + + if (readl(priv->base + GPIO_CONFIG_OFF(offset)) & GPIO_OE_ENABLE) + return GPIOF_OUTPUT; + + return GPIOF_INPUT; +} + +static const struct dm_gpio_ops gpio_msm_ops = { + .direction_input = msm_gpio_direction_input, + .direction_output = msm_gpio_direction_output, + .get_value = msm_gpio_get_value, + .set_value = msm_gpio_set_value, + .get_function = msm_gpio_get_function, +}; + +static int msm_gpio_probe(struct udevice *dev) +{ + struct msm_gpio_bank *priv = dev_get_priv(dev); + + priv->base = dev_get_addr(dev); + + return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0; +} + +static int msm_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "gpio-count", 0); + uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, + "gpio-bank-name", NULL); + if (uc_priv->bank_name == NULL) + uc_priv->bank_name = "soc"; + + return 0; +} + +static const struct udevice_id msm_gpio_ids[] = { + { .compatible = "qcom,msm8916-pinctrl" }, + { .compatible = "qcom,apq8016-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(gpio_msm) = { + .name = "gpio_msm", + .id = UCLASS_GPIO, + .of_match = msm_gpio_ids, + .ofdata_to_platdata = msm_gpio_ofdata_to_platdata, + .probe = msm_gpio_probe, + .ops = &gpio_msm_ops, + .priv_auto_alloc_size = sizeof(struct msm_gpio_bank), +}; + +

On Thu, Mar 31, 2016 at 11:12:15PM +0200, Mateusz Kulikowski wrote:
Add support for gpio controllers on Qualcomm Snapdragon devices. This devices are usually called Top Level Mode Multiplexing in Qualcomm documentation.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Add support for SD/eMMC controller present on some Qualcomm Snapdragon devices. This controller implements SDHCI 2.0 interface but requires vendor-specific initialization. Driver works in PIO mode as ADMA is not supported by U-Boot (yet).
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Add reviewed-by
Changes in v1: - Added commit message - Added DT binding documentation - Added Kconfig help - Reordered includes - Dropped redundant fields from msm_sdhc - Cleaned up clock init code (+ added error handling) - Dropped mdelay - use wait_for_bit instead in reset code - Added missing newline after declarations - Added error handling if "reg" is missing - Converted base address to pointer
doc/device-tree-bindings/mmc/msm_sdhci.txt | 25 ++++ drivers/mmc/Kconfig | 9 ++ drivers/mmc/Makefile | 1 + drivers/mmc/msm_sdhci.c | 180 +++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 doc/device-tree-bindings/mmc/msm_sdhci.txt create mode 100644 drivers/mmc/msm_sdhci.c
diff --git a/doc/device-tree-bindings/mmc/msm_sdhci.txt b/doc/device-tree-bindings/mmc/msm_sdhci.txt new file mode 100644 index 0000000..08a290c --- /dev/null +++ b/doc/device-tree-bindings/mmc/msm_sdhci.txt @@ -0,0 +1,25 @@ +Qualcomm Snapdragon SDHCI controller + +Required properties: +- compatible : "qcom,sdhci-msm-v4" +- reg: Base address and length of registers: + - Host controller registers (SDHCI) + - SD Core registers +- clock: interface clock (must accept SD bus clock as a frequency) + +Optional properties: +- index: If there is more than one controller - controller index (required + by generic SDHCI code). +- bus_width: Width of SD/eMMC bus (default 4) +- clock-frequency: Frequency of SD/eMMC bus (default 400 kHz) + +Example: + +sdhci@07864000 { + compatible = "qcom,sdhci-msm-v4"; + reg = <0x7864900 0x11c 0x7864000 0x800>; + index = <0x1>; + bus-width = <0x4>; + clock = <&clkc 1>; + clock-frequency = <200000000>; +}; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index dc8532f..4d3df11 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -16,6 +16,15 @@ config DM_MMC appear as block devices in U-Boot and can support filesystems such as EXT4 and FAT.
+config MSM_SDHCI + bool "Qualcomm SDHCI controller" + depends on DM_MMC + help + Enables support for SDHCI 2.0 controller present on some Qualcomm + Snapdragon devices. This device is compatible with eMMC v4.5 and + SD 3.0 specifications. Both SD and eMMC devices are supported. + Card-detect gpios are not supported. + config ROCKCHIP_DWMMC bool "Rockchip SD/MMC controller support" depends on DM_MMC && OF_CONTROL diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index b85e4bf..585aaf3 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -50,3 +50,4 @@ else obj-$(CONFIG_GENERIC_MMC) += mmc_write.o endif obj-$(CONFIG_PIC32_SDHCI) += pic32_sdhci.o +obj-$(CONFIG_MSM_SDHCI) += msm_sdhci.o diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c new file mode 100644 index 0000000..1e2a29b --- /dev/null +++ b/drivers/mmc/msm_sdhci.c @@ -0,0 +1,180 @@ +/* + * Qualcomm SDHCI driver - SD/eMMC controller + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * Based on Linux driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <sdhci.h> +#include <wait_bit.h> +#include <asm/io.h> +#include <linux/bitops.h> + +/* Non-standard registers needed for SDHCI startup */ +#define SDCC_MCI_POWER 0x0 +#define SDCC_MCI_POWER_SW_RST BIT(7) + +/* This is undocumented register */ +#define SDCC_MCI_VERSION 0x50 +#define SDCC_MCI_VERSION_MAJOR_SHIFT 28 +#define SDCC_MCI_VERSION_MAJOR_MASK (0xf << SDCC_MCI_VERSION_MAJOR_SHIFT) +#define SDCC_MCI_VERSION_MINOR_MASK 0xff + +#define SDCC_MCI_STATUS2 0x6C +#define SDCC_MCI_STATUS2_MCI_ACT 0x1 +#define SDCC_MCI_HC_MODE 0x78 + +/* Offset to SDHCI registers */ +#define SDCC_SDHCI_OFFSET 0x900 + +/* Non standard (?) SDHCI register */ +#define SDHCI_VENDOR_SPEC_CAPABILITIES0 0x11c + +struct msm_sdhc { + struct sdhci_host host; + void *base; +}; + +DECLARE_GLOBAL_DATA_PTR; + +static int msm_sdc_clk_init(struct udevice *dev) +{ + uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + "clock-frequency", 400000); + uint clkd[2]; /* clk_id and clk_no */ + int clk_offset; + struct udevice *clk; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, + 2); + if (ret) + return ret; + + clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]); + if (clk_offset < 0) + return clk_offset; + + ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk); + if (ret) + return ret; + + ret = clk_set_periph_rate(clk, clkd[1], clk_rate); + if (ret < 0) + return ret; + + return 0; +} + +static int msm_sdc_probe(struct udevice *dev) +{ + struct msm_sdhc *prv = dev_get_priv(dev); + struct sdhci_host *host = &prv->host; + u32 core_version, core_minor, core_major; + int ret; + + host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; + + /* Init clocks */ + ret = msm_sdc_clk_init(dev); + if (ret) + return ret; + + /* Reset the core and Enable SDHC mode */ + writel(readl(prv->base + SDCC_MCI_POWER) | SDCC_MCI_POWER_SW_RST, + prv->base + SDCC_MCI_POWER); + + + /* Wait for reset to be written to register */ + if (wait_for_bit(__func__, prv->base + SDCC_MCI_STATUS2, + SDCC_MCI_STATUS2_MCI_ACT, false, 10, false)) { + printf("msm_sdhci: reset request failed\n"); + return -EIO; + } + + /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */ + if (wait_for_bit(__func__, prv->base + SDCC_MCI_POWER, + SDCC_MCI_POWER_SW_RST, false, 2, false)) { + printf("msm_sdhci: stuck in reset\n"); + return -ETIMEDOUT; + } + + /* Enable host-controller mode */ + writel(1, prv->base + SDCC_MCI_HC_MODE); + + core_version = readl(prv->base + SDCC_MCI_VERSION); + + core_major = (core_version & SDCC_MCI_VERSION_MAJOR_MASK); + core_major >>= SDCC_MCI_VERSION_MAJOR_SHIFT; + + core_minor = core_version & SDCC_MCI_VERSION_MINOR_MASK; + + /* + * Support for some capabilities is not advertised by newer + * controller versions and must be explicitly enabled. + */ + if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { + u32 caps = readl(host->ioaddr + SDHCI_CAPABILITIES); + caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; + writel(caps, host->ioaddr + SDHCI_VENDOR_SPEC_CAPABILITIES0); + } + + /* Set host controller version */ + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + /* automatically detect max and min speed */ + return add_sdhci(host, 0, 0); +} + +static int msm_sdc_remove(struct udevice *dev) +{ + struct msm_sdhc *priv = dev_get_priv(dev); + + /* Disable host-controller mode */ + writel(0, priv->base + SDCC_MCI_HC_MODE); + + return 0; +} + +static int msm_ofdata_to_platdata(struct udevice *dev) +{ + struct udevice *parent = dev->parent; + struct msm_sdhc *priv = dev_get_priv(dev); + struct sdhci_host *host = &priv->host; + + host->name = strdup(dev->name); + host->ioaddr = (void *)dev_get_addr(dev); + host->bus_width = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "bus-width", 4); + host->index = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "index", 0); + priv->base = (void *)fdtdec_get_addr_size_auto_parent(gd->fdt_blob, + parent->of_offset, + dev->of_offset, + "reg", 1, NULL); + if (priv->base == (void *)FDT_ADDR_T_NONE || + host->ioaddr == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static const struct udevice_id msm_mmc_ids[] = { + { .compatible = "qcom,sdhci-msm-v4" }, + { } +}; + +U_BOOT_DRIVER(msm_sdc_drv) = { + .name = "msm_sdc", + .id = UCLASS_MMC, + .of_match = msm_mmc_ids, + .ofdata_to_platdata = msm_ofdata_to_platdata, + .probe = msm_sdc_probe, + .remove = msm_sdc_remove, + .priv_auto_alloc_size = sizeof(struct msm_sdhc), +};

On Thu, Mar 31, 2016 at 11:12:16PM +0200, Mateusz Kulikowski wrote:
Add support for SD/eMMC controller present on some Qualcomm Snapdragon devices. This controller implements SDHCI 2.0 interface but requires vendor-specific initialization. Driver works in PIO mode as ADMA is not supported by U-Boot (yet).
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Some host controllers need addidional initialization after ehci_reset() In non-dm implementation it is possible to use CONFIG_EHCI_HCD_INIT_AFTER_RESET. This patch adds similar option to ehci drivers using dm.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Add Reviewed-by (sjg)
Changes in v1: - No changes, just added Acked-by, Reviewed-by
drivers/usb/host/ehci-hcd.c | 6 ++++++ drivers/usb/host/ehci.h | 1 + 2 files changed, 7 insertions(+)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 0113c6c..598f444 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1615,6 +1615,12 @@ int ehci_register(struct udevice *dev, struct ehci_hccr *hccr, if (ret) goto err;
+ if (ops->init_after_reset) { + ret = ops->init_after_reset(ctrl); + if (ret) + goto err; + } + ret = ehci_common_init(ctrl, tweaks); if (ret) goto err; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 826b3fe..734d7f0 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -240,6 +240,7 @@ struct ehci_ops { void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg, uint32_t *reg); uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port); + int (*init_after_reset)(struct ehci_ctrl *ctrl); };
struct ehci_ctrl {

On Thu, Mar 31, 2016 at 11:12:17PM +0200, Mateusz Kulikowski wrote:
Some host controllers need addidional initialization after ehci_reset() In non-dm implementation it is possible to use CONFIG_EHCI_HCD_INIT_AFTER_RESET. This patch adds similar option to ehci drivers using dm.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Commit 3f9f8a5b83f8aec40c9f4ee496046a695e333c45 breaks U-Boot on Banana Pi (tested using FEL mode):
--- snip --- U-Boot SPL 2016.03-00612-g3f9f8a5 (Apr 03 2016 - 12:53:35) DRAM: 1024 MiB CPU: 912000000Hz, AXI/AHB/APB: 3/2/2 Trying to boot from
U-Boot 2016.03-00612-g3f9f8a5 (Apr 03 2016 - 12:53:35 +0200) Allwinner Technoloy
CPU: Allwinner A20 (SUN7I) Model: LeMaker Banana Pi I2C: ready DRAM: 1 GiB MMC: SUNXI SD/MMC: 0 Card did not respond to voltage select! *** Warning - MMC init failed, using default environment
Setting up a 720x576i composite-pal console (overscan 32x20) In: serial Out: vga Err: vga SCSI: SATA link 0 timeout. AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode flags: ncq stag pm led clo only pmp pio slum part ccc apst Net: eth0: ethernet@01c50000 starting USB... USB0: undefined instruction pc : [<00006004>] lr : [<7ef8876c>] reloc pc : [<cb0ac004>] lr : [<4a02e76c>] sp : 7af31660 ip : 00000000 fp : 7af3bb28 r10: 7af3be08 r9 : 7af39ee0 r8 : 01c14010 r7 : 01c14000 r6 : 00000000 r5 : 00000000 r4 : 7af3bc40 r3 : 00006000 r2 : 014af4dd r1 : 01c20c00 r0 : 7af3bc40 Flags: nzCv IRQs off FIQs off Mode SVC_32 Resetting CPU ...
resetting ... --- snip ---
Regards, B. Nortmann

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
On 03.04.2016 12:58, Bernhard Nortmann wrote:
Commit 3f9f8a5b83f8aec40c9f4ee496046a695e333c45 breaks U-Boot on Banana Pi (tested using FEL mode):
Fix posted - thanks :)
http://lists.denx.de/pipermail/u-boot/2016-April/250373.html
Regards, Mateusz

The following options can be now enabled via defconfig: - CONFIG_USB_ULPI - CONFIG_USB_ULPI_VIEWPORT - CONFIG_USB_ULPI_VIEWPORT_OMAP
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Acked-by: Marek Vasut marex@denx.de ---
Changes in v4: - Add Ack from Marek
Changes in v3: None Changes in v2: - Add better (any) descriptions for Kconfig items.
Changes in v1: None
drivers/usb/Kconfig | 2 ++ drivers/usb/ulpi/Kconfig | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 drivers/usb/ulpi/Kconfig
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7fa99c6..bccf43e 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -53,6 +53,8 @@ source "drivers/usb/musb-new/Kconfig"
source "drivers/usb/emul/Kconfig"
+source "drivers/usb/ulpi/Kconfig" + comment "USB peripherals"
config USB_STORAGE diff --git a/drivers/usb/ulpi/Kconfig b/drivers/usb/ulpi/Kconfig new file mode 100644 index 0000000..329d2df --- /dev/null +++ b/drivers/usb/ulpi/Kconfig @@ -0,0 +1,33 @@ +comment "ULPI drivers" + +choice + prompt "ULPI Viewport type" + optional + default n + help + Select ULPI viewport (SoC-side interface to ULPI) implementation + appropriate for the device if you want to communicate with + UTMI (USB PHY) via ULPI interface. + +config USB_ULPI_VIEWPORT + bool "Generic ULPI Viewport" + help + Support generic ULPI Viewport implementation that is used on + some Tegra and Snapdragon devices. + +config USB_ULPI_VIEWPORT_OMAP + bool "OMAP ULPI Viewport" + help + Support ULPI Viewport implementation that is used on OMAP devices. + +endchoice + +config USB_ULPI + bool "ULPI support" + depends on (USB_ULPI_VIEWPORT || USB_ULPI_VIEWPORT_OMAP) + help + Select to commnicate with USB PHY via ULPI interface. + ULPI is wrapper on UTMI+ core that is used as + PHY Transreceiver for USB controllers. + + This driver uses ULPI viewports that are specific for each SoC.

On Thu, Mar 31, 2016 at 11:12:18PM +0200, Mateusz Kulikowski wrote:
The following options can be now enabled via defconfig:
- CONFIG_USB_ULPI
- CONFIG_USB_ULPI_VIEWPORT
- CONFIG_USB_ULPI_VIEWPORT_OMAP
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Acked-by: Marek Vasut marex@denx.de
Applied to u-boot/master, thanks!

Move CONFIG_USB_ULPI* from headers to defconfigs for boards that use it. Also - add CONFIG_USB where necesarry - all boards use it, but some are not defining it explicitly.
Affected boards: colibri_t20, harmony, mcx, mt_ventoux, twister, zynq_(picozed, zc702, zc706, zed, zybo)
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - New patch, independent of the rest - Should compile cleanly on all affected platforms - Is orthogonal to series (i.e. if get's NAK will not break rest of series)
Changes in v1: None
configs/colibri_t20_defconfig | 2 ++ configs/harmony_defconfig | 2 ++ configs/mcx_defconfig | 3 +++ configs/mt_ventoux_defconfig | 3 +++ configs/twister_defconfig | 3 +++ configs/zynq_picozed_defconfig | 2 ++ configs/zynq_zc702_defconfig | 2 ++ configs/zynq_zc706_defconfig | 2 ++ configs/zynq_zed_defconfig | 2 ++ configs/zynq_zybo_defconfig | 2 ++ include/configs/colibri_t20.h | 3 +-- include/configs/harmony.h | 2 -- include/configs/mcx.h | 2 -- include/configs/tam3517-common.h | 2 -- include/configs/zynq-common.h | 2 -- 15 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/configs/colibri_t20_defconfig b/configs/colibri_t20_defconfig index c36967d..3813e96 100644 --- a/configs/colibri_t20_defconfig +++ b/configs/colibri_t20_defconfig @@ -21,4 +21,6 @@ CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_DM_VIDEO=y CONFIG_VIDEO_TEGRA20=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USE_PRIVATE_LIBGCC=y diff --git a/configs/harmony_defconfig b/configs/harmony_defconfig index c150f6e..d4aafe9 100644 --- a/configs/harmony_defconfig +++ b/configs/harmony_defconfig @@ -21,4 +21,6 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_VIDEO=y CONFIG_VIDEO_TEGRA20=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USE_PRIVATE_LIBGCC=y diff --git a/configs/mcx_defconfig b/configs/mcx_defconfig index a25ffcf..9c9d51a 100644 --- a/configs/mcx_defconfig +++ b/configs/mcx_defconfig @@ -12,3 +12,6 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set CONFIG_SYS_NS16550=y CONFIG_OF_LIBFDT=y +CONFIG_USB=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT_OMAP=y diff --git a/configs/mt_ventoux_defconfig b/configs/mt_ventoux_defconfig index c537440..45913d4 100644 --- a/configs/mt_ventoux_defconfig +++ b/configs/mt_ventoux_defconfig @@ -10,3 +10,6 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set CONFIG_SYS_NS16550=y CONFIG_OF_LIBFDT=y +CONFIG_USB=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT_OMAP=y diff --git a/configs/twister_defconfig b/configs/twister_defconfig index 06c98eb..064cf91 100644 --- a/configs/twister_defconfig +++ b/configs/twister_defconfig @@ -10,3 +10,6 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set CONFIG_SYS_NS16550=y CONFIG_OF_LIBFDT=y +CONFIG_USB=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT_OMAP=y diff --git a/configs/zynq_picozed_defconfig b/configs/zynq_picozed_defconfig index 67e38e5..c730f3c 100644 --- a/configs/zynq_picozed_defconfig +++ b/configs/zynq_picozed_defconfig @@ -14,3 +14,5 @@ CONFIG_ZYNQ_SDHCI=y CONFIG_ZYNQ_GEM=y CONFIG_USB=y CONFIG_USB_GADGET=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y diff --git a/configs/zynq_zc702_defconfig b/configs/zynq_zc702_defconfig index d1740a7..e8d28e4 100644 --- a/configs/zynq_zc702_defconfig +++ b/configs/zynq_zc702_defconfig @@ -26,3 +26,5 @@ CONFIG_DEBUG_UART_CLOCK=50000000 CONFIG_ZYNQ_QSPI=y CONFIG_USB=y CONFIG_USB_GADGET=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y diff --git a/configs/zynq_zc706_defconfig b/configs/zynq_zc706_defconfig index d3ae438..d19108f 100644 --- a/configs/zynq_zc706_defconfig +++ b/configs/zynq_zc706_defconfig @@ -23,3 +23,5 @@ CONFIG_ZYNQ_GEM=y CONFIG_ZYNQ_QSPI=y CONFIG_USB=y CONFIG_USB_GADGET=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig index 9ad33ff..b13de10 100644 --- a/configs/zynq_zed_defconfig +++ b/configs/zynq_zed_defconfig @@ -23,3 +23,5 @@ CONFIG_ZYNQ_GEM=y CONFIG_ZYNQ_QSPI=y CONFIG_USB=y CONFIG_USB_GADGET=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig index 470c9cb..4a59890 100644 --- a/configs/zynq_zybo_defconfig +++ b/configs/zynq_zybo_defconfig @@ -24,3 +24,5 @@ CONFIG_DEBUG_UART_CLOCK=50000000 CONFIG_ZYNQ_QSPI=y CONFIG_USB=y CONFIG_USB_GADGET=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y diff --git a/include/configs/colibri_t20.h b/include/configs/colibri_t20.h index b7ad189..e97e5a1 100644 --- a/include/configs/colibri_t20.h +++ b/include/configs/colibri_t20.h @@ -36,8 +36,7 @@ /* USB host support */ #define CONFIG_USB_EHCI #define CONFIG_USB_EHCI_TEGRA -#define CONFIG_USB_ULPI -#define CONFIG_USB_ULPI_VIEWPORT +#define CONFIG_USB_MAX_CONTROLLER_COUNT 3 #define CONFIG_USB_STORAGE #define CONFIG_CMD_USB
diff --git a/include/configs/harmony.h b/include/configs/harmony.h index f66ac70..0a3cb18 100644 --- a/include/configs/harmony.h +++ b/include/configs/harmony.h @@ -44,8 +44,6 @@ /* USB Host support */ #define CONFIG_USB_EHCI #define CONFIG_USB_EHCI_TEGRA -#define CONFIG_USB_ULPI -#define CONFIG_USB_ULPI_VIEWPORT #define CONFIG_USB_STORAGE #define CONFIG_CMD_USB
diff --git a/include/configs/mcx.h b/include/configs/mcx.h index 174cb5c..9a4f638 100644 --- a/include/configs/mcx.h +++ b/include/configs/mcx.h @@ -102,8 +102,6 @@ #define CONFIG_OMAP3_GPIO_5 #define CONFIG_USB_EHCI #define CONFIG_USB_EHCI_OMAP -#define CONFIG_USB_ULPI -#define CONFIG_USB_ULPI_VIEWPORT_OMAP #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 57 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_HOST_ETHER diff --git a/include/configs/tam3517-common.h b/include/configs/tam3517-common.h index a532417..59b6c5f 100644 --- a/include/configs/tam3517-common.h +++ b/include/configs/tam3517-common.h @@ -91,8 +91,6 @@ #define CONFIG_OMAP3_GPIO_5 #define CONFIG_USB_EHCI #define CONFIG_USB_EHCI_OMAP -#define CONFIG_USB_ULPI -#define CONFIG_USB_ULPI_VIEWPORT_OMAP #define CONFIG_OMAP_EHCI_PHY1_RESET_GPIO 25 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_USB_STORAGE diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index 9ff3df2..c2ed28a 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -96,8 +96,6 @@ # define CONFIG_CMD_USB # define CONFIG_USB_STORAGE # define CONFIG_USB_EHCI_ZYNQ -# define CONFIG_USB_ULPI_VIEWPORT -# define CONFIG_USB_ULPI # define CONFIG_EHCI_IS_TDI # define CONFIG_USB_MAX_CONTROLLER_COUNT 2

On Thu, Mar 31, 2016 at 11:12:19PM +0200, Mateusz Kulikowski wrote:
Move CONFIG_USB_ULPI* from headers to defconfigs for boards that use it. Also - add CONFIG_USB where necesarry - all boards use it, but some are not defining it explicitly.
Affected boards: colibri_t20, harmony, mcx, mt_ventoux, twister, zynq_(picozed, zc702, zc706, zed, zybo)
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

viewport_addr is address of memory mapped ULPI viewport. It is used only as argument to readl/writel later causing compile warnings on 64-bit devices.
This fix changes its type to match pointer size.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de ---
Changes in v4: - Add Ack from Marek
Changes in v3: - New patch
Changes in v2: None Changes in v1: None
include/usb/ulpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/usb/ulpi.h b/include/usb/ulpi.h index 4fa765b..dfea395 100644 --- a/include/usb/ulpi.h +++ b/include/usb/ulpi.h @@ -32,7 +32,7 @@ * be extended from this structure */ struct ulpi_viewport { - u32 viewport_addr; + uintptr_t viewport_addr; u32 port_num; };

On Thu, Mar 31, 2016 at 11:12:20PM +0200, Mateusz Kulikowski wrote:
viewport_addr is address of memory mapped ULPI viewport. It is used only as argument to readl/writel later causing compile warnings on 64-bit devices.
This fix changes its type to match pointer size.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de
Applied to u-boot/master, thanks!

ulpi_read and ulpi_write are used to read/write registers via ULPI bus. Code generates compilation warnings on 64-bit machines where pointer is cast to u32.
This patch drops all but last 8 bits of register address. It is possible, because addresses on ULPI bus are 6- or 8-bit.
It is not possible (according to ULPI 1.1 spec) to have more than 8-bit addressing.
This patch should not cause regressions as all calls to ulpi_read/write use either structure pointer (@ address 0) or integer offsets cast to pointer - addresses requested are way below 8-bit range.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de ---
Changes in v4: - Add Ack from Marek
Changes in v3: - New patch
Changes in v2: None Changes in v1: None
drivers/usb/ulpi/ulpi-viewport.c | 5 +++-- include/usb/ulpi.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/ulpi/ulpi-viewport.c b/drivers/usb/ulpi/ulpi-viewport.c index 72a06de..d111680 100644 --- a/drivers/usb/ulpi/ulpi-viewport.c +++ b/drivers/usb/ulpi/ulpi-viewport.c @@ -92,7 +92,8 @@ static int ulpi_request(struct ulpi_viewport *ulpi_vp, u32 value)
int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value) { - u32 val = ULPI_RWRUN | ULPI_RWCTRL | ((u32)reg << 16) | (value & 0xff); + u32 addr = (uintptr_t)reg & 0xFF; + u32 val = ULPI_RWRUN | ULPI_RWCTRL | addr << 16 | (value & 0xff);
val |= (ulpi_vp->port_num & 0x7) << 24; return ulpi_request(ulpi_vp, val); @@ -101,7 +102,7 @@ int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value) u32 ulpi_read(struct ulpi_viewport *ulpi_vp, u8 *reg) { int err; - u32 val = ULPI_RWRUN | ((u32)reg << 16); + u32 val = ULPI_RWRUN | ((uintptr_t)reg & 0xFF) << 16;
val |= (ulpi_vp->port_num & 0x7) << 24; err = ulpi_request(ulpi_vp, val); diff --git a/include/usb/ulpi.h b/include/usb/ulpi.h index dfea395..747fb0a 100644 --- a/include/usb/ulpi.h +++ b/include/usb/ulpi.h @@ -123,6 +123,7 @@ int ulpi_reset(struct ulpi_viewport *ulpi_vp); /* * Write to the ULPI PHY register via the viewport. * @reg - the ULPI register (one of the fields in struct ulpi_regs). + * Due to ULPI design, only 8 lsb of address are used. * @value - the value - only 8 lower bits are used, others ignored. * * returns 0 on success, ULPI_ERROR on failure. @@ -132,6 +133,7 @@ int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value); /* * Read the ULPI PHY register content via the viewport. * @reg - the ULPI register (one of the fields in struct ulpi_regs). + * Due to ULPI design, only 8 lsb of address are used. * * returns register content on success, ULPI_ERROR on failure. */

On Thu, Mar 31, 2016 at 11:12:21PM +0200, Mateusz Kulikowski wrote:
ulpi_read and ulpi_write are used to read/write registers via ULPI bus. Code generates compilation warnings on 64-bit machines where pointer is cast to u32.
This patch drops all but last 8 bits of register address. It is possible, because addresses on ULPI bus are 6- or 8-bit.
It is not possible (according to ULPI 1.1 spec) to have more than 8-bit addressing.
This patch should not cause regressions as all calls to ulpi_read/write use either structure pointer (@ address 0) or integer offsets cast to pointer - addresses requested are way below 8-bit range.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de
Applied to u-boot/master, thanks!

Debug printf used '%u' to print size_t variable. This caused warnings on 64-bit machines.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com ---
Changes in v4: - Add Ack from Marek and Joe
Changes in v3: - New patch
Changes in v2: None Changes in v1: None
drivers/usb/eth/asix88179.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c index cf4085d..5e1ea86 100644 --- a/drivers/usb/eth/asix88179.c +++ b/drivers/usb/eth/asix88179.c @@ -497,7 +497,7 @@ static int asix_send(struct eth_device *eth, void *packet, int length) length + sizeof(packet_len) + sizeof(tx_hdr2), &actual_len, USB_BULK_SEND_TIMEOUT); - debug("Tx: len = %u, actual = %u, err = %d\n", + debug("Tx: len = %zu, actual = %u, err = %d\n", length + sizeof(packet_len), actual_len, err);
return err;

On Thu, Mar 31, 2016 at 11:12:22PM +0200, Mateusz Kulikowski wrote:
Debug printf used '%u' to print size_t variable. This caused warnings on 64-bit machines.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Acked-by: Joe Hershberger joe.hershberger@ni.com
Applied to u-boot/master, thanks!

Most of ehci-fsl header describe USB controller designed by Chipidea and used by various SoC vendors.
This patch renames it to a generic header: ehci-ci.h Contents of file are not changed (so it contains several references to freescale SoCs).
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: - Add missing renames (arch/* and board/*)
Changes in v3: None Changes in v2: - Add acked-by
Changes in v1: None
arch/powerpc/cpu/mpc83xx/cpu_init.c | 2 +- board/boundary/nitrogen6x/nitrogen6x.c | 2 +- board/denx/m53evk/m53evk.c | 2 +- board/freescale/mx51evk/mx51evk.c | 2 +- board/freescale/mx6slevk/mx6slevk.c | 2 +- board/freescale/mx6sxsabreauto/mx6sxsabreauto.c | 2 +- board/freescale/mx6sxsabresd/mx6sxsabresd.c | 2 +- board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c | 2 +- board/freescale/mx7dsabresd/mx7dsabresd.c | 2 +- board/solidrun/mx6cuboxi/mx6cuboxi.c | 2 +- drivers/usb/host/ehci-fsl.c | 2 +- drivers/usb/host/ehci-mpc512x.c | 2 +- drivers/usb/host/ehci-mx5.c | 2 +- drivers/usb/host/ehci-mx6.c | 2 +- drivers/usb/host/ehci-mxc.c | 2 +- drivers/usb/host/ehci-vf.c | 2 +- drivers/usb/host/ehci-zynq.c | 2 +- include/usb/{ehci-fsl.h => ehci-ci.h} | 6 +++--- 18 files changed, 20 insertions(+), 20 deletions(-) rename include/usb/{ehci-fsl.h => ehci-ci.h} (99%)
diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c index 00572de..0791043 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c @@ -9,7 +9,7 @@ #include <ioports.h> #include <asm/io.h> #ifdef CONFIG_USB_EHCI_FSL -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #endif
DECLARE_GLOBAL_DATA_PTR; diff --git a/board/boundary/nitrogen6x/nitrogen6x.c b/board/boundary/nitrogen6x/nitrogen6x.c index 104d71f..a3a56ca 100644 --- a/board/boundary/nitrogen6x/nitrogen6x.c +++ b/board/boundary/nitrogen6x/nitrogen6x.c @@ -31,7 +31,7 @@ #include <i2c.h> #include <input.h> #include <netdev.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR; #define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22) diff --git a/board/denx/m53evk/m53evk.c b/board/denx/m53evk/m53evk.c index 5dd6cdd..934f009 100644 --- a/board/denx/m53evk/m53evk.c +++ b/board/denx/m53evk/m53evk.c @@ -22,7 +22,7 @@ #include <spl.h> #include <fsl_esdhc.h> #include <asm/gpio.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <linux/fb.h> #include <ipu_pixfmt.h>
diff --git a/board/freescale/mx51evk/mx51evk.c b/board/freescale/mx51evk/mx51evk.c index c7c21f3..2ea5346 100644 --- a/board/freescale/mx51evk/mx51evk.c +++ b/board/freescale/mx51evk/mx51evk.c @@ -20,7 +20,7 @@ #include <power/pmic.h> #include <fsl_pmic.h> #include <mc13892.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index f440ce6..f1915a8 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -28,7 +28,7 @@ #include <power/pfuze100_pmic.h> #include "../common/pfuze.h" #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c b/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c index a240982..886373c 100644 --- a/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c +++ b/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c @@ -28,7 +28,7 @@ #include <power/pfuze100_pmic.h> #include "../common/pfuze.h" #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <pca953x.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/board/freescale/mx6sxsabresd/mx6sxsabresd.c b/board/freescale/mx6sxsabresd/mx6sxsabresd.c index 41319c6..25e009e 100644 --- a/board/freescale/mx6sxsabresd/mx6sxsabresd.c +++ b/board/freescale/mx6sxsabresd/mx6sxsabresd.c @@ -27,7 +27,7 @@ #include <power/pfuze100_pmic.h> #include "../common/pfuze.h" #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c b/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c index 98d5675..88d3fbd 100644 --- a/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c +++ b/board/freescale/mx6ul_14x14_evk/mx6ul_14x14_evk.c @@ -27,7 +27,7 @@ #include <power/pfuze3000_pmic.h> #include "../common/pfuze.h" #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/freescale/mx7dsabresd/mx7dsabresd.c b/board/freescale/mx7dsabresd/mx7dsabresd.c index 4d0b195..c3062f1 100644 --- a/board/freescale/mx7dsabresd/mx7dsabresd.c +++ b/board/freescale/mx7dsabresd/mx7dsabresd.c @@ -24,7 +24,7 @@ #include <asm/imx-common/mxc_i2c.h> #include <asm/arch/crm_regs.h> #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/board/solidrun/mx6cuboxi/mx6cuboxi.c b/board/solidrun/mx6cuboxi/mx6cuboxi.c index 823b70f..bcc9729 100644 --- a/board/solidrun/mx6cuboxi/mx6cuboxi.c +++ b/board/solidrun/mx6cuboxi/mx6cuboxi.c @@ -33,7 +33,7 @@ #include <asm/arch/sys_proto.h> #include <spl.h> #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 97b7f14..4bcea9d 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -12,7 +12,7 @@ #include <pci.h> #include <usb.h> #include <asm/io.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <hwconfig.h> #include <fsl_usb.h> #include <fdt_support.h> diff --git a/drivers/usb/host/ehci-mpc512x.c b/drivers/usb/host/ehci-mpc512x.c index b320c4a..4b50ac8 100644 --- a/drivers/usb/host/ehci-mpc512x.c +++ b/drivers/usb/host/ehci-mpc512x.c @@ -17,7 +17,7 @@ #include <pci.h> #include <usb.h> #include <asm/io.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
#include "ehci.h"
diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c index d319962..2b36ceb 100644 --- a/drivers/usb/host/ehci-mx5.c +++ b/drivers/usb/host/ehci-mx5.c @@ -9,7 +9,7 @@ #include <usb.h> #include <errno.h> #include <linux/compiler.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index e1c67f7..a981b50 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -10,7 +10,7 @@ #include <errno.h> #include <wait_bit.h> #include <linux/compiler.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index f09c75a..f8324ee 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -9,7 +9,7 @@ #include <usb.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <errno.h>
#include "ehci.h" diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c index 335e303..61789dd 100644 --- a/drivers/usb/host/ehci-vf.c +++ b/drivers/usb/host/ehci-vf.c @@ -17,7 +17,7 @@ #include <asm/arch/crm_regs.h> #include <asm/imx-common/iomux-v3.h> #include <asm/imx-common/regs-usbphy.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h>
#include "ehci.h"
diff --git a/drivers/usb/host/ehci-zynq.c b/drivers/usb/host/ehci-zynq.c index 7770d05..37a7935 100644 --- a/drivers/usb/host/ehci-zynq.c +++ b/drivers/usb/host/ehci-zynq.c @@ -11,7 +11,7 @@ #include <asm/arch/sys_proto.h> #include <asm/io.h> #include <usb.h> -#include <usb/ehci-fsl.h> +#include <usb/ehci-ci.h> #include <usb/ulpi.h>
#include "ehci.h" diff --git a/include/usb/ehci-fsl.h b/include/usb/ehci-ci.h similarity index 99% rename from include/usb/ehci-fsl.h rename to include/usb/ehci-ci.h index e9349b5..725aec5 100644 --- a/include/usb/ehci-fsl.h +++ b/include/usb/ehci-ci.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: GPL-2.0+ */
-#ifndef _EHCI_FSL_H -#define _EHCI_FSL_H +#ifndef _EHCI_CI_H +#define _EHCI_CI_H
#include <asm/processor.h>
@@ -285,4 +285,4 @@ int usb_phy_mode(int port); int board_ehci_hcd_init(int port); int board_usb_phy_mode(int port);
-#endif /* _EHCI_FSL_H */ +#endif /* _EHCI_CI_H */

On Thu, Mar 31, 2016 at 11:12:23PM +0200, Mateusz Kulikowski wrote:
Most of ehci-fsl header describe USB controller designed by Chipidea and used by various SoC vendors.
This patch renames it to a generic header: ehci-ci.h Contents of file are not changed (so it contains several references to freescale SoCs).
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Some registers of usb_ehci were marked as reserved. This may be true for some variants of Chipidea USB core, but they have meaning on other devices.
The following registers were added: sbusstatus/sbusmode: AHB-related registers genconfig*: Auxiluary IP core configuration registers.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org
---
Changes in v4: None Changes in v3: None Changes in v2: - Add reviewed-by
Changes in v1: None
include/usb/ehci-ci.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/include/usb/ehci-ci.h b/include/usb/ehci-ci.h index 725aec5..305b180 100644 --- a/include/usb/ehci-ci.h +++ b/include/usb/ehci-ci.h @@ -191,7 +191,11 @@ struct usb_ehci { u32 gptimer1_ld; /* 0x088 - General Purpose Timer 1 load value */ u32 gptimer1_ctrl; /* 0x08C - General Purpose Timer 1 control */ u32 sbuscfg; /* 0x090 - System Bus Interface Control */ - u8 res2[0x6C]; + u32 sbusstatus; /* 0x094 - System Bus Interface Status */ + u32 sbusmode; /* 0x098 - System Bus Interface Mode */ + u32 genconfig; /* 0x09C - USB Core Configuration */ + u32 genconfig2; /* 0x0A0 - USB Core Configuration 2 */ + u8 res2[0x5c]; u8 caplength; /* 0x100 - Capability Register Length */ u8 res3[0x1]; u16 hciversion; /* 0x102 - Host Interface Version */

On Thu, Mar 31, 2016 at 11:12:24PM +0200, Mateusz Kulikowski wrote:
Some registers of usb_ehci were marked as reserved. This may be true for some variants of Chipidea USB core, but they have meaning on other devices.
The following registers were added: sbusstatus/sbusmode: AHB-related registers genconfig*: Auxiluary IP core configuration registers.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Use definitions from ehci.h instead.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org
---
Changes in v4: None Changes in v3: None Changes in v2: - Add Acked-by
Changes in v1: None
drivers/usb/host/ehci-mpc512x.c | 4 ++-- include/usb/ehci-ci.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/host/ehci-mpc512x.c b/drivers/usb/host/ehci-mpc512x.c index 4b50ac8..bb4f461 100644 --- a/drivers/usb/host/ehci-mpc512x.c +++ b/drivers/usb/host/ehci-mpc512x.c @@ -93,7 +93,7 @@ static int reset_usb_controller(volatile struct usb_ehci *ehci) unsigned int i;
/* Command a reset of the USB Controller */ - out_be32(&(ehci->usbcmd), EHCI_FSL_USBCMD_RST); + out_be32(&(ehci->usbcmd), CMD_RESET);
/* Wait for the reset process to finish */ for (i = 65535 ; i > 0 ; i--) { @@ -101,7 +101,7 @@ static int reset_usb_controller(volatile struct usb_ehci *ehci) * The host will set this bit to zero once the * reset process is complete */ - if ((in_be32(&(ehci->usbcmd)) & EHCI_FSL_USBCMD_RST) == 0) + if ((in_be32(&(ehci->usbcmd)) & CMD_RESET) == 0) return 0; }
diff --git a/include/usb/ehci-ci.h b/include/usb/ehci-ci.h index 305b180..586d32a 100644 --- a/include/usb/ehci-ci.h +++ b/include/usb/ehci-ci.h @@ -97,10 +97,6 @@ #define INTR_DATA_PULSING_EN (0x1<<30) #define INTSTS_MASK (0x00ff0000)
-/* USBCMD Bits of interest */ -#define EHCI_FSL_USBCMD_RST (1 << 1) -#define EHCI_FSL_USBCMD_RS (1 << 0) - #define INTERRUPT_ENABLE_BITS_MASK \ (INTR_USB_ID_EN | \ INTR_1MS_TIMER_EN | \

On Thu, Mar 31, 2016 at 11:12:25PM +0200, Mateusz Kulikowski wrote:
Use definitions from ehci.h instead.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

This driver is able to reconfigure OTG controller into HOST mode. Board can add board-specific initialization as board_prepare_usb(). It requires USB_ULPI_VIEWPORT enabled in board configuration.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Use PORT_... macro to write to portsc - Remove extra whitespace in probe() - Add acked-by
Changes in v1: - Reordered header files - Removed braces around constant - Added more verbose help to KConfig - Added ULPI dependency to Kconfig - Drop register #defines - use ehci-ci.h instead - Create fixed ulpi viewport for device - Use setbits/clearbits where possible - Use wait_for_bit to reset controller - Add dt binding documents
doc/device-tree-bindings/usb/ehci-msm.txt | 10 ++ drivers/usb/host/Kconfig | 11 ++ drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-msm.c | 178 ++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 doc/device-tree-bindings/usb/ehci-msm.txt create mode 100644 drivers/usb/host/ehci-msm.c
diff --git a/doc/device-tree-bindings/usb/ehci-msm.txt b/doc/device-tree-bindings/usb/ehci-msm.txt new file mode 100644 index 0000000..205bb07 --- /dev/null +++ b/doc/device-tree-bindings/usb/ehci-msm.txt @@ -0,0 +1,10 @@ +Chipidea EHCI controller (part of OTG controller) used on Qualcomm devices. + +Required properties: +- compatible: must be "qcom,ehci-host" +- reg: start address and size of the registers + +ehci@78d9000 { + compatible = "qcom,ehci-host"; + reg = <0x78d9000 0x400>; +}; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 9332374..d2363c8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -74,6 +74,17 @@ config USB_EHCI_MX6 ---help--- Enables support for the on-chip EHCI controller on i.MX6 SoCs.
+config USB_EHCI_MSM + bool "Support for Qualcomm on-chip EHCI USB controller" + depends on DM_USB + select USB_ULPI_VIEWPORT + default n + ---help--- + Enables support for the on-chip EHCI controller on Qualcomm + Snapdragon SoCs. + This driver supports combination of Chipidea USB controller + and Synapsys USB PHY in host mode only. + config USB_EHCI_GENERIC bool "Support for generic EHCI USB controller" depends on OF_CONTROL diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 9a87d2b..507519e 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_USB_EHCI_MX7) += ehci-mx6.o obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o obj-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o +obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c new file mode 100644 index 0000000..6484c1c --- /dev/null +++ b/drivers/usb/host/ehci-msm.c @@ -0,0 +1,178 @@ +/* + * Qualcomm EHCI driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * Based on Linux driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <usb.h> +#include <usb/ehci-ci.h> +#include <usb/ulpi.h> +#include <wait_bit.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <linux/compat.h> +#include "ehci.h" + +/* PHY viewport regs */ +#define ULPI_MISC_A_READ 0x96 +#define ULPI_MISC_A_SET 0x97 +#define ULPI_MISC_A_CLEAR 0x98 +#define ULPI_MISC_A_VBUSVLDEXTSEL (1 << 1) +#define ULPI_MISC_A_VBUSVLDEXT (1 << 0) + +#define GEN2_SESS_VLD_CTRL_EN (1 << 7) + +#define SESS_VLD_CTRL (1 << 25) + +struct msm_ehci_priv { + struct ehci_ctrl ctrl; /* Needed by EHCI */ + struct usb_ehci *ehci; /* Start of IP core*/ + struct ulpi_viewport ulpi_vp; /* ULPI Viewport */ +}; + +int __weak board_prepare_usb(enum usb_init_type type) +{ + return 0; +} + +static void setup_usb_phy(struct msm_ehci_priv *priv) +{ + /* Select and enable external configuration with USB PHY */ + ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_SET, + ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); +} + +static void reset_usb_phy(struct msm_ehci_priv *priv) +{ + /* Disable VBUS mimicing in the controller. */ + ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR, + ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); +} + + +static int msm_init_after_reset(struct ehci_ctrl *dev) +{ + struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl); + struct usb_ehci *ehci = p->ehci; + + /* select ULPI phy */ + writel(PORT_PTS_ULPI, &ehci->portsc); + setup_usb_phy(p); + + /* Enable sess_vld */ + setbits_le32(&ehci->genconfig2, GEN2_SESS_VLD_CTRL_EN); + + /* Enable external vbus configuration in the LINK */ + setbits_le32(&ehci->usbcmd, SESS_VLD_CTRL); + + /* USB_OTG_HS_AHB_BURST */ + writel(0x0, &ehci->sbuscfg); + + /* USB_OTG_HS_AHB_MODE: HPROT_MODE */ + /* Bus access related config. */ + writel(0x08, &ehci->sbusmode); + + /* set mode to host controller */ + writel(CM_HOST, &ehci->usbmode); + + return 0; +} + +static const struct ehci_ops msm_ehci_ops = { + .init_after_reset = msm_init_after_reset +}; + +static int ehci_usb_probe(struct udevice *dev) +{ + struct msm_ehci_priv *p = dev_get_priv(dev); + struct usb_ehci *ehci = p->ehci; + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; + int ret; + + hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength); + hcor = (struct ehci_hcor *)((phys_addr_t)hccr + + HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); + + ret = board_prepare_usb(USB_INIT_HOST); + if (ret < 0) + return ret; + + return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, USB_INIT_HOST); +} + +static int ehci_usb_remove(struct udevice *dev) +{ + struct msm_ehci_priv *p = dev_get_priv(dev); + struct usb_ehci *ehci = p->ehci; + int ret; + + ret = ehci_deregister(dev); + if (ret) + return ret; + + /* Stop controller. */ + clrbits_le32(&ehci->usbcmd, CMD_RUN); + + reset_usb_phy(p); + + ret = board_prepare_usb(USB_INIT_DEVICE); /* Board specific hook */ + if (ret < 0) + return ret; + + /* Reset controller */ + setbits_le32(&ehci->usbcmd, CMD_RESET); + + /* Wait for reset */ + if (wait_for_bit(__func__, &ehci->usbcmd, CMD_RESET, false, 30, + false)) { + printf("Stuck on USB reset.\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int ehci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct msm_ehci_priv *priv = dev_get_priv(dev); + + priv->ulpi_vp.port_num = 0; + priv->ehci = (void *)dev_get_addr(dev); + + if (priv->ehci == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + /* Warning: this will not work if viewport address is > 64 bit due to + * ULPI design. + */ + priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint; + + return 0; +} + +static const struct udevice_id ehci_usb_ids[] = { + { .compatible = "qcom,ehci-host", }, + { } +}; + +U_BOOT_DRIVER(usb_ehci) = { + .name = "ehci_msm", + .id = UCLASS_USB, + .of_match = ehci_usb_ids, + .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, + .probe = ehci_usb_probe, + .remove = ehci_usb_remove, + .ops = &ehci_usb_ops, + .priv_auto_alloc_size = sizeof(struct msm_ehci_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +};

On Thu, Mar 31, 2016 at 11:12:26PM +0200, Mateusz Kulikowski wrote:
This driver is able to reconfigure OTG controller into HOST mode. Board can add board-specific initialization as board_prepare_usb(). It requires USB_ULPI_VIEWPORT enabled in board configuration.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Acked-by: Marek Vasut marex@denx.de Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Qualcom processors use proprietary bus to talk with PMIC devices - SPMI (System Power Management Interface). On wiring level it is similar to I2C, but on protocol level, it's multi-master and has simple autodetection capabilities. This commit adds simple uclass that provides bus read/write interface.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Use proper entry order in Kconfig - Rename CONFIG_DM_SPMI -> CONFIG_SPMI - Fix header ordering - Add reviewed-by
Changes in v1: - Reorder includes - Add read/write arguments documentation
drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/spmi/Kconfig | 10 ++++++++++ drivers/spmi/Makefile | 7 +++++++ drivers/spmi/spmi-uclass.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/spmi/spmi.h | 47 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 116 insertions(+) create mode 100644 drivers/spmi/Kconfig create mode 100644 drivers/spmi/Makefile create mode 100644 drivers/spmi/spmi-uclass.c create mode 100644 include/spmi/spmi.h
diff --git a/drivers/Kconfig b/drivers/Kconfig index 70993fd..c82a94b 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -60,6 +60,8 @@ source "drivers/sound/Kconfig"
source "drivers/spi/Kconfig"
+source "drivers/spmi/Kconfig" + source "drivers/thermal/Kconfig"
source "drivers/timer/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index e7eab66..6900097 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -54,6 +54,7 @@ obj-y += dfu/ obj-$(CONFIG_X86) += pch/ obj-y += rtc/ obj-y += sound/ +obj-y += spmi/ obj-y += timer/ obj-y += tpm/ obj-y += twserial/ diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig new file mode 100644 index 0000000..0b9bd31 --- /dev/null +++ b/drivers/spmi/Kconfig @@ -0,0 +1,10 @@ +menu "SPMI support" + +config SPMI + bool "Enable SPMI bus support" + depends on DM + ---help--- + Select this to enable to support SPMI bus. + SPMI (System Power Management Interface) bus is used + to connect PMIC devices on various SoCs. +endmenu diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile new file mode 100644 index 0000000..99092eb --- /dev/null +++ b/drivers/spmi/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_SPMI) += spmi-uclass.o diff --git a/drivers/spmi/spmi-uclass.c b/drivers/spmi/spmi-uclass.c new file mode 100644 index 0000000..4ddd51b --- /dev/null +++ b/drivers/spmi/spmi-uclass.c @@ -0,0 +1,48 @@ +/* + * SPMI bus uclass driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <dm/root.h> +#include <spmi/spmi.h> +#include <linux/ctype.h> + +DECLARE_GLOBAL_DATA_PTR; + +int spmi_reg_read(struct udevice *dev, int usid, int pid, int reg) +{ + const struct dm_spmi_ops *ops = dev_get_driver_ops(dev); + + if (!ops || !ops->read) + return -ENOSYS; + + return ops->read(dev, usid, pid, reg); +} + +int spmi_reg_write(struct udevice *dev, int usid, int pid, int reg, + uint8_t value) +{ + const struct dm_spmi_ops *ops = dev_get_driver_ops(dev); + + if (!ops || !ops->write) + return -ENOSYS; + + return ops->write(dev, usid, pid, reg, value); +} + +static int spmi_post_bind(struct udevice *dev) +{ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +UCLASS_DRIVER(spmi) = { + .id = UCLASS_SPMI, + .name = "spmi", + .post_bind = spmi_post_bind, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 37c4176..cbf9b2c 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -66,6 +66,7 @@ enum uclass_id { UCLASS_RTC, /* Real time clock device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SPI, /* SPI bus */ + UCLASS_SPMI, /* System Power Management Interface bus */ UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_SPI_GENERIC, /* Generic SPI flash target */ UCLASS_SYSCON, /* System configuration device */ diff --git a/include/spmi/spmi.h b/include/spmi/spmi.h new file mode 100644 index 0000000..65a49bd --- /dev/null +++ b/include/spmi/spmi.h @@ -0,0 +1,47 @@ +#ifndef _SPMI_SPMI_H +#define _SPMI_SPMI_H + +/** + * struct dm_spmi_ops - SPMI device I/O interface + * + * Should be implemented by UCLASS_SPMI device drivers. The standard + * device operations provides the I/O interface for it's childs. + * + * @read: read register 'reg' of slave 'usid' and peripheral 'pid' + * @write: write register 'reg' of slave 'usid' and peripheral 'pid' + * + * Each register is 8-bit, both read and write can return negative values + * on error. + */ +struct dm_spmi_ops { + int (*read)(struct udevice *dev, int usid, int pid, int reg); + int (*write)(struct udevice *dev, int usid, int pid, int reg, + uint8_t value); +}; + +/** + * spmi_reg_read() - read a register from specific slave/peripheral + * + * @dev: SPMI bus to read + * @usid SlaveID + * @pid Peripheral ID + * @reg: Register to read + * @return value read on success or negative value of errno. + */ +int spmi_reg_read(struct udevice *dev, int usid, int pid, int reg); + +/** + * spmi_reg_write() - write a register of specific slave/peripheral + * + * @dev: SPMI bus to write + * @usid SlaveID + * @pid Peripheral ID + * @reg: Register to write + * @value: Value to write + * @return 0 on success or negative value of errno. + */ +int spmi_reg_write(struct udevice *dev, int usid, int pid, int reg, + uint8_t value); + +#endif +

On Thu, Mar 31, 2016 at 11:12:27PM +0200, Mateusz Kulikowski wrote:
Qualcom processors use proprietary bus to talk with PMIC devices - SPMI (System Power Management Interface). On wiring level it is similar to I2C, but on protocol level, it's multi-master and has simple autodetection capabilities. This commit adds simple uclass that provides bus read/write interface.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

This patch adds emulated spmi bus controller with part of pm8916 pmic on it to sandbox and tests validating SPMI uclass.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: - Updated test.dts to include SPMI like sandbox.dts does
Changes in v2: - Rename CONFIG_DM_SPMI -> CONFIG_SPMI - Rename r -> regs, p -> priv - Add reviewed-by - Update binding doc (drop unused bindig)
Changes in v1: None
arch/sandbox/dts/sandbox.dts | 20 ++++ arch/sandbox/dts/test.dts | 20 ++++ configs/sandbox_defconfig | 4 + doc/device-tree-bindings/spmi/spmi-sandbox.txt | 31 +++++ drivers/spmi/Kconfig | 8 ++ drivers/spmi/Makefile | 1 + drivers/spmi/spmi-sandbox.c | 157 +++++++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/spmi.c | 115 ++++++++++++++++++ 9 files changed, 357 insertions(+) create mode 100644 doc/device-tree-bindings/spmi/spmi-sandbox.txt create mode 100644 drivers/spmi/spmi-sandbox.c create mode 100644 test/dm/spmi.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index e3f02bf..2ae4014 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -240,6 +240,26 @@ status = "disabled"; };
+ spmi: spmi@0 { + compatible = "sandbox,spmi"; + #address-cells = <0x1>; + #size-cells = <0x1>; + pm8916@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 0x1>; + #address-cells = <0x1>; + #size-cells = <0x1>; + + spmi_gpios: gpios@c000 { + compatible = "qcom,pm8916-gpio"; + reg = <0xc000 0x400>; + gpio-controller; + gpio-count = <4>; + #gpio-cells = <2>; + gpio-bank-name="spmi"; + }; + }; + }; };
#include "cros-ec-keyboard.dtsi" diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9b8d658..8930009 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -351,6 +351,26 @@ status = "disabled"; };
+ spmi: spmi@0 { + compatible = "sandbox,spmi"; + #address-cells = <0x1>; + #size-cells = <0x1>; + pm8916@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 0x1>; + #address-cells = <0x1>; + #size-cells = <0x1>; + + spmi_gpios: gpios@c000 { + compatible = "qcom,pm8916-gpio"; + reg = <0xc000 0x400>; + gpio-controller; + gpio-count = <4>; + #gpio-cells = <2>; + gpio-bank-name="spmi"; + }; + }; + }; };
#include "sandbox_pmic.dtsi" diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index d69c9fc..bfc8b61 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -31,6 +31,7 @@ CONFIG_ADC_SANDBOX=y CONFIG_BLK=y CONFIG_CLK=y CONFIG_SANDBOX_GPIO=y +CONFIG_PM8916_GPIO=y CONFIG_SYS_I2C_SANDBOX=y CONFIG_CROS_EC_KEYB=y CONFIG_LED=y @@ -59,6 +60,9 @@ CONFIG_PINCONF=y CONFIG_PINCTRL_SANDBOX=y CONFIG_DM_PMIC=y CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_PM8916=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_SANDBOX=y CONFIG_RAM=y diff --git a/doc/device-tree-bindings/spmi/spmi-sandbox.txt b/doc/device-tree-bindings/spmi/spmi-sandbox.txt new file mode 100644 index 0000000..8569a1a --- /dev/null +++ b/doc/device-tree-bindings/spmi/spmi-sandbox.txt @@ -0,0 +1,31 @@ +Sandbox SPMI emulated arbiter. + +This is bus driver for Sandbox. It includes part of emulated pm8916 pmic. + +Required properties: +- compatible: "sandbox,spmi" +- #address-cells: 0x1 - childs slave ID address +- #size-cells: 0x1 + +Example: + +spmi: spmi@0 { + compatible = "sandbox,spmi"; + #address-cells = <0x1>; + #size-cells = <0x1>; + pm8916@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 0x1>; + #address-cells = <0x1>; + #size-cells = <0x1>; + + spmi_gpios: gpios@c000 { + compatible = "qcom,pm8916-gpio"; + reg = <0xc000 0x400>; + gpio-controller; + gpio-count = <4>; + #gpio-cells = <2>; + gpio-bank-name="spmi"; + }; + }; +}; diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index 0b9bd31..c70d675 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -7,4 +7,12 @@ config SPMI Select this to enable to support SPMI bus. SPMI (System Power Management Interface) bus is used to connect PMIC devices on various SoCs. + +config SPMI_SANDBOX + boolean "Support for Sandbox SPMI bus" + depends on SPMI + ---help--- + Demo SPMI bus implementation. Emulates part of PM8916 as single + slave (0) on bus. It has 4 GPIO peripherals, pid 0xC0-0xC3. + endmenu diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile index 99092eb..4ca65a9 100644 --- a/drivers/spmi/Makefile +++ b/drivers/spmi/Makefile @@ -5,3 +5,4 @@ #
obj-$(CONFIG_SPMI) += spmi-uclass.o +obj-$(CONFIG_SPMI_SANDBOX) += spmi-sandbox.o diff --git a/drivers/spmi/spmi-sandbox.c b/drivers/spmi/spmi-sandbox.c new file mode 100644 index 0000000..2f0fea0 --- /dev/null +++ b/drivers/spmi/spmi-sandbox.c @@ -0,0 +1,157 @@ +/* + * Sample SPMI bus driver + * + * It emulates bus with single pm8916-like pmic that has only GPIO reigsters. + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <spmi/spmi.h> +#include <asm/gpio.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define EMUL_GPIO_PID_START 0xC0 +#define EMUL_GPIO_PID_END 0xC3 + +#define EMUL_GPIO_COUNT 4 + +#define EMUL_GPIO_REG_END 0x46 /* Last valid register */ + +#define EMUL_PERM_R 0x1 +#define EMUL_PERM_W 0x2 +#define EMUL_PERM_RW (EMUL_PERM_R | EMUL_PERM_W) + +struct sandbox_emul_fake_regs { + u8 value; + u8 access_mask; + u8 perms; /* Access permissions */ +}; + +struct sandbox_emul_gpio { + struct sandbox_emul_fake_regs r[EMUL_GPIO_REG_END]; /* Fake registers */ +}; + +struct sandbox_spmi_priv { + struct sandbox_emul_gpio gpios[EMUL_GPIO_COUNT]; +}; + +/* Check if valid register was requested */ +static bool check_address_valid(int usid, int pid, int off) +{ + if (usid != 0) + return false; + if (pid < EMUL_GPIO_PID_START || pid > EMUL_GPIO_PID_END) + return false; + if (off > EMUL_GPIO_REG_END) + return false; + return true; +} + +static int sandbox_spmi_write(struct udevice *dev, int usid, int pid, int off, + uint8_t val) +{ + struct sandbox_spmi_priv *priv = dev_get_priv(dev); + struct sandbox_emul_fake_regs *regs; + + if (!check_address_valid(usid, pid, off)) + return -EIO; + + regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */ + + switch (off) { + case 0x40: /* Control */ + val &= regs[off].access_mask; + if (((val & 0x30) == 0x10) || ((val & 0x30) == 0x20)) { + /* out/inout - set status register */ + regs[0x8].value &= ~0x1; + regs[0x8].value |= val & 0x1; + } + break; + default: + if (regs[off].perms & EMUL_PERM_W) + regs[off].value = val & regs[off].access_mask; + } + return 0; +} + +static int sandbox_spmi_read(struct udevice *dev, int usid, int pid, int off) +{ + struct sandbox_spmi_priv *priv = dev_get_priv(dev); + struct sandbox_emul_fake_regs *regs; + + if (!check_address_valid(usid, pid, off)) + return -EIO; + + regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */ + + if (regs[0x46].value == 0) /* Block disabled */ + return 0; + + switch (off) { + case 0x8: /* Status */ + if (regs[0x46].value == 0) /* Block disabled */ + return 0; + return regs[off].value; + default: + if (regs[off].perms & EMUL_PERM_R) + return regs[off].value; + else + return 0; + } +} + +static struct dm_spmi_ops sandbox_spmi_ops = { + .read = sandbox_spmi_read, + .write = sandbox_spmi_write, +}; + +static int sandbox_spmi_probe(struct udevice *dev) +{ + struct sandbox_spmi_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < EMUL_GPIO_COUNT; ++i) { + struct sandbox_emul_fake_regs *regs = priv->gpios[i].r; + regs[4].perms = EMUL_PERM_R; + regs[4].value = 0x10; + regs[5].perms = EMUL_PERM_R; + regs[5].value = 0x5; + regs[8].access_mask = 0x81; + regs[8].perms = EMUL_PERM_RW; + regs[0x40].access_mask = 0x7F; + regs[0x40].perms = EMUL_PERM_RW; + regs[0x41].access_mask = 7; + regs[0x41].perms = EMUL_PERM_RW; + regs[0x42].access_mask = 7; + regs[0x42].perms = EMUL_PERM_RW; + regs[0x42].value = 0x4; + regs[0x45].access_mask = 0x3F; + regs[0x45].perms = EMUL_PERM_RW; + regs[0x45].value = 0x1; + regs[0x46].access_mask = 0x80; + regs[0x46].perms = EMUL_PERM_RW; + regs[0x46].value = 0x80; + } + return 0; +} + +static const struct udevice_id sandbox_spmi_ids[] = { + { .compatible = "sandbox,spmi" }, + { } +}; + +U_BOOT_DRIVER(msm_spmi) = { + .name = "sandbox_spmi", + .id = UCLASS_SPMI, + .of_match = sandbox_spmi_ids, + .ops = &sandbox_spmi_ops, + .probe = sandbox_spmi_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_spmi_priv), +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index df2d71f..9a11ae0 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -37,4 +37,5 @@ obj-$(CONFIG_DM_REGULATOR) += regulator.o obj-$(CONFIG_TIMER) += timer.o obj-$(CONFIG_DM_VIDEO) += video.o obj-$(CONFIG_ADC) += adc.o +obj-$(CONFIG_SPMI) += spmi.o endif diff --git a/test/dm/spmi.c b/test/dm/spmi.c new file mode 100644 index 0000000..81767f6 --- /dev/null +++ b/test/dm/spmi.c @@ -0,0 +1,115 @@ +/* + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <dm.h> +#include <dm/device.h> +#include <dm/root.h> +#include <dm/test.h> +#include <dm/util.h> +#include <power/pmic.h> +#include <spmi/spmi.h> +#include <asm/gpio.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Test if bus childs got probed propperly*/ +static int dm_test_spmi_probe(struct unit_test_state *uts) +{ + const char *name = "spmi@0"; + struct udevice *bus, *dev; + + ut_assertok(uclass_get_device(UCLASS_SPMI, 0, &bus)); + + /* Check bus name */ + ut_asserteq_str(name, bus->name); + + /* Check that it has some devices */ + ut_asserteq(device_has_children(bus), true); + + ut_assertok(device_find_first_child(bus, &dev)); + + /* There should be at least one child */ + ut_assertnonnull(dev); + + /* Check that only PMICs are connected to the bus */ + while (dev) { + ut_asserteq(device_get_uclass_id(dev), UCLASS_PMIC); + device_find_next_child(&dev); + } + + return 0; +} +DM_TEST(dm_test_spmi_probe, DM_TESTF_SCAN_FDT); + +/* Test if it's possible to read bus directly and indirectly */ +static int dm_test_spmi_access(struct unit_test_state *uts) +{ + const char *pmic_name = "pm8916@0"; + struct udevice *bus, *pmic; + + ut_assertok(uclass_get_device(UCLASS_SPMI, 0, &bus)); + + ut_assertok(device_get_child(bus, 0, &pmic)); + + /* Sanity check if it's proper PMIC */ + ut_asserteq_str(pmic_name, pmic->name); + + /* Read PMIC ID reg using SPMI bus - it assumes it has slaveID == 0*/ + ut_asserteq(spmi_reg_read(bus, 0, 0xC0, 0x4), 0x10); + ut_asserteq(spmi_reg_read(bus, 0, 0xC0, 0x5), 0x5); + + /* Read ID reg via pmic interface */ + ut_asserteq(pmic_reg_read(pmic, 0xC004), 0x10); + ut_asserteq(pmic_reg_read(pmic, 0xC005), 0x5); + + return 0; +} +DM_TEST(dm_test_spmi_access, DM_TESTF_SCAN_FDT); + + +/* Test if it's possible to access GPIO that should be in pmic */ +static int dm_test_spmi_access_peripheral(struct unit_test_state *uts) +{ + struct udevice *dev; + unsigned int offset, gpio; + const char *name; + int offset_count; + + /* Get second pin of PMIC GPIO */ + ut_assertok(gpio_lookup_name("spmi1", &dev, &offset, &gpio)); + + /* Check if PMIC is parent */ + ut_asserteq(device_get_uclass_id(dev->parent), UCLASS_PMIC); + + /* This should be second gpio */ + ut_asserteq(1, offset); + + name = gpio_get_bank_info(dev, &offset_count); + + /* Check bank name */ + ut_asserteq_str("spmi", name); + /* Check pin count */ + ut_asserteq(4, offset_count); + + ut_assertok(gpio_request(gpio, "testing")); + + /* Try to set/clear gpio */ + ut_assertok(gpio_direction_output(gpio, 0)); + ut_asserteq(gpio_get_value(gpio), 0); + ut_assertok(gpio_direction_output(gpio, 1)); + ut_asserteq(gpio_get_value(gpio), 1); + ut_assertok(gpio_direction_input(gpio)); + ut_asserteq(gpio_get_value(gpio), 1); + + ut_assertok(gpio_free(gpio)); + + return 0; +} +DM_TEST(dm_test_spmi_access_peripheral, DM_TESTF_SCAN_FDT); +

On Thu, Mar 31, 2016 at 11:12:28PM +0200, Mateusz Kulikowski wrote:
This patch adds emulated spmi bus controller with part of pm8916 pmic on it to sandbox and tests validating SPMI uclass.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
... but note that the tests fail currently, please fix :)

On 04/01/2016 08:04 PM, Tom Rini wrote:
On Thu, Mar 31, 2016 at 11:12:28PM +0200, Mateusz Kulikowski wrote:
This patch adds emulated spmi bus controller with part of pm8916 pmic on it to sandbox and tests validating SPMI uclass.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
... but note that the tests fail currently, please fix :)
Yup, my automated build/test systems all started failing due to this. You can easily reproduce this by running:
./test/py/test.py --bd sandbox --build
Perhaps it's worth disabling these tests until they pass, so that any other new failures that arise are more easily noticed?
Unfortunately, this issue has already been picked up by u-boot-i2c.git/master and u-boot-usb.git/master:-(

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
Hi,
On 04.04.2016 17:49, Stephen Warren wrote:
On 04/01/2016 08:04 PM, Tom Rini wrote:
On Thu, Mar 31, 2016 at 11:12:28PM +0200, Mateusz Kulikowski wrote:
This patch adds emulated spmi bus controller with part of pm8916 pmic on it to sandbox and tests validating SPMI uclass.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
... but note that the tests fail currently, please fix :)
Yup, my automated build/test systems all started failing due to this. You can easily reproduce this by running:
Working on it. Weird thing is - it works on sandbox.dtb, and segfaults on test.dtb even if entries are exactly the same :0
Regards, Mateusz

On 04/04/2016 10:19 AM, Mateusz Kulikowski wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
Hi,
On 04.04.2016 17:49, Stephen Warren wrote:
On 04/01/2016 08:04 PM, Tom Rini wrote:
On Thu, Mar 31, 2016 at 11:12:28PM +0200, Mateusz Kulikowski wrote:
This patch adds emulated spmi bus controller with part of pm8916 pmic on it to sandbox and tests validating SPMI uclass.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
... but note that the tests fail currently, please fix :)
Yup, my automated build/test systems all started failing due to this. You can easily reproduce this by running:
Working on it. Weird thing is - it works on sandbox.dtb, and segfaults on test.dtb even if entries are exactly the same :0
I wonder if there's some kind of memory corruption going on; IIRC I checked out the committed version of this patch in u-boot/master's history, and 3 tests failed, but by the time you reach the current u-boot/master, only 2 tests fail, and I don't think there were any more spmi-related commits between the two. That would indicate some kind of outside interference, which would also be consistent with your unusual findings.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
Hi,
On 04.04.2016 19:09, Stephen Warren wrote:
On 04/04/2016 10:19 AM, Mateusz Kulikowski wrote:
[...]
... but note that the tests fail currently, please fix :)
Yup, my automated build/test systems all started failing due to this. You can easily reproduce this by running:
Working on it. Weird thing is - it works on sandbox.dtb, and segfaults on test.dtb even if entries are exactly the same :0
I wonder if there's some kind of memory corruption going on; IIRC I checked out the committed version of this patch in u-boot/master's history, and 3 tests failed, but by the time you reach the current u-boot/master, only 2 tests fail, and I don't think there were any more spmi-related commits between the two. That would indicate some kind of outside interference, which would also be consistent with your unusual findings.
Yeah.. we all love off-by-one don't we? ;)
Patch already posted - please check it if you want to.
Regards, Mateusz

On Mon, Apr 04, 2016 at 09:49:06AM -0600, Stephen Warren wrote:
On 04/01/2016 08:04 PM, Tom Rini wrote:
On Thu, Mar 31, 2016 at 11:12:28PM +0200, Mateusz Kulikowski wrote:
This patch adds emulated spmi bus controller with part of pm8916 pmic on it to sandbox and tests validating SPMI uclass.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
... but note that the tests fail currently, please fix :)
Yup, my automated build/test systems all started failing due to this. You can easily reproduce this by running:
./test/py/test.py --bd sandbox --build
Perhaps it's worth disabling these tests until they pass, so that any other new failures that arise are more easily noticed?
Unfortunately, this issue has already been picked up by u-boot-i2c.git/master and u-boot-usb.git/master:-(
So yes. I'm not quite yet comfortable making test.py failures a hard failure (I only noticed since I was re-checking the CMDLINE stuff). I'm open to changing this stance in the future as I really ought to try and plug my local workflow into some CI too along with my more manual setups.

Support SPMI arbiter on Qualcomm Snapdragon devices.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Rename DM_SPMI -> SPMI - Rename p -> priv (in write/read) - Fix header ordering (again) - Add reviewed-by
Changes in v1: - add binding documentation and better Kconfig help - Changed a bit mapping - Change include order - Use clrsetbits* where possible - Add one more supported dts id - Handle missing fields in dt properly
doc/device-tree-bindings/spmi/spmi-msm.txt | 26 ++++ drivers/spmi/Kconfig | 7 +- drivers/spmi/Makefile | 1 + drivers/spmi/spmi-msm.c | 189 +++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/spmi/spmi-msm.txt create mode 100644 drivers/spmi/spmi-msm.c
diff --git a/doc/device-tree-bindings/spmi/spmi-msm.txt b/doc/device-tree-bindings/spmi/spmi-msm.txt new file mode 100644 index 0000000..ae47673 --- /dev/null +++ b/doc/device-tree-bindings/spmi/spmi-msm.txt @@ -0,0 +1,26 @@ +Qualcomm SPMI arbiter/bus driver + +This is bus driver for Qualcomm chips that use SPMI to communicate with PMICs. + +Required properties: +- compatible: "qcom,spmi-pmic-arb" +- reg: Register block adresses and sizes for various parts of device: + 1) PMIC arbiter channel mapping base (PMIC_ARB_REG_CHNLn) + 2) SPMI write command (master) registers (PMIC_ARB_CORE_SW_DEC_CHANNELS) + 3) SPMI read command (observer) registers (PMIC_ARB_CORE_REGISTERS_OBS) + +Optional properties (if not set by parent): +- #address-cells: 0x1 - childs slave ID address +- #size-cells: 0x1 + +All PMICs should be placed as a child nodes of bus arbiter. +Automatic detection of childs is currently not supported. + +Example: + +spmi@200f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x200f800 0x200 0x2400000 0x400000 0x2c00000 0x400000>; + #address-cells = <0x1>; + #size-cells = <0x1>; +}; diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index c70d675..8d25b45 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -8,11 +8,16 @@ config SPMI SPMI (System Power Management Interface) bus is used to connect PMIC devices on various SoCs.
+config SPMI_MSM + boolean "Support Qualcomm SPMI bus" + depends on SPMI + ---help--- + Support SPMI bus implementation found on Qualcomm Snapdragon SoCs. + config SPMI_SANDBOX boolean "Support for Sandbox SPMI bus" depends on SPMI ---help--- Demo SPMI bus implementation. Emulates part of PM8916 as single slave (0) on bus. It has 4 GPIO peripherals, pid 0xC0-0xC3. - endmenu diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile index 4ca65a9..c0b1220 100644 --- a/drivers/spmi/Makefile +++ b/drivers/spmi/Makefile @@ -5,4 +5,5 @@ #
obj-$(CONFIG_SPMI) += spmi-uclass.o +obj-$(CONFIG_SPMI_MSM) += spmi-msm.o obj-$(CONFIG_SPMI_SANDBOX) += spmi-sandbox.o diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c new file mode 100644 index 0000000..0cef505 --- /dev/null +++ b/drivers/spmi/spmi-msm.c @@ -0,0 +1,189 @@ +/* + * Qualcomm SPMI bus driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * Loosely based on Little Kernel driver + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <asm/io.h> +#include <spmi/spmi.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define ARB_CHANNEL_OFFSET(n) (0x4 * (n)) +#define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000) + +#define SPMI_REG_CMD0 0x0 +#define SPMI_REG_CONFIG 0x4 +#define SPMI_REG_STATUS 0x8 +#define SPMI_REG_WDATA 0x10 +#define SPMI_REG_RDATA 0x18 + +#define SPMI_CMD_OPCODE_SHIFT 27 +#define SPMI_CMD_SLAVE_ID_SHIFT 20 +#define SPMI_CMD_ADDR_SHIFT 12 +#define SPMI_CMD_ADDR_OFFSET_SHIFT 4 +#define SPMI_CMD_BYTE_CNT_SHIFT 0 + +#define SPMI_CMD_EXT_REG_WRITE_LONG 0x00 +#define SPMI_CMD_EXT_REG_READ_LONG 0x01 + +#define SPMI_STATUS_DONE 0x1 + +#define SPMI_MAX_CHANNELS 128 +#define SPMI_MAX_SLAVES 16 +#define SPMI_MAX_PERIPH 256 + +struct msm_spmi_priv { + phys_addr_t arb_chnl; /* ARB channel mapping base */ + phys_addr_t spmi_core; /* SPMI core */ + phys_addr_t spmi_obs; /* SPMI observer */ + /* SPMI channel map */ + uint8_t channel_map[SPMI_MAX_SLAVES][SPMI_MAX_PERIPH]; +}; + +static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off, + uint8_t val) +{ + struct msm_spmi_priv *priv = dev_get_priv(dev); + unsigned channel; + uint32_t reg = 0; + + if (usid >= SPMI_MAX_SLAVES) + return -EIO; + if (pid >= SPMI_MAX_PERIPH) + return -EIO; + + channel = priv->channel_map[usid][pid]; + + /* Disable IRQ mode for the current channel*/ + writel(0x0, priv->spmi_core + SPMI_CH_OFFSET(channel) + + SPMI_REG_CONFIG); + + /* Write single byte */ + writel(val, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_WDATA); + + /* Prepare write command */ + reg |= SPMI_CMD_EXT_REG_WRITE_LONG << SPMI_CMD_OPCODE_SHIFT; + reg |= (usid << SPMI_CMD_SLAVE_ID_SHIFT); + reg |= (pid << SPMI_CMD_ADDR_SHIFT); + reg |= (off << SPMI_CMD_ADDR_OFFSET_SHIFT); + reg |= 1; /* byte count */ + + /* Send write command */ + writel(reg, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0); + + /* Wait till CMD DONE status */ + reg = 0; + while (!reg) { + reg = readl(priv->spmi_core + SPMI_CH_OFFSET(channel) + + SPMI_REG_STATUS); + } + + if (reg ^ SPMI_STATUS_DONE) { + printf("SPMI write failure.\n"); + return -EIO; + } + + return 0; +} + +static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off) +{ + struct msm_spmi_priv *priv = dev_get_priv(dev); + unsigned channel; + uint32_t reg = 0; + + if (usid >= SPMI_MAX_SLAVES) + return -EIO; + if (pid >= SPMI_MAX_PERIPH) + return -EIO; + + channel = priv->channel_map[usid][pid]; + + /* Disable IRQ mode for the current channel*/ + writel(0x0, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG); + + /* Prepare read command */ + reg |= SPMI_CMD_EXT_REG_READ_LONG << SPMI_CMD_OPCODE_SHIFT; + reg |= (usid << SPMI_CMD_SLAVE_ID_SHIFT); + reg |= (pid << SPMI_CMD_ADDR_SHIFT); + reg |= (off << SPMI_CMD_ADDR_OFFSET_SHIFT); + reg |= 1; /* byte count */ + + /* Request read */ + writel(reg, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0); + + /* Wait till CMD DONE status */ + reg = 0; + while (!reg) { + reg = readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) + + SPMI_REG_STATUS); + } + + if (reg ^ SPMI_STATUS_DONE) { + printf("SPMI read failure.\n"); + return -EIO; + } + + /* Read the data */ + return readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) + + SPMI_REG_RDATA) & 0xFF; +} + +static struct dm_spmi_ops msm_spmi_ops = { + .read = msm_spmi_read, + .write = msm_spmi_write, +}; + +static int msm_spmi_probe(struct udevice *dev) +{ + struct udevice *parent = dev->parent; + struct msm_spmi_priv *priv = dev_get_priv(dev); + int i; + + priv->arb_chnl = dev_get_addr(dev); + priv->spmi_core = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, + parent->of_offset, + dev->of_offset, + "reg", 1, NULL); + priv->spmi_obs = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, + parent->of_offset, + dev->of_offset, "reg", + 2, NULL); + if (priv->arb_chnl == FDT_ADDR_T_NONE || + priv->spmi_core == FDT_ADDR_T_NONE || + priv->spmi_obs == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Scan peripherals connected to each SPMI channel */ + for (i = 0; i < SPMI_MAX_CHANNELS ; i++) { + uint32_t periph = readl(priv->arb_chnl + ARB_CHANNEL_OFFSET(i)); + uint8_t slave_id = (periph & 0xf0000) >> 16; + uint8_t pid = (periph & 0xff00) >> 8; + + priv->channel_map[slave_id][pid] = i; + } + return 0; +} + +static const struct udevice_id msm_spmi_ids[] = { + { .compatible = "qcom,spmi-pmic-arb" }, + { } +}; + +U_BOOT_DRIVER(msm_spmi) = { + .name = "msm_spmi", + .id = UCLASS_SPMI, + .of_match = msm_spmi_ids, + .ops = &msm_spmi_ops, + .probe = msm_spmi_probe, + .priv_auto_alloc_size = sizeof(struct msm_spmi_priv), +};

On Thu, Mar 31, 2016 at 11:12:29PM +0200, Mateusz Kulikowski wrote:
Support SPMI arbiter on Qualcomm Snapdragon devices.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

This PMIC is connected on SPMI bus so needs SPMI support enabled.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Add reviewed-by - Reordered Kconfig & Makefile (to keep alphabetical ordering) - Added link to dt binding @ help
Changes in v1: - Added dt bindings - Reoder includes - Replaced extract_* macros with ordinary shift/mask - Added error checking and whitespaces in probe
doc/device-tree-bindings/pmic/pm8916.txt | 18 ++++++ drivers/power/pmic/Kconfig | 16 ++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pm8916.c | 96 ++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 doc/device-tree-bindings/pmic/pm8916.txt create mode 100644 drivers/power/pmic/pm8916.c
diff --git a/doc/device-tree-bindings/pmic/pm8916.txt b/doc/device-tree-bindings/pmic/pm8916.txt new file mode 100644 index 0000000..15c598b --- /dev/null +++ b/doc/device-tree-bindings/pmic/pm8916.txt @@ -0,0 +1,18 @@ +Qualcomm pm8916 PMIC + +This PMIC is connected using SPMI bus so should be child of SPMI bus controller. + +Required properties: +- compatible: "qcom,spmi-pmic"; +- reg: SPMI Slave ID, size (ignored) +- #address-cells: 0x1 (peripheral ID) +- #size-cells: 0x1 (size of peripheral register space) + +Example: + +pm8916@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 0x1>; + #address-cells = <0x1>; + #size-cells = <0x1>; +}; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 7f69ae1..69f8d51 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -54,6 +54,22 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations.
+config PMIC_PM8916 + bool "Enable Driver Model for Qualcomm PM8916 PMIC" + depends on DM_PMIC + ---help--- + The PM8916 is a PMIC connected to one (or several) processors + with SPMI bus. It has 2 slaves with several peripherals: + - 18x LDO + - 4x GPIO + - Power and Reset buttons + - Watchdog + - RTC + - Vibrator drivers + - Others + + Driver binding info: doc/device-tree-bindings/pmic/pm8916.txt + config PMIC_RK808 bool "Enable support for Rockchip PMIC RK808" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index c6e8d0c..52b4f71 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o +obj-$(CONFIG_PMIC_PM8916) += pm8916.o obj-$(CONFIG_PMIC_RK808) += rk808.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o diff --git a/drivers/power/pmic/pm8916.c b/drivers/power/pmic/pm8916.c new file mode 100644 index 0000000..9acf5f5 --- /dev/null +++ b/drivers/power/pmic/pm8916.c @@ -0,0 +1,96 @@ +/* + * Qualcomm pm8916 pmic driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <dm.h> +#include <dm/root.h> +#include <power/pmic.h> +#include <spmi/spmi.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define PID_SHIFT 8 +#define PID_MASK (0xFF << PID_SHIFT) +#define REG_MASK 0xFF + +struct pm8916_priv { + uint16_t usid; /* Slave ID on SPMI bus */ +}; + +static int pm8916_reg_count(struct udevice *dev) +{ + return 0xFFFF; +} + +static int pm8916_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + struct pm8916_priv *priv = dev_get_priv(dev); + + if (len != 1) + return -EINVAL; + + return spmi_reg_write(dev->parent, priv->usid, + (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK, + *buff); +} + +static int pm8916_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + struct pm8916_priv *priv = dev_get_priv(dev); + int val; + + if (len != 1) + return -EINVAL; + + val = spmi_reg_read(dev->parent, priv->usid, + (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK); + + if (val < 0) + return val; + *buff = val; + return 0; +} + +static struct dm_pmic_ops pm8916_ops = { + .reg_count = pm8916_reg_count, + .read = pm8916_read, + .write = pm8916_write, +}; + +static const struct udevice_id pm8916_ids[] = { + { .compatible = "qcom,spmi-pmic" }, + { } +}; + +static int pm8916_probe(struct udevice *dev) +{ + struct pm8916_priv *priv = dev_get_priv(dev); + + priv->usid = dev_get_addr(dev); + + if (priv->usid == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + + +static int pm8916_bind(struct udevice *dev) +{ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +U_BOOT_DRIVER(pmic_pm8916) = { + .name = "pmic_pm8916", + .id = UCLASS_PMIC, + .of_match = pm8916_ids, + .bind = pm8916_bind, + .probe = pm8916_probe, + .ops = &pm8916_ops, + .priv_auto_alloc_size = sizeof(struct pm8916_priv), +};

On Thu, Mar 31, 2016 at 11:12:30PM +0200, Mateusz Kulikowski wrote:
This PMIC is connected on SPMI bus so needs SPMI support enabled.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

This driver supports GPIOs present on PM8916 PMIC. There are 2 device drivers inside: - GPIO driver (4 "generic" GPIOs) - Keypad driver that presents itself as GPIO with 2 inputs (power and reset)
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: - Add Reviewed-by
Changes in v1: - Add binding doc - Fixed inlcude ordering - Merged direction_input and direction_output functions - gpio_get: use switch instead of stacked if - use pmic_clrsetbits - add possibility to change prwkey bank name - Handle invalid bindings - Sanity HW check (i.e. check type/subtype registers)
doc/device-tree-bindings/gpio/pm8916_gpio.txt | 48 ++++ drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/pm8916_gpio.c | 302 ++++++++++++++++++++++++++ 4 files changed, 361 insertions(+) create mode 100644 doc/device-tree-bindings/gpio/pm8916_gpio.txt create mode 100644 drivers/gpio/pm8916_gpio.c
diff --git a/doc/device-tree-bindings/gpio/pm8916_gpio.txt b/doc/device-tree-bindings/gpio/pm8916_gpio.txt new file mode 100644 index 0000000..58185b8 --- /dev/null +++ b/doc/device-tree-bindings/gpio/pm8916_gpio.txt @@ -0,0 +1,48 @@ +Driver for part of pm8916 PMIC - gpio and power/reset keys + +This device should be child of SPMI pmic. + +1) GPIO driver + +Required properties: +- compatible: "qcom,pm8916-gpio" +- reg: peripheral ID, size of register block +- gpio-controller +- gpio-count: number of GPIOs +- #gpio-cells: 2 + +Optional properties: +- gpio-bank-name: name of bank (as default "pm8916" is used) + +Example: + +pmic_gpios: gpios@c000 { + compatible = "qcom,pm8916-gpio"; + reg = <0xc000 0x400>; + gpio-controller; + gpio-count = <4>; + #gpio-cells = <2>; + gpio-bank-name="pmic"; +}; + + +2) Power/Reset key driver + +Required properties: +- compatible: "qcom,pm8916-pwrkey" +- reg: peripheral ID, size of register block +- gpio-controller +- #gpio-cells: 2 + +Optional properties: +- gpio-bank-name: name of bank (as default "pm8916_key" is used) + + +Example: + +pmic_pon: pon@800 { + compatible = "qcom,pm8916-pwrkey"; + reg = <0x800 0x96>; + #gpio-cells = <2>; + gpio-controller; +}; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4d9e74c..f56a606 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -69,6 +69,16 @@ config MSM_GPIO - APQ8016 - MSM8916
+config PM8916_GPIO + bool "Qualcomm PM8916 PMIC GPIO/keypad driver" + depends on DM_GPIO && PMIC_PM8916 + help + Support for GPIO pins and power/reset buttons found on + Qualcomm PM8916 PMIC. + Default name for GPIO bank is "pm8916". + Power and reset buttons are placed in "pm8916_key" bank and + have gpio numbers 0 and 1 respectively. + config ROCKCHIP_GPIO bool "Rockchip GPIO driver" depends on DM_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4162c3c..4f071c4 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o +obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o diff --git a/drivers/gpio/pm8916_gpio.c b/drivers/gpio/pm8916_gpio.c new file mode 100644 index 0000000..1abab7f --- /dev/null +++ b/drivers/gpio/pm8916_gpio.c @@ -0,0 +1,302 @@ +/* + * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <power/pmic.h> +#include <spmi/spmi.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <linux/bitops.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Register offset for each gpio */ +#define REG_OFFSET(x) ((x) * 0x100) + +/* Register maps */ + +/* Type and subtype are shared for all pm8916 peripherals */ +#define REG_TYPE 0x4 +#define REG_SUBTYPE 0x5 + +#define REG_STATUS 0x08 +#define REG_STATUS_VAL_MASK 0x1 + +/* MODE_CTL */ +#define REG_CTL 0x40 +#define REG_CTL_MODE_MASK 0x70 +#define REG_CTL_MODE_INPUT 0x00 +#define REG_CTL_MODE_INOUT 0x20 +#define REG_CTL_MODE_OUTPUT 0x10 +#define REG_CTL_OUTPUT_MASK 0x0F + +#define REG_DIG_VIN_CTL 0x41 +#define REG_DIG_VIN_VIN0 0 + +#define REG_DIG_PULL_CTL 0x42 +#define REG_DIG_PULL_NO_PU 0x5 + +#define REG_DIG_OUT_CTL 0x45 +#define REG_DIG_OUT_CTL_CMOS (0x0 << 4) +#define REG_DIG_OUT_CTL_DRIVE_L 0x1 + +#define REG_EN_CTL 0x46 +#define REG_EN_CTL_ENABLE (1 << 7) + +struct pm8916_gpio_bank { + uint16_t pid; /* Peripheral ID on SPMI bus */ +}; + +static int pm8916_gpio_set_direction(struct udevice *dev, unsigned offset, + bool input, int value) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + int ret; + + /* Disable the GPIO */ + ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, + REG_EN_CTL_ENABLE, 0); + if (ret < 0) + return ret; + + /* Select the mode */ + if (input) + ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, + REG_CTL_MODE_INPUT); + else + ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, + REG_CTL_MODE_INOUT | (value ? 1 : 0)); + if (ret < 0) + return ret; + + /* Set the right pull (no pull) */ + ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL, + REG_DIG_PULL_NO_PU); + if (ret < 0) + return ret; + + /* Configure output pin drivers if needed */ + if (!input) { + /* Select the VIN - VIN0, pin is input so it doesn't matter */ + ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL, + REG_DIG_VIN_VIN0); + if (ret < 0) + return ret; + + /* Set the right dig out control */ + ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL, + REG_DIG_OUT_CTL_CMOS | + REG_DIG_OUT_CTL_DRIVE_L); + if (ret < 0) + return ret; + } + + /* Enable the GPIO */ + return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0, + REG_EN_CTL_ENABLE); +} + +static int pm8916_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + return pm8916_gpio_set_direction(dev, offset, true, 0); +} + +static int pm8916_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + return pm8916_gpio_set_direction(dev, offset, false, value); +} + +static int pm8916_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + int reg; + + /* Set the output value of the gpio */ + reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL); + if (reg < 0) + return reg; + + switch (reg & REG_CTL_MODE_MASK) { + case REG_CTL_MODE_INPUT: + return GPIOF_INPUT; + case REG_CTL_MODE_INOUT: /* Fallthrough */ + case REG_CTL_MODE_OUTPUT: + return GPIOF_OUTPUT; + default: + return GPIOF_UNKNOWN; + } +} + +static int pm8916_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + int reg; + + reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS); + if (reg < 0) + return reg; + + return !!(reg & REG_STATUS_VAL_MASK); +} + +static int pm8916_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + + /* Set the output value of the gpio */ + return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL, + REG_CTL_OUTPUT_MASK, !!value); +} + +static const struct dm_gpio_ops pm8916_gpio_ops = { + .direction_input = pm8916_gpio_direction_input, + .direction_output = pm8916_gpio_direction_output, + .get_value = pm8916_gpio_get_value, + .set_value = pm8916_gpio_set_value, + .get_function = pm8916_gpio_get_function, +}; + +static int pm8916_gpio_probe(struct udevice *dev) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + int reg; + + priv->pid = dev_get_addr(dev); + if (priv->pid == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Do a sanity check */ + reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE); + if (reg != 0x10) + return -ENODEV; + + reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE); + if (reg != 0x5) + return -ENODEV; + + return 0; +} + +static int pm8916_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "gpio-count", 0); + uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, + "gpio-bank-name", NULL); + if (uc_priv->bank_name == NULL) + uc_priv->bank_name = "pm8916"; + + return 0; +} + +static const struct udevice_id pm8916_gpio_ids[] = { + { .compatible = "qcom,pm8916-gpio" }, + { } +}; + +U_BOOT_DRIVER(gpio_pm8916) = { + .name = "gpio_pm8916", + .id = UCLASS_GPIO, + .of_match = pm8916_gpio_ids, + .ofdata_to_platdata = pm8916_gpio_ofdata_to_platdata, + .probe = pm8916_gpio_probe, + .ops = &pm8916_gpio_ops, + .priv_auto_alloc_size = sizeof(struct pm8916_gpio_bank), +}; + + +/* Add pmic buttons as GPIO as well - there is no generic way for now */ +#define PON_INT_RT_STS 0x10 +#define KPDPWR_ON_INT_BIT 0 +#define RESIN_ON_INT_BIT 1 + +static int pm8941_pwrkey_get_function(struct udevice *dev, unsigned offset) +{ + return GPIOF_INPUT; +} + +static int pm8941_pwrkey_get_value(struct udevice *dev, unsigned offset) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + + int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS); + + if (reg < 0) + return 0; + + switch (offset) { + case 0: /* Power button */ + return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0; + break; + case 1: /* Reset button */ + default: + return (reg & BIT(RESIN_ON_INT_BIT)) != 0; + break; + } +} + +static const struct dm_gpio_ops pm8941_pwrkey_ops = { + .get_value = pm8941_pwrkey_get_value, + .get_function = pm8941_pwrkey_get_function, +}; + +static int pm8941_pwrkey_probe(struct udevice *dev) +{ + struct pm8916_gpio_bank *priv = dev_get_priv(dev); + int reg; + + priv->pid = dev_get_addr(dev); + if (priv->pid == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Do a sanity check */ + reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE); + if (reg != 0x1) + return -ENODEV; + + reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE); + if (reg != 0x1) + return -ENODEV; + + return 0; +} + +static int pm8941_pwrkey_ofdata_to_platdata(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = 2; + if (uc_priv->bank_name == NULL) + uc_priv->bank_name = "pm8916_key"; + + return 0; +} + +static const struct udevice_id pm8941_pwrkey_ids[] = { + { .compatible = "qcom,pm8916-pwrkey" }, + { } +}; + +U_BOOT_DRIVER(pwrkey_pm8941) = { + .name = "pwrkey_pm8916", + .id = UCLASS_GPIO, + .of_match = pm8941_pwrkey_ids, + .ofdata_to_platdata = pm8941_pwrkey_ofdata_to_platdata, + .probe = pm8941_pwrkey_probe, + .ops = &pm8941_pwrkey_ops, + .priv_auto_alloc_size = sizeof(struct pm8916_gpio_bank), +};

On Thu, Mar 31, 2016 at 11:12:31PM +0200, Mateusz Kulikowski wrote:
This driver supports GPIOs present on PM8916 PMIC. There are 2 device drivers inside:
- GPIO driver (4 "generic" GPIOs)
- Keypad driver that presents itself as GPIO with 2 inputs (power and reset)
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

First supported chip is APQ8016 (that is compatible with MSM8916). Drivers in SoC code: - Reset controller (PSHOLD) - Clock controller (very simple clock configuration for MMC and UART)
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org ---
Changes in v4: - Add sysmap for apq8016 (required to enable MMU)
Changes in v3: None Changes in v2: - Rename DM_SPMI -> SPMI - Make MND divider comments more compact :) - p -> priv - Add reviewed-by - Reordered Kconfig to keep alphabetical order - Renamed reset_sandbox -> msm_reset (typo in reset.c)
Changes in v1: - Fix include order - Cleanup defines (added spaces for readibility) - Base address is integer to avoid casting - Use setbits_* family where possible - Drop unneded comments, added newlines where needed - Check return value of dev_get_addr - Add binding for apq8016 - Cleaned up divider calculation - Drop most of gpio.h (only empty file is needed)
arch/arm/Kconfig | 12 + arch/arm/Makefile | 1 + arch/arm/mach-snapdragon/Kconfig | 6 + arch/arm/mach-snapdragon/Makefile | 9 + arch/arm/mach-snapdragon/clock-apq8016.c | 262 +++++++++++++++++++++ arch/arm/mach-snapdragon/include/mach/gpio.h | 9 + .../mach-snapdragon/include/mach/sysmap-apq8016.h | 14 ++ arch/arm/mach-snapdragon/reset.c | 40 ++++ arch/arm/mach-snapdragon/sysmap-apq8016.c | 30 +++ 9 files changed, 383 insertions(+) create mode 100644 arch/arm/mach-snapdragon/Kconfig create mode 100644 arch/arm/mach-snapdragon/Makefile create mode 100644 arch/arm/mach-snapdragon/clock-apq8016.c create mode 100644 arch/arm/mach-snapdragon/include/mach/gpio.h create mode 100644 arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h create mode 100644 arch/arm/mach-snapdragon/reset.c create mode 100644 arch/arm/mach-snapdragon/sysmap-apq8016.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9851065..fc0c03f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -511,6 +511,16 @@ config RMOBILE bool "Renesas ARM SoCs" select CPU_V7
+config ARCH_SNAPDRAGON + bool "Qualcomm Snapdragon SoCs" + select ARM64 + select DM + select DM_GPIO + select DM_SERIAL + select SPMI + select OF_CONTROL + select OF_SEPARATE + config ARCH_SOCFPGA bool "Altera SOCFPGA family" select CPU_V7 @@ -774,6 +784,8 @@ source "arch/arm/mach-rockchip/Kconfig"
source "arch/arm/mach-s5pc1xx/Kconfig"
+source "arch/arm/mach-snapdragon/Kconfig" + source "arch/arm/mach-socfpga/Kconfig"
source "arch/arm/mach-stm32/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 6defdfb..bb2666c 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -54,6 +54,7 @@ machine-$(CONFIG_ARCH_MVEBU) += mvebu # TODO: rename CONFIG_ORION5X -> CONFIG_ARCH_ORION5X machine-$(CONFIG_ORION5X) += orion5x machine-$(CONFIG_ARCH_S5PC1XX) += s5pc1xx +machine-$(CONFIG_ARCH_SNAPDRAGON) += snapdragon machine-$(CONFIG_ARCH_SOCFPGA) += socfpga machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip machine-$(CONFIG_STM32) += stm32 diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig new file mode 100644 index 0000000..156e733 --- /dev/null +++ b/arch/arm/mach-snapdragon/Kconfig @@ -0,0 +1,6 @@ +if ARCH_SNAPDRAGON + +config SYS_SOC + default "snapdragon" + +endif diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile new file mode 100644 index 0000000..4735844 --- /dev/null +++ b/arch/arm/mach-snapdragon/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clock-apq8016.o +obj-y += sysmap-apq8016.o +obj-y += reset.o diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c new file mode 100644 index 0000000..d548d75 --- /dev/null +++ b/arch/arm/mach-snapdragon/clock-apq8016.c @@ -0,0 +1,262 @@ +/* + * Clock drivers for Qualcomm APQ8016 + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * Based on Little Kernel driver, simplified + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/bitops.h> + +/* GPLL0 clock control registers */ +#define GPLL0_STATUS 0x2101C +#define GPLL0_STATUS_ACTIVE BIT(17) + +#define APCS_GPLL_ENA_VOTE 0x45000 +#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0) + +/* vote reg for blsp1 clock */ +#define APCS_CLOCK_BRANCH_ENA_VOTE 0x45004 +#define APCS_CLOCK_BRANCH_ENA_VOTE_BLSP1 BIT(10) + +/* SDC(n) clock control registers; n=1,2 */ + +/* block control register */ +#define SDCC_BCR(n) ((n * 0x1000) + 0x41000) +/* cmd */ +#define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004) +/* cfg */ +#define SDCC_CFG_RCGR(n) ((n * 0x1000) + 0x41008) +/* m */ +#define SDCC_M(n) ((n * 0x1000) + 0x4100C) +/* n */ +#define SDCC_N(n) ((n * 0x1000) + 0x41010) +/* d */ +#define SDCC_D(n) ((n * 0x1000) + 0x41014) +/* branch control */ +#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018) +#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C) + +/* BLSP1 AHB clock (root clock for BLSP) */ +#define BLSP1_AHB_CBCR 0x1008 + +/* Uart clock control registers */ +#define BLSP1_UART2_BCR 0x3028 +#define BLSP1_UART2_APPS_CBCR 0x302C +#define BLSP1_UART2_APPS_CMD_RCGR 0x3034 +#define BLSP1_UART2_APPS_CFG_RCGR 0x3038 +#define BLSP1_UART2_APPS_M 0x303C +#define BLSP1_UART2_APPS_N 0x3040 +#define BLSP1_UART2_APPS_D 0x3044 + +/* CBCR register fields */ +#define CBCR_BRANCH_ENABLE_BIT BIT(0) +#define CBCR_BRANCH_OFF_BIT BIT(31) + +struct msm_clk_priv { + phys_addr_t base; +}; + +/* Enable clock controlled by CBC soft macro */ +static void clk_enable_cbc(phys_addr_t cbcr) +{ + setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT); + + while (readl(cbcr) & CBCR_BRANCH_OFF_BIT) + ; +} + +/* clock has 800MHz */ +static void clk_enable_gpll0(phys_addr_t base) +{ + if (readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE) + return; /* clock already enabled */ + + setbits_le32(base + APCS_GPLL_ENA_VOTE, APCS_GPLL_ENA_VOTE_GPLL0); + + while ((readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE) == 0) + ; +} + +#define APPS_CMD_RGCR_UPDATE BIT(0) + +/* Update clock command via CMD_RGCR */ +static void clk_bcr_update(phys_addr_t apps_cmd_rgcr) +{ + setbits_le32(apps_cmd_rgcr, APPS_CMD_RGCR_UPDATE); + + /* Wait for frequency to be updated. */ + while (readl(apps_cmd_rgcr) & APPS_CMD_RGCR_UPDATE) + ; +} + +struct bcr_regs { + uintptr_t cfg_rcgr; + uintptr_t cmd_rcgr; + uintptr_t M; + uintptr_t N; + uintptr_t D; +}; + +/* RCGR_CFG register fields */ +#define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */ + +/* sources */ +#define CFG_CLK_SRC_CXO (0 << 8) +#define CFG_CLK_SRC_GPLL0 (1 << 8) +#define CFG_CLK_SRC_MASK (7 << 8) + +/* Mask for supported fields */ +#define CFG_MASK 0x3FFF + +#define CFG_DIVIDER_MASK 0x1F + +/* root set rate for clocks with half integer and MND divider */ +static void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, + int div, int m, int n, int source) +{ + uint32_t cfg; + /* M value for MND divider. */ + uint32_t m_val = m; + /* NOT(N-M) value for MND divider. */ + uint32_t n_val = ~((n)-(m)) * !!(n); + /* NOT 2D value for MND divider. */ + uint32_t d_val = ~(n); + + /* Program MND values */ + writel(m_val, base + regs->M); + writel(n_val, base + regs->N); + writel(d_val, base + regs->D); + + /* setup src select and divider */ + cfg = readl(base + regs->cfg_rcgr); + cfg &= ~CFG_MASK; + cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ + + /* Set the divider; HW permits fraction dividers (+0.5), but + for simplicity, we will support integers only */ + if (div) + cfg |= (2 * div - 1) & CFG_DIVIDER_MASK; + + if (n_val) + cfg |= CFG_MODE_DUAL_EDGE; + + writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */ + + /* Inform h/w to start using the new config. */ + clk_bcr_update(base + regs->cmd_rcgr); +} + +static const struct bcr_regs sdc_regs[] = { + { + .cfg_rcgr = SDCC_CFG_RCGR(1), + .cmd_rcgr = SDCC_CMD_RCGR(1), + .M = SDCC_M(1), + .N = SDCC_N(1), + .D = SDCC_D(1), + }, + { + .cfg_rcgr = SDCC_CFG_RCGR(2), + .cmd_rcgr = SDCC_CMD_RCGR(2), + .M = SDCC_M(2), + .N = SDCC_N(2), + .D = SDCC_D(2), + } +}; + +/* Init clock for SDHCI controller */ +static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) +{ + int div = 8; /* 100MHz default */ + + if (rate == 200000000) + div = 4; + + clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot)); + /* 800Mhz/div, gpll0 */ + clk_rcg_set_rate_mnd(priv->base, &sdc_regs[slot], div, 0, 0, + CFG_CLK_SRC_GPLL0); + clk_enable_gpll0(priv->base); + clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); + + return rate; +} + +static const struct bcr_regs uart2_regs = { + .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR, + .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR, + .M = BLSP1_UART2_APPS_M, + .N = BLSP1_UART2_APPS_N, + .D = BLSP1_UART2_APPS_D, +}; + +/* Init UART clock, 115200 */ +static int clk_init_uart(struct msm_clk_priv *priv) +{ + /* Enable iface clk */ + clk_enable_cbc(priv->base + BLSP1_AHB_CBCR); + /* 7372800 uart block clock @ GPLL0 */ + clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625, + CFG_CLK_SRC_GPLL0); + clk_enable_gpll0(priv->base); + /* Enable core clk */ + clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); + + return 0; +} + +ulong msm_set_periph_rate(struct udevice *dev, int periph, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(dev); + + switch (periph) { + case 0: /* SDC1 */ + return clk_init_sdc(priv, 0, rate); + break; + case 1: /* SDC2 */ + return clk_init_sdc(priv, 1, rate); + break; + case 4: /* UART2 */ + return clk_init_uart(priv); + break; + default: + return 0; + } +} + +static int msm_clk_probe(struct udevice *dev) +{ + struct msm_clk_priv *priv = dev_get_priv(dev); + + priv->base = dev_get_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static struct clk_ops msm_clk_ops = { + .set_periph_rate = msm_set_periph_rate, +}; + +static const struct udevice_id msm_clk_ids[] = { + { .compatible = "qcom,gcc-msm8916" }, + { .compatible = "qcom,gcc-apq8016" }, + { } +}; + +U_BOOT_DRIVER(clk_msm) = { + .name = "clk_msm", + .id = UCLASS_CLK, + .of_match = msm_clk_ids, + .ops = &msm_clk_ops, + .priv_auto_alloc_size = sizeof(struct msm_clk_priv), + .probe = msm_clk_probe, +}; diff --git a/arch/arm/mach-snapdragon/include/mach/gpio.h b/arch/arm/mach-snapdragon/include/mach/gpio.h new file mode 100644 index 0000000..ff949b2 --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/gpio.h @@ -0,0 +1,9 @@ +/* + * Empty gpio.h + * + * This file must stay as arch/arm/include/asm/gpio.h requires it. + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ diff --git a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h new file mode 100644 index 0000000..cdbfad0 --- /dev/null +++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h @@ -0,0 +1,14 @@ +/* + * Qualcomm APQ8916 sysmap + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _MACH_SYSMAP_APQ8016_H +#define _MACH_SYSMAP_APQ8016_H + +#define GICD_BASE 0x0b000000 +#define GICC_BASE 0x0a20c000 + +#endif diff --git a/arch/arm/mach-snapdragon/reset.c b/arch/arm/mach-snapdragon/reset.c new file mode 100644 index 0000000..2627eec --- /dev/null +++ b/arch/arm/mach-snapdragon/reset.c @@ -0,0 +1,40 @@ +/* + * Qualcomm APQ8016 reset controller driver + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <reset.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int msm_reset_request(struct udevice *dev, enum reset_t type) +{ + phys_addr_t addr = dev_get_addr(dev); + if (!addr) + return -EINVAL; + writel(0, addr); + return -EINPROGRESS; +} + +static struct reset_ops msm_reset_ops = { + .request = msm_reset_request, +}; + +static const struct udevice_id msm_reset_ids[] = { + { .compatible = "qcom,pshold" }, + { } +}; + +U_BOOT_DRIVER(msm_reset) = { + .name = "msm_reset", + .id = UCLASS_RESET, + .of_match = msm_reset_ids, + .ops = &msm_reset_ops, +}; diff --git a/arch/arm/mach-snapdragon/sysmap-apq8016.c b/arch/arm/mach-snapdragon/sysmap-apq8016.c new file mode 100644 index 0000000..ef0db2a --- /dev/null +++ b/arch/arm/mach-snapdragon/sysmap-apq8016.c @@ -0,0 +1,30 @@ +/* + * Qualcomm APQ8016 memory map + * + * (C) Copyright 2016 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/armv8/mmu.h> + +static struct mm_region apq8016_mem_map[] = { + { + .base = 0x0UL, /* Peripheral block */ + .size = 0x8000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + .base = 0x80000000UL, /* DDR */ + .size = 0x80000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* List terminator */ + 0, + } +}; + +struct mm_region *mem_map = apq8016_mem_map;

On Thu, Mar 31, 2016 at 11:12:32PM +0200, Mateusz Kulikowski wrote:
First supported chip is APQ8016 (that is compatible with MSM8916). Drivers in SoC code:
- Reset controller (PSHOLD)
- Clock controller (very simple clock configuration for MMC and UART)
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

This commit add support for 96Boards Dragonboard410C. It is board based on APQ8016 Qualcomm SoC, complying with 96boards specification. Features (present out of the box): - 4x Cortex A53 (ARMv8) - 2x USB Host port - 1x USB Device port - 4x LEDs - 1x HDMI connector - 1x uSD connector - 3x buttons (Power, Vol+, Vol-/Reset) - WIFI, Bluetooth with integrated antenna - 8GiB eMMC
U-Boot boots chained with fastboot in 64-bit mode. For detailed build instructions see readme.txt in board directory.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Tested-by: Simon Glass sjg@chromium.org
---
Changes in v4: - Move CONFIG_OF_LIBFDT to defconfig and cleaned it up with savedefconfig
Changes in v3: - readme: Added info on how to enter fastboot mode and that dtbTool is also part of skales. Added more explanation on image generation. - head: Add comment why it's needed, drop MZ EFI signature that makes no sense on this particular SoC, fix confusing entry point name (+update .lds file)
Changes in v2: - Renamed CONFIG_DM_SPMI -> CONFIG_SPMI - Removed extra enter in dragonboard file - Added ULPI* to defconfig - Added MAINTAINERS to board - Cleaned up config file - use distro defaults/environment: - Dropped multiple CONFIG_CMD* and other CONFIG_* - Added distro env/config - Dropped old boot commands - Split dts - pm8916_gpio entries are taken directly from Linux Dragonboard dts; Add handles for u-boot in -uboot.dtsi; They will be removed once gpio drivers are converted to pinctrl. - Renamed some pmic nodes, fixed dragonboard.c to find them properly. - Added header and converted comments to c98-style in head.S - Print error if pmic gpio node is not found.
Changes in v1: - Add better help for dragonboard - Move static structures to board_prepare_usb - Add DM_SPMI to defconfig
arch/arm/dts/Makefile | 2 + arch/arm/dts/dragonboard410c-uboot.dtsi | 28 +++++ arch/arm/dts/dragonboard410c.dts | 148 ++++++++++++++++++++++ arch/arm/mach-snapdragon/Kconfig | 20 +++ board/qualcomm/dragonboard410c/Kconfig | 15 +++ board/qualcomm/dragonboard410c/MAINTAINERS | 6 + board/qualcomm/dragonboard410c/Makefile | 8 ++ board/qualcomm/dragonboard410c/dragonboard410c.c | 131 ++++++++++++++++++++ board/qualcomm/dragonboard410c/head.S | 34 +++++ board/qualcomm/dragonboard410c/readme.txt | 71 +++++++++++ board/qualcomm/dragonboard410c/u-boot.lds | 90 ++++++++++++++ configs/dragonboard410c_defconfig | 26 ++++ include/configs/dragonboard410c.h | 150 +++++++++++++++++++++++ 13 files changed, 729 insertions(+) create mode 100644 arch/arm/dts/dragonboard410c-uboot.dtsi create mode 100644 arch/arm/dts/dragonboard410c.dts create mode 100644 board/qualcomm/dragonboard410c/Kconfig create mode 100644 board/qualcomm/dragonboard410c/MAINTAINERS create mode 100644 board/qualcomm/dragonboard410c/Makefile create mode 100644 board/qualcomm/dragonboard410c/dragonboard410c.c create mode 100644 board/qualcomm/dragonboard410c/head.S create mode 100644 board/qualcomm/dragonboard410c/readme.txt create mode 100644 board/qualcomm/dragonboard410c/u-boot.lds create mode 100644 configs/dragonboard410c_defconfig create mode 100644 include/configs/dragonboard410c.h
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 50bcc0b..5bd4b02 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -107,6 +107,8 @@ dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds-duart.dtb \ fsl-ls1043a-qds-lpuart.dtb \ fsl-ls1043a-rdb.dtb
+dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb + dtb-$(CONFIG_MACH_SUN4I) += \ sun4i-a10-a1000.dtb \ sun4i-a10-ba10-tvbox.dtb \ diff --git a/arch/arm/dts/dragonboard410c-uboot.dtsi b/arch/arm/dts/dragonboard410c-uboot.dtsi new file mode 100644 index 0000000..cc2c175 --- /dev/null +++ b/arch/arm/dts/dragonboard410c-uboot.dtsi @@ -0,0 +1,28 @@ +/* + * U-Boot addition to handle Dragonboard 410c pins + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +&pm8916_gpios { + usb_hub_reset_pm { + gpios = <&pm8916_gpios 2 0>; + }; + + usb_sw_sel_pm { + gpios = <&pm8916_gpios 3 0>; + }; +}; + + +&pm8916_pon { + key_vol_down { + gpios = <&pm8916_pon 1 0>; + }; + + key_power { + gpios = <&pm8916_pon 0 0>; + }; +}; diff --git a/arch/arm/dts/dragonboard410c.dts b/arch/arm/dts/dragonboard410c.dts new file mode 100644 index 0000000..7746622 --- /dev/null +++ b/arch/arm/dts/dragonboard410c.dts @@ -0,0 +1,148 @@ +/* + * Qualcomm APQ8016 based Dragonboard 410C board device tree source + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +#include "skeleton64.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Dragonboard 410c"; + compatible = "qcom,dragonboard", "qcom,apq8016-sbc"; + qcom,msm-id = <0xce 0x0 0xf8 0x0 0xf9 0x0 0xfa 0x0 0xf7 0x0>; + qcom,board-id = <0x10018 0x0>; + #address-cells = <0x2>; + #size-cells = <0x2>; + + memory { + device_type = "memory"; + reg = <0 0x80000000 0 0x3da00000>; + }; + + chosen { + stdout-path = "/soc/serial@78b0000"; + }; + + + soc { + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0x0 0x0 0x0 0xffffffff>; + compatible = "simple-bus"; + + clkc: qcom,gcc@1800000 { + compatible = "qcom,gcc-apq8016"; + reg = <0x1800000 0x80000>; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + + serial@78b0000 { + compatible = "qcom,msm-uartdm-v1.4"; + reg = <0x78b0000 0x200>; + u-boot,dm-pre-reloc; + clock = <&clkc 4>; + }; + + restart@4ab000 { + compatible = "qcom,pshold"; + reg = <0x4ab000 0x4>; + }; + + soc_gpios: pinctrl@1000000 { + compatible = "qcom,apq8016-pinctrl"; + reg = <0x1000000 0x300000>; + gpio-controller; + gpio-count = <122>; + gpio-bank-name="soc"; + #gpio-cells = <1>; + }; + + ehci@78d9000 { + compatible = "qcom,ehci-host"; + reg = <0x78d9000 0x400>; + }; + + sdhci@07824000 { + compatible = "qcom,sdhci-msm-v4"; + reg = <0x7824900 0x11c 0x7824000 0x800>; + bus-width = <0x8>; + index = <0x0>; + non-removable; + clock = <&clkc 0>; + clock-frequency = <100000000>; + }; + + sdhci@07864000 { + compatible = "qcom,sdhci-msm-v4"; + reg = <0x7864900 0x11c 0x7864000 0x800>; + index = <0x1>; + bus-width = <0x4>; + clock = <&clkc 1>; + clock-frequency = <200000000>; + }; + + spmi@200f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x200f800 0x200 0x2400000 0x400000 0x2c00000 0x400000>; + #address-cells = <0x1>; + #size-cells = <0x1>; + pmic0: pm8916@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 0x1>; + #address-cells = <0x1>; + #size-cells = <0x1>; + + pm8916_pon: pm8916_pon@800 { + compatible = "qcom,pm8916-pwrkey"; + reg = <0x800 0x96>; + #gpio-cells = <2>; + gpio-controller; + }; + + pm8916_gpios: pm8916_gpios@c000 { + compatible = "qcom,pm8916-gpio"; + reg = <0xc000 0x400>; + gpio-controller; + gpio-count = <4>; + #gpio-cells = <2>; + gpio-bank-name="pmic"; + }; + }; + + pmic1: pm8916@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 0x1>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + user1 { + label = "green:user1"; + gpios = <&soc_gpios 21 0>; + }; + + user2 { + label = "green:user2"; + gpios = <&soc_gpios 120 0>; + }; + + user3 { + label = "green:user3"; + gpios = <&pm8916_gpios 0 0>; + }; + + user4 { + label = "green:user4"; + gpios = <&pm8916_gpios 1 0>; + }; + }; +}; + +#include "dragonboard410c-uboot.dtsi" diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 156e733..dc7ba21 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -3,4 +3,24 @@ if ARCH_SNAPDRAGON config SYS_SOC default "snapdragon"
+choice + prompt "Snapdragon board select" + +config TARGET_DRAGONBOARD410C + bool "96Boards Dragonboard 410C" + help + Support for 96Boards Dragonboard 410C. This board complies with + 96Board Open Platform Specifications. Features: + - Qualcomm Snapdragon 410C SoC - APQ8016 (4xCortex A53, Adreno 306) + - 1GiB RAM + - 8GiB eMMC, uSD slot + - WiFi, Bluetooth and GPS module + - 2x Host, 1x Device USB port + - HDMI + - 20-pin low speed and 40-pin high speed expanders, 4 LED, 3 buttons + +endchoice + +source "board/qualcomm/dragonboard410c/Kconfig" + endif diff --git a/board/qualcomm/dragonboard410c/Kconfig b/board/qualcomm/dragonboard410c/Kconfig new file mode 100644 index 0000000..03bd7ae --- /dev/null +++ b/board/qualcomm/dragonboard410c/Kconfig @@ -0,0 +1,15 @@ +if TARGET_DRAGONBOARD410C + +config SYS_BOARD + default "dragonboard410c" + +config SYS_VENDOR + default "qualcomm" + +config SYS_SOC + default "apq8016" + +config SYS_CONFIG_NAME + default "dragonboard410c" + +endif diff --git a/board/qualcomm/dragonboard410c/MAINTAINERS b/board/qualcomm/dragonboard410c/MAINTAINERS new file mode 100644 index 0000000..65cb47c --- /dev/null +++ b/board/qualcomm/dragonboard410c/MAINTAINERS @@ -0,0 +1,6 @@ +DRAGONBOARD410C BOARD +M: Mateusz Kulikowski mateusz.kulikowski@gmail.com +S: Maintained +F: board/qualcomm/dragonboard410c/ +F: include/configs/dragonboard410c.h +F: configs/dragonboard410c_defconfig diff --git a/board/qualcomm/dragonboard410c/Makefile b/board/qualcomm/dragonboard410c/Makefile new file mode 100644 index 0000000..cd67808 --- /dev/null +++ b/board/qualcomm/dragonboard410c/Makefile @@ -0,0 +1,8 @@ +# +# (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := dragonboard410c.o +extra-y += head.o diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c new file mode 100644 index 0000000..1fa5664 --- /dev/null +++ b/board/qualcomm/dragonboard410c/dragonboard410c.c @@ -0,0 +1,131 @@ +/* + * Board init file for Dragonboard 410C + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <usb.h> +#include <asm/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + gd->ram_size = PHYS_SDRAM_1_SIZE; + return 0; +} + +void dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; +} + + +int board_prepare_usb(enum usb_init_type type) +{ + static struct udevice *pmic_gpio; + static struct gpio_desc hub_reset, usb_sel; + int ret = 0, node; + + if (!pmic_gpio) { + ret = uclass_get_device_by_name(UCLASS_GPIO, + "pm8916_gpios@c000", + &pmic_gpio); + if (ret < 0) { + printf("Failed to find pm8916_gpios@c000 node.\n"); + return ret; + } + } + + /* Try to request gpios needed to start usb host on dragonboard */ + if (!dm_gpio_is_valid(&hub_reset)) { + node = fdt_subnode_offset(gd->fdt_blob, pmic_gpio->of_offset, + "usb_hub_reset_pm"); + if (node < 0) { + printf("Failed to find usb_hub_reset_pm dt node.\n"); + return node; + } + ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, + &hub_reset, 0); + if (ret < 0) { + printf("Failed to request usb_hub_reset_pm gpio.\n"); + return ret; + } + } + + if (!dm_gpio_is_valid(&usb_sel)) { + node = fdt_subnode_offset(gd->fdt_blob, pmic_gpio->of_offset, + "usb_sw_sel_pm"); + if (node < 0) { + printf("Failed to find usb_sw_sel_pm dt node.\n"); + return 0; + } + ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, + &usb_sel, 0); + if (ret < 0) { + printf("Failed to request usb_sw_sel_pm gpio.\n"); + return ret; + } + } + + if (type == USB_INIT_HOST) { + /* Start USB Hub */ + dm_gpio_set_dir_flags(&hub_reset, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + mdelay(100); + /* Switch usb to host connectors */ + dm_gpio_set_dir_flags(&usb_sel, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + mdelay(100); + } else { /* Device */ + /* Disable hub */ + dm_gpio_set_dir_flags(&hub_reset, GPIOD_IS_OUT); + /* Switch back to device connector */ + dm_gpio_set_dir_flags(&usb_sel, GPIOD_IS_OUT); + } + + return 0; +} + +int board_init(void) +{ + return 0; +} + +/* Check for vol- button - if pressed - stop autoboot */ +int misc_init_r(void) +{ + struct udevice *pon; + struct gpio_desc resin; + int node, ret; + + ret = uclass_get_device_by_name(UCLASS_GPIO, "pm8916_pon@800", &pon); + if (ret < 0) { + printf("Failed to find PMIC pon node. Check device tree\n"); + return 0; + } + + node = fdt_subnode_offset(gd->fdt_blob, pon->of_offset, "key_vol_down"); + if (node < 0) { + printf("Failed to find key_vol_down node. Check device tree\n"); + return 0; + } + + if (gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, &resin, + 0)) { + printf("Failed to request key_vol_down button.\n"); + return 0; + } + + if (dm_gpio_get_value(&resin)) { + setenv("bootdelay", "-1"); + printf("Power button pressed - dropping to console.\n"); + } + + return 0; +} diff --git a/board/qualcomm/dragonboard410c/head.S b/board/qualcomm/dragonboard410c/head.S new file mode 100644 index 0000000..ba29b12 --- /dev/null +++ b/board/qualcomm/dragonboard410c/head.S @@ -0,0 +1,34 @@ +/* + * ARM64 header for proper chain-loading with Little Kernel. + * + * Little Kernel shipped with Dragonboard410C boots standard Linux images for + * ARM64. This file adds header that is required to boot U-Boot properly. + * + * For details see: + * https://www.kernel.org/doc/Documentation/arm64/booting.txt + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> + +.global _arm64_header +_arm64_header: + b _start + .word 0 + /* Image load offset from start of RAM, little-endian */ + .quad CONFIG_SYS_TEXT_BASE-PHYS_SDRAM_1 + /* Effective size of kernel image, little-endian */ + .quad 0 /* 0x60000 - ignored */ + /* Informative flags, little-endian */ + .quad 0 + .quad 0 /* reserved */ + .quad 0 /* reserved */ + .quad 0 /* reserved */ + .byte 0x41 /* Magic number, "ARM\x64" */ + .byte 0x52 + .byte 0x4d + .byte 0x64 + .word 0 /* reserved */ diff --git a/board/qualcomm/dragonboard410c/readme.txt b/board/qualcomm/dragonboard410c/readme.txt new file mode 100644 index 0000000..7fc7c7a --- /dev/null +++ b/board/qualcomm/dragonboard410c/readme.txt @@ -0,0 +1,71 @@ +# +# (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +Build & Run instructions: + +1) Install mkbootimg and dtbTool from + git://codeaurora.org/quic/kernel/skales (15ece94f09 worked for me) +2) Setup CROSS_COMPILE to aarch64 compiler +3) make dragonboard410c_config +4) make +5) generate fake, empty ramdisk (can have 0 bytes) +$ touch rd + +6) Generate qualcomm device tree table with dtbTool [1] +$ dtbTool -o dt.img arch/arm/dts + +7) Generate Android boot image with mkbootimg [2]: +$ mkbootimg --kernel=u-boot-dtb.bin --output=u-boot.img --dt=dt.img \ + --pagesize 2048 --base 0x80000000 --ramdisk=rd --cmdline="" + +8) Enter fastboot (reboot board with vol- button pressed) + +9) Boot it: +$ fastboot boot u-boot.img +or flash as kernel: +$ fastboot flash boot u-boot.img +$ fastboot reboot + + +What is working: +- UART +- GPIO (SoC) +- SD +- eMMC +- Reset +- USB in EHCI mode (usb starts does switch device->host, usb stop does the opposite) +- PMIC GPIOS (but not in generic subsystem) +- PMIC "special" buttons (power, vol-) + +What is not working / known bugs: +- SDHCI is slow (~2.5MiB/s for SD and eMMC) + +[1] To boot any kernel image, Little Kernel requires valid device tree for the +platform it runs on. dtbTool creates device tree table that Little Kernel scans. +Later on proper device tree is passed to next boot stage. +Full device tree is not required to boot u-boot. Enough would be: +/dts-v1/; + +/ { + model = "Qualcomm Technologies, Inc. Dragonboard 410c"; + compatible = "qcom,dragonboard", "qcom,apq8016-sbc"; + qcom,msm-id = <0xce 0x0 0xf8 0x0 0xf9 0x0 0xfa 0x0 0xf7 0x0>; + qcom,board-id = <0x10018 0x0>; + #address-cells = <0x2>; + #size-cells = <0x2>; + chosen { }; + aliases { }; + + memory { + device_type = "memory"; + reg = <0 0x80000000 0 0x3da00000>; + }; +}; + +but for simplicity (and because size of image is not that critical) we use +existing Qualcomm device trees. + +[2] Note that ramdisk is required, even if it is unused. diff --git a/board/qualcomm/dragonboard410c/u-boot.lds b/board/qualcomm/dragonboard410c/u-boot.lds new file mode 100644 index 0000000..6e1c5a8 --- /dev/null +++ b/board/qualcomm/dragonboard410c/u-boot.lds @@ -0,0 +1,90 @@ +/* + * Override linker script for fastboot-readable images + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * Based on arch/arm/cpu/armv8/u-boot.lds (Just add header) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_arm64_header) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(8); + .text : + { + *(.__image_copy_start) + board/qualcomm/dragonboard410c/head.o (.text*) + CPUDIR/start.o (.text*) + *(.text*) + } + + . = ALIGN(8); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(8); + .data : { + *(.data*) + } + + . = ALIGN(8); + + . = .; + + . = ALIGN(8); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + . = ALIGN(8); + + .image_copy_end : + { + *(.__image_copy_end) + } + + . = ALIGN(8); + + .rel_dyn_start : + { + *(.__rel_dyn_start) + } + + .rela.dyn : { + *(.rela*) + } + + .rel_dyn_end : + { + *(.__rel_dyn_end) + } + + _end = .; + + . = ALIGN(8); + + .bss_start : { + KEEP(*(.__bss_start)); + } + + .bss : { + *(.bss*) + . = ALIGN(8); + } + + .bss_end : { + KEEP(*(.__bss_end)); + } + + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig new file mode 100644 index 0000000..2f33a8a --- /dev/null +++ b/configs/dragonboard410c_defconfig @@ -0,0 +1,26 @@ +CONFIG_ARM=y +CONFIG_ARCH_SNAPDRAGON=y +CONFIG_DEFAULT_DEVICE_TREE="dragonboard410c" +CONFIG_SYS_PROMPT="dragonboard410c => " +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_USB=y +CONFIG_CLK=y +CONFIG_MSM_GPIO=y +CONFIG_PM8916_GPIO=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_RESET=y +CONFIG_DM_MMC=y +CONFIG_MSM_SDHCI=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_PM8916=y +CONFIG_MSM_SERIAL=y +CONFIG_SPMI_MSM=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_ULPI=y +CONFIG_USB_STORAGE=y diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h new file mode 100644 index 0000000..a63440f --- /dev/null +++ b/include/configs/dragonboard410c.h @@ -0,0 +1,150 @@ +/* + * Board configuration file for Dragonboard 410C + * + * (C) Copyright 2015 Mateusz Kulikowski mateusz.kulikowski@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIGS_DRAGONBOARD410C_H +#define __CONFIGS_DRAGONBOARD410C_H + +#include <linux/sizes.h> +#include <asm/arch/sysmap-apq8016.h> + +#define CONFIG_IDENT_STRING "\nQualcomm-DragonBoard 410C" + +#define CONFIG_MISC_INIT_R /* To stop autoboot */ + +/* Physical Memory Map */ +#define CONFIG_NR_DRAM_BANKS 1 +#define PHYS_SDRAM_1 0x80000000 +/* 1008 MB (the last ~30Mb are secured for TrustZone by ATF*/ +#define PHYS_SDRAM_1_SIZE 0x3da00000 +#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 +#define CONFIG_SYS_TEXT_BASE 0x80080000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0) +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x80000) +#define CONFIG_SYS_BOOTM_LEN 0x1000000 /* 16MB max kernel size */ + +/* UART */ +#define CONFIG_BAUDRATE 115200 + +/* Generic Timer Definitions */ +#define COUNTER_FREQUENCY 19000000 + +/* This are needed to have proper mmc support */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_SDHCI + +#define CONFIG_SYS_LDSCRIPT "board/qualcomm/dragonboard410c/u-boot.lds" + +/* Fixup - in init code we switch from device to host mode, + * it has to be done after each HCD reset */ +#define CONFIG_EHCI_HCD_INIT_AFTER_RESET + +#define CONFIG_USB_HOST_ETHER /* Enable USB Networking */ + +/* Support all possible USB ethernet dongles */ +#define CONFIG_USB_ETHER_DM9601 +#define CONFIG_USB_ETHER_ASIX +#define CONFIG_USB_ETHER_ASIX88179 +#define CONFIG_USB_ETHER_MCS7830 +#define CONFIG_USB_ETHER_SMSC95XX + +/* Libraries */ +#define CONFIG_MD5 + +/* Extra Commands */ +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_ENV +#define CONFIG_CMD_GPIO +#define CONFIG_CMD_GPT +#define CONFIG_CMD_MD5SUM +#define CONFIG_CMD_MEMINFO +#define CONFIG_CMD_MMC +/* Enable that for switching of boot partitions */ +/* Disabled by default as some sub-commands can brick eMMC */ +/*#define CONFIG_SUPPORT_EMMC_BOOT */ +#define CONFIG_CMD_PART +#define CONFIG_CMD_REGINFO /* Register dump */ +#define CONFIG_CMD_TFTP +#define CONFIG_CMD_TIMER +#define CONFIG_CMD_UNZIP + +/* Partition table support */ +#define HAVE_BLOCK_DEVICE /* Needed for partition commands */ +#define CONFIG_PARTITION_UUIDS + +#include <config_distro_defaults.h> + +/* BOOTP options */ +#define CONFIG_BOOTP_BOOTFILESIZE + +/* Environment - Boot*/ +#define CONFIG_BOOTARGS "console=ttyMSM0,115200n8" + +#define BOOT_TARGET_DEVICES(func) \ + func(USB, usb, 0) \ + func(MMC, mmc, 0) \ + func(MMC, mmc, 1) \ + func(DHCP, dhcp, na) + +#include <config_distro_bootcmd.h> + +/* Does what recovery does */ +#define REFLASH(file, part) \ +"part start mmc 0 "#part" start && "\ +"part size mmc 0 "#part" size && "\ +"tftp $loadaddr "#file" && " \ +"mmc write $loadaddr $start $size && " + + +#define CONFIG_ENV_REFLASH \ +"mmc dev 0 && "\ +"usb start && "\ +"dhcp && "\ +"tftp $loadaddr dragonboard/rescue/gpt_both0.bin && "\ +"mmc write $loadaddr 0 43 && " \ +"mmc rescan && "\ +REFLASH(dragonboard/rescue/NON-HLOS.bin, 1)\ +REFLASH(dragonboard/rescue/sbl1.mbn, 2)\ +REFLASH(dragonboard/rescue/rpm.mbn, 3)\ +REFLASH(dragonboard/rescue/tz.mbn, 4)\ +REFLASH(dragonboard/rescue/hyp.mbn, 5)\ +REFLASH(dragonboard/rescue/sec.dat, 6)\ +REFLASH(dragonboard/rescue/emmc_appsboot.mbn, 7)\ +REFLASH(dragonboard/u-boot.img, 8)\ +"usb stop &&"\ +"echo Reflash completed" + +/* Environment */ +#define CONFIG_EXTRA_ENV_SETTINGS \ + "reflash="CONFIG_ENV_REFLASH"\0"\ + "loadaddr=0x81000000\0" \ + "fdt_high=0xffffffffffffffff\0" \ + "initrd_high=0xffffffffffffffff\0" \ + "linux_image=Image\0" \ + "linux_addr=0x81000000\0"\ + "fdt_image=apq8016-sbc.dtb\0" \ + "fdt_addr=0x83000000\0"\ + "ramdisk_addr=0x84000000\0"\ + BOOTENV + +#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SIZE 0x1000 +#define CONFIG_ENV_VARS_UBOOT_CONFIG +#define CONFIG_SYS_NO_FLASH + +/* Size of malloc() pool */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_8M) + +/* Monitor Command Prompt */ +#define CONFIG_SYS_CBSIZE 512 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT) + 16) +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE +#define CONFIG_SYS_MAXARGS 64 /* max command args */ + +#endif

On Thu, Mar 31, 2016 at 11:12:33PM +0200, Mateusz Kulikowski wrote:
This commit add support for 96Boards Dragonboard410C. It is board based on APQ8016 Qualcomm SoC, complying with 96boards specification. Features (present out of the box):
- 4x Cortex A53 (ARMv8)
- 2x USB Host port
- 1x USB Device port
- 4x LEDs
- 1x HDMI connector
- 1x uSD connector
- 3x buttons (Power, Vol+, Vol-/Reset)
- WIFI, Bluetooth with integrated antenna
- 8GiB eMMC
U-Boot boots chained with fastboot in 64-bit mode. For detailed build instructions see readme.txt in board directory.
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Tested-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Am 31.03.2016 um 23:12 schrieb Mateusz Kulikowski:
diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h new file mode 100644 index 0000000..a63440f --- /dev/null +++ b/include/configs/dragonboard410c.h
[...]
+#include <config_distro_defaults.h>
+/* BOOTP options */ +#define CONFIG_BOOTP_BOOTFILESIZE
+/* Environment - Boot*/ +#define CONFIG_BOOTARGS "console=ttyMSM0,115200n8"
+#define BOOT_TARGET_DEVICES(func) \
- func(USB, usb, 0) \
- func(MMC, mmc, 0) \
- func(MMC, mmc, 1) \
- func(DHCP, dhcp, na)
+#include <config_distro_bootcmd.h>
+/* Does what recovery does */ +#define REFLASH(file, part) \ +"part start mmc 0 "#part" start && "\ +"part size mmc 0 "#part" size && "\ +"tftp $loadaddr "#file" && " \ +"mmc write $loadaddr $start $size && "
+#define CONFIG_ENV_REFLASH \ +"mmc dev 0 && "\ +"usb start && "\ +"dhcp && "\ +"tftp $loadaddr dragonboard/rescue/gpt_both0.bin && "\ +"mmc write $loadaddr 0 43 && " \ +"mmc rescan && "\ +REFLASH(dragonboard/rescue/NON-HLOS.bin, 1)\ +REFLASH(dragonboard/rescue/sbl1.mbn, 2)\ +REFLASH(dragonboard/rescue/rpm.mbn, 3)\ +REFLASH(dragonboard/rescue/tz.mbn, 4)\ +REFLASH(dragonboard/rescue/hyp.mbn, 5)\ +REFLASH(dragonboard/rescue/sec.dat, 6)\ +REFLASH(dragonboard/rescue/emmc_appsboot.mbn, 7)\ +REFLASH(dragonboard/u-boot.img, 8)\ +"usb stop &&"\ +"echo Reflash completed"
+/* Environment */ +#define CONFIG_EXTRA_ENV_SETTINGS \
- "reflash="CONFIG_ENV_REFLASH"\0"\
- "loadaddr=0x81000000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "linux_image=Image\0" \
- "linux_addr=0x81000000\0"\
kernel_addr_r
- "fdt_image=apq8016-sbc.dtb\0" \
- "fdt_addr=0x83000000\0"\
fdt_addr_r
- "ramdisk_addr=0x84000000\0"\
ramdisk_addr_r
These variables that the distro boot depends upon are missing/misnamed.
Regards, Andreas
- BOOTENV
+#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SIZE 0x1000 +#define CONFIG_ENV_VARS_UBOOT_CONFIG +#define CONFIG_SYS_NO_FLASH
+/* Size of malloc() pool */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_8M)
+/* Monitor Command Prompt */ +#define CONFIG_SYS_CBSIZE 512 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE +#define CONFIG_SYS_MAXARGS 64 /* max command args */
+#endif

On Tue, Apr 05, 2016 at 01:13:38AM +0200, Andreas Färber wrote:
Am 31.03.2016 um 23:12 schrieb Mateusz Kulikowski:
+/* Environment */ +#define CONFIG_EXTRA_ENV_SETTINGS \
- "reflash="CONFIG_ENV_REFLASH"\0"\
- "loadaddr=0x81000000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "linux_image=Image\0" \
- "linux_addr=0x81000000\0"\
kernel_addr_r
- "fdt_image=apq8016-sbc.dtb\0" \
- "fdt_addr=0x83000000\0"\
fdt_addr_r
- "ramdisk_addr=0x84000000\0"\
ramdisk_addr_r
These variables that the distro boot depends upon are missing/misnamed.
This reminds me that I had to add scriptaddr to make it run my boot.scr.
Best regards,
Daniel

Am 05.04.2016 um 01:54 schrieb Daniel Glöckner:
On Tue, Apr 05, 2016 at 01:13:38AM +0200, Andreas Färber wrote:
Am 31.03.2016 um 23:12 schrieb Mateusz Kulikowski:
+/* Environment */ +#define CONFIG_EXTRA_ENV_SETTINGS \
- "reflash="CONFIG_ENV_REFLASH"\0"\
- "loadaddr=0x81000000\0" \
- "fdt_high=0xffffffffffffffff\0" \
- "initrd_high=0xffffffffffffffff\0" \
- "linux_image=Image\0" \
Is linux_image used anywhere? dhcp uses boot_script_dhcp.
- "linux_addr=0x81000000\0"\
kernel_addr_r
- "fdt_image=apq8016-sbc.dtb\0" \
fdtfile
- "fdt_addr=0x83000000\0"\
fdt_addr_r
- "ramdisk_addr=0x84000000\0"\
ramdisk_addr_r
These variables that the distro boot depends upon are missing/misnamed.
This reminds me that I had to add scriptaddr to make it run my boot.scr.
I'm testing a local patch but am on travel this week, so maybe Mateusz or someone else is quicker.
Regards, Andreas

- Update MAINTAINERS - Update git-mailrc
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: None Changes in v3: None Changes in v2: - New patch
Changes in v1: None
MAINTAINERS | 11 +++++++++++ doc/git-mailrc | 3 +++ 2 files changed, 14 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS index 32f97b2..6061139 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -125,6 +125,11 @@ F: arch/arm/mach-s5pc1xx/ F: arch/arm/cpu/armv7/s5p-common/ F: arch/arm/include/asm/arch-s3c24x0/
+ARM SNAPDRAGON +M: Mateusz Kulikowski mateusz.kulikowski@gmail.com +S: Maintained +F: arch/arm/mach-snapdragon/ + ARM STM SPEAR #M: Vipin Kumar vipin.kumar@st.com S: Orphaned (Since 2016-02) @@ -396,6 +401,12 @@ F: drivers/mtd/spi/ F: drivers/spi/ F: include/spi*
+SPMI +M: Mateusz Kulikowski mateusz.kulikowski@gmail.com +S: Maintained +F: drivers/spmi/ +F: include/spmi/ + TQ GROUP #M: Martin Krause martin.krause@tq-systems.de S: Orphaned (Since 2016-02) diff --git a/doc/git-mailrc b/doc/git-mailrc index ced7085..1201d4a 100644 --- a/doc/git-mailrc +++ b/doc/git-mailrc @@ -33,6 +33,7 @@ alias lukma Lukasz Majewski l.majewski@samsung.com alias macpaul Macpaul Lin macpaul@andestech.com alias marex Marek Vasut marex@denx.de alias masahiro Masahiro Yamada yamada.masahiro@socionext.com +alias mateusz Mateusz Kulikowski mateusz.kulikowski@gmail.com alias monstr Michal Simek monstr@monstr.eu alias panto Pantelis Antoniou panto@antoniou-consulting.com alias prafulla Prafulla Wadaskar prafulla@marvell.com @@ -67,6 +68,7 @@ alias rmobile uboot, iwamatsu alias s3c samsung alias s5pc samsung alias samsung uboot, prom +alias snapdragon uboot, mateusz alias socfpga uboot, marex, Dinh Nguyen dinguyen@opensource.altera.com alias sunxi uboot, ijc, jwrdegoede alias tegra uboot, sjg, Tom Warren twarren@nvidia.com, Stephen Warren swarren@nvidia.com @@ -127,6 +129,7 @@ alias nand uboot, scottwood alias net uboot, jhersh alias phy uboot, jhersh alias spi uboot, jagan +alias spmi uboot, mateusz alias ubi uboot, hs alias usb uboot, marex alias video uboot, ag

On Thu, Mar 31, 2016 at 11:12:34PM +0200, Mateusz Kulikowski wrote:
- Update MAINTAINERS
- Update git-mailrc
Signed-off-by: Mateusz Kulikowski mateusz.kulikowski@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
participants (6)
-
Andreas Färber
-
Bernhard Nortmann
-
Daniel Glöckner
-
Mateusz Kulikowski
-
Stephen Warren
-
Tom Rini