Skip to contentSkip to conversation

Add support for 96boards Dragonboard410C board

RFC PATCH New Mateusz Kulikowski 6 participants 43 messages Dec 10, 2015 – Dec 28, 2015

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

cover Add support for 96boards Dragonboard410C board

Hi All,

With a slight delay (Sorry Syed) I'm finally ready to show code I've been working recently on.

This series add support for:
- New board - 96board Dragonboard 410C (ARMv8)
- Qualcomm snapdragon architecture (for now only single SoC)
- Some Qualcomm peripherals (UART, GPIO, PMIC including bus, SDHCI, USB...)
- New bus (SPMI)
- It also adds minor function to ehci HCD

Please take a look at it and give me feedback what can be changed so it will be ready for submission.

I'd like to thank Przemyslaw Marczak for doing initial reviews and helping me figure out what is the best approach in some cases.

Notes/Design decisions I made/Issues I have/had (please comment them as well)
0) If I missed someone on CC - please let me know;
If I misused patman - apologize for that - It's my first time with patman.

1) Documentation is missing - dt-bindings, spmi bus documentation. I left it as I expect some redesign after your review.

2) I tried to use DM and Kconfig where possible, but some drivers (USB) depend on subsystems that don't support Kconfig yet

3) There are 3 long-line warnings and some complains about too short Kconfig
- is it ok to ignore lines that are 1-2 characters longer (and making them shorter will cause code to be less readable)?

4) Licensing (@trini)
My code is based on 2 trees:
Linux: https://git.linaro.org/landing-teams/working/qualcomm/kernel.git
LittleKernel: https://git.linaro.org/people/nicolas.dechesne/lk.git
One is GPLv2, other BSD(-clause3 I think).
When tried to figure out how to write drivers, I looked at both drivers, and even if some drivers are totally different than their originals, they are derivative work.
I decided to use Linux license where possible (where I was almost sure I copied/analyzed Linux drivers), left BSD only for SPMI code. Is it ok? Or should I run tool like Protex and drop references where code no longer matches linux/lk codebase (not that I have Protex at home)

5) Clock mapping - I need advice on how to properly access clock controller from devices that need some clocks to be enabled. I want clock controller code to be as simple as possible, but am not sure how to add links to a specific clocks.

6) SPMI: I decided to add new bus. Contrary to other vendors, Qualcomm SoCs use SPMI to talk with PMICs. This is "closed" bus (you need to pay membership to get specification), and I need it to properly describe pmics inside device tree.

7) Snapdragon mach: I added new MACH as my plan is to support more than one Qualcomm SoC/board - hopefully days where U-Boot had no Qualcomm support will be over soon :)

8) I didn't modified Maintainers files - will do that for PATCH v1

9) I moved register offsets to driver files (didn't put them in one big header file. I know it's not common but IMO it's better if drivers are self contained (and there are not many registers anyways).

10) Compilation causes 8 warnings, none in my code:
- 1x in asix88179 driver (format %u expects...)
- 7x in ulpi-viewport code
The problem is - this drivers are handling poorly ARMv8 processors, where sizeof(int) < sizeof(void*) and
sizeof(int) < sizeof(long).
Fix for asix would be trivial, with ULPI it's worse as in my opinion it needs slight redesign (use phaddr_t or something).
Is it ok if I redesign that? Or just ignore warnings or write my own ulpi code (I wanted to avoid code duplication)

Best Regards,
Mateusz

Mateusz Kulikowski (11):
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
ehci: Add support for Qualcomm EHCI
drivers: Add SPMI bus uclass
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

 arch/arm/Kconfig                                   |  12 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/dts/Makefile                              |   2 +
 arch/arm/dts/dragonboard410c.dts                   | 157 +++++++++++
 arch/arm/mach-snapdragon/Kconfig                   |  15 +
 arch/arm/mach-snapdragon/Makefile                  |   8 +
 arch/arm/mach-snapdragon/clock-apq8016.c           | 262 ++++++++++++++++++
 arch/arm/mach-snapdragon/include/mach/gpio.h       |  25 ++
 .../mach-snapdragon/include/mach/sysmap-apq8016.h  |  15 +
 arch/arm/mach-snapdragon/reset.c                   |  40 +++
 board/qualcomm/dragonboard410c/Kconfig             |  15 +
 board/qualcomm/dragonboard410c/Makefile            |   8 +
 board/qualcomm/dragonboard410c/dragonboard410c.c   | 111 ++++++++
 board/qualcomm/dragonboard410c/head.S              |  20 ++
 board/qualcomm/dragonboard410c/readme.txt          |  40 +++
 board/qualcomm/dragonboard410c/u-boot.lds          |  90 ++++++
 configs/dragonboard410c_defconfig                  |  29 ++
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/gpio/Kconfig                               |  14 +
 drivers/gpio/Makefile                              |   3 +-
 drivers/gpio/msm_gpio.c                            | 115 ++++++++
 drivers/gpio/pm8916_gpio.c                         | 306 +++++++++++++++++++++
 drivers/mmc/Kconfig                                |   6 +
 drivers/mmc/Makefile                               |   1 +
 drivers/mmc/msm_sdhci.c                            | 149 ++++++++++
 drivers/power/pmic/Kconfig                         |  14 +
 drivers/power/pmic/Makefile                        |   1 +
 drivers/power/pmic/pm8916.c                        |  92 +++++++
 drivers/serial/Kconfig                             |   5 +
 drivers/serial/Makefile                            |   1 +
 drivers/serial/serial_msm.c                        | 204 ++++++++++++++
 drivers/spmi/Kconfig                               |  16 ++
 drivers/spmi/Makefile                              |   8 +
 drivers/spmi/spmi-msm.c                            | 183 ++++++++++++
 drivers/spmi/spmi-uclass.c                         |  53 ++++
 drivers/usb/host/Kconfig                           |   8 +
 drivers/usb/host/Makefile                          |   1 +
 drivers/usb/host/ehci-hcd.c                        |   6 +
 drivers/usb/host/ehci-msm.c                        | 198 +++++++++++++
 drivers/usb/host/ehci.h                            |   1 +
 include/configs/dragonboard410c.h                  | 184 +++++++++++++
 include/dm/uclass-id.h                             |   1 +
 include/spmi/spmi.h                                |  44 +++
 44 files changed, 2466 insertions(+), 1 deletion(-)
 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 board/qualcomm/dragonboard410c/Kconfig
 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 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-uclass.c
 create mode 100644 drivers/usb/host/ehci-msm.c
 create mode 100644 include/configs/dragonboard410c.h
 create mode 100644 include/spmi/spmi.h
Signature · 1 line
2.5.0
#1 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

This driver works in "new" Data Mover UART mode, so will be compatible with modern Qualcomm chips only.

---

 drivers/serial/Kconfig      |   5 ++
 drivers/serial/Makefile     |   1 +
 drivers/serial/serial_msm.c | 204 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 210 insertions(+)
 create mode 100644 drivers/serial/serial_msm.c
drivers/serial/Kconfig +5 -0
index 1fc287e..f28c093 100644
@@ -223,4 +223,9 @@ config UNIPHIER_SERIAL
 	  If you have a UniPhier based board and want to use the on-chip
 	  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.
 endmenu
drivers/serial/Makefile +1 -0
index dd87147..d052175 100644
@@ -41,6 +41,7 @@ obj-$(CONFIG_MXS_AUART) += mxs_auart.o
 obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
 obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
 obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
+obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_USB_TTY) += usbtty.o
drivers/serial/serial_msm.c new file +204 -0

204 lines not on this page · raw message

Signature · 1 line
2.5.0
#2 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

Hi Mateusz,

Quoted 17 lines · Mateusz Kulikowski

This driver works in "new" Data Mover UART mode, so will be compatible with modern Qualcomm chips only.

---

 drivers/serial/Kconfig      |   5 ++
 drivers/serial/Makefile     |   1 +
 drivers/serial/serial_msm.c | 204 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 210 insertions(+)
 create mode 100644 drivers/serial/serial_msm.c
drivers/serial/Kconfig +0 -0
index 1fc287e..f28c093 100644

drivers/serial/Kconfig config UNIPHIER_SERIAL · line 230

Quoted 8 lines
drivers/serial/Kconfig +5 -0
@@ -223,4 +223,9 @@ config UNIPHIER_SERIAL
          If you have a UniPhier based board and want to use the on-chip
          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.

Any more details? What baud rates does it support? What SoCs use it?

Quoted 28 lines
drivers/serial/Kconfig +0 -0
 endmenu
drivers/serial/Makefile +1 -0
index dd87147..d052175 100644
@@ -41,6 +41,7 @@ obj-$(CONFIG_MXS_AUART) += mxs_auart.o
 obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
 obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
 obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
+obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_USB_TTY) += usbtty.o
drivers/serial/serial_msm.c new file +9 -0
new file mode 100644
index 0000000..13dad33
@@ -0,0 +1,204 @@
+/*
+ * Qualcomm UART driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * UART will work in Data Mover mode.
+ * Based on Linux driver.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+

drivers/serial/serial_msm.c line 19

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <serial.h>
+#include <watchdog.h>

Ordering:

common.h
clk.h
dm.h
errno.h
serial.h
watchdog.h
asm/
linux/

Quoted 76 lines
drivers/serial/serial_msm.c new file +76 -0
+
+/* 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_getc(struct udevice *dev)
+{
+       struct msm_serial_data *p = dev_get_priv(dev);
+       unsigned sr;
+       char c;
+
+       /* There was something buffered */
+       if (p->chars_cnt) {
+               c = p->chars_buf & 0xFF;
+               p->chars_buf >>= 8;
+               p->chars_cnt--;
+               return c;
+       }
+
+       /* Clear error in case of buffer overrun */
+       if (readl(p->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN)
+               writel(UARTDM_CR_CMD_RESET_ERR, p->base + UARTDM_CR);
+
+       /* We need to fetch new character */
+       sr = readl(p->base + UARTDM_SR);
+
+       /* There are at least 4 bytes in fifo */
+       if (sr & UARTDM_SR_RX_READY) {
+               p->chars_buf = readl(p->base + UARTDM_RF);
+               c = p->chars_buf & 0xFF;
+               p->chars_cnt = 3; /* 4 - one read */
+               p->chars_buf >>= 8;
+               return c;
+       }
+
+       /* Check if there is anything in fifo */
+       p->chars_cnt = readl(p->base + UARTDM_RXFS);
+       /* Extract number of characters in UART packing buffer */
+       p->chars_cnt = (p->chars_cnt >> UARTDM_RXFS_BUF_SHIFT) &
+                      UARTDM_RXFS_BUF_MASK;
+       if (!p->chars_cnt)
+               return -EAGAIN;
+

drivers/serial/serial_msm.c line 105

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+       /* There is at least one charcter, move it to fifo */
+       writel(UARTDM_CR_CMD_FORCE_STALE, p->base + UARTDM_CR);
+
+       p->chars_buf = readl(p->base + UARTDM_RF);
+       writel(UARTDM_CR_CMD_RESET_STALE_INT, p->base + UARTDM_CR);
+       writel(0xFFFFFF, p->base + UARTDM_DMRX);
+
+       c = p->chars_buf & 0xFF;
+       p->chars_buf >>= 8;
+       p->chars_cnt--;

Can you not rationalise this code a bit? E.g.

if (no chars in fifo) {
try to get some
}
if (no chars in fifo)
return -EAGAIN
extract char from fifo
return ch;

You seem to have three copies of the same code.

Quoted 35 lines
drivers/serial/serial_msm.c new file +35 -0
+
+       return c;
+}
+
+static int msm_serial_putc(struct udevice *dev, const char ch)
+{
+       struct msm_serial_data *p = dev_get_priv(dev);
+
+       if (!(readl(p->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
+           !(readl(p->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
+               return -EAGAIN;
+
+       writel(UARTDM_CR_CMD_RESET_TX_READY, p->base + UARTDM_CR);
+
+       writel(1, p->base + UARTDM_NCF_TX);
+       writel(ch, p->base + UARTDM_TF);
+       return 0;
+}
+
+static int msm_serial_pending(struct udevice *dev, bool input)
+{
+       struct msm_serial_data *p = dev_get_priv(dev);
+
+       if (input) {
+               if (p->chars_cnt)
+                       return 1;
+               if (readl(p->base + UARTDM_SR) & UARTDM_SR_RX_READY)
+                       return 1;
+               if (readl(p->base + UARTDM_RXFS))
+                       return 1;
+       }
+       return 0;
+}
+
+static const struct dm_serial_ops msm_serial_ops = {

drivers/serial/serial_msm.c line 150

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+       .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 */

blank line

drivers/serial/serial_msm.c line 151

Quoted 1 line
drivers/serial/serial_msm.c new file +1 -0
+       fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, 2);

check return value and maybe return -EINVAL

drivers/serial/serial_msm.c line 154

Quoted 3 lines
drivers/serial/serial_msm.c new file +3 -0
+       clkd[0] = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
+
+       struct udevice *clk = NULL;

Put this decl at the top. Also do you need to assign to NULL?

drivers/serial/serial_msm.c line 155

Quoted 1 line
drivers/serial/serial_msm.c new file +1 -0
+       uclass_get_device_by_of_offset(UCLASS_CLK, clkd[0], &clk);

Check return value. -ENODEV means there is no clk. Is it OK to have no clock?

drivers/serial/serial_msm.c line 157

Quoted 2 lines
drivers/serial/serial_msm.c new file +2 -0
+       if (clk)
+               clk_set_periph_rate(clk, clkd[1], clk_rate);

If is OK to

Quoted 9 lines
drivers/serial/serial_msm.c new file +9 -0
+
+       return 0;
+}
+
+static int msm_serial_probe(struct udevice *dev)
+{
+       struct msm_serial_data *p = dev_get_priv(dev);
+
+       msm_uart_clk_init(dev);

drivers/serial/serial_msm.c line 176

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+
+       if (readl(p->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN)
+               writel(UARTDM_CR_CMD_RESET_ERR, p->base + UARTDM_CR);
+
+       writel(0, p->base + UARTDM_IMR);
+       writel(UARTDM_CR_CMD_STALE_EVENT_DISABLE, p->base + UARTDM_CR);
+       writel(0xFFFFFF, p->base + UARTDM_DMRX);
+
+       p->chars_buf = 0;
+       p->chars_cnt = 0;

No need for the above two lines. Private data is set to 0 by driver model.

Quoted 17 lines
drivers/serial/serial_msm.c new file +17 -0
+       return 0;
+}
+
+static int msm_serial_ofdata_to_platdata(struct udevice *dev)
+{
+       struct msm_serial_data *p = dev_get_priv(dev);
+
+       p->base = dev_get_addr(dev);
+       if (p->base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+       return 0;
+}
+
+static const struct udevice_id msm_serial_ids[] = {
+       { .compatible = "qcom,msm-uartdm-v1.4" },
+       { }
+};

drivers/serial/serial_msm.c line 203

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+
+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,
+       .flags = DM_FLAG_PRE_RELOC,

Do you need this? You can specify this with u-boot,dm-pre-reloc in the device tree.

Quoted 4 lines
drivers/serial/serial_msm.c new file +1 -1
+};
--

2.5.0

Regards,
Simon

#3 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Thank you for awesome review!

I fully agree with most of the suggestions (for this and following patches), so to keep it short will reply only to questions (or where I disagree)

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 59 lines
Quoted 38 lines
drivers/serial/serial_msm.c new file +38 -0
+static int msm_serial_getc(struct udevice *dev)
+{
+       struct msm_serial_data *p = dev_get_priv(dev);
+       unsigned sr;
+       char c;
+
+       /* There was something buffered */
+       if (p->chars_cnt) {
+               c = p->chars_buf & 0xFF;
+               p->chars_buf >>= 8;
+               p->chars_cnt--;
+               return c;
+       }
+
+       /* Clear error in case of buffer overrun */
+       if (readl(p->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN)
+               writel(UARTDM_CR_CMD_RESET_ERR, p->base + UARTDM_CR);
+
+       /* We need to fetch new character */
+       sr = readl(p->base + UARTDM_SR);
+
+       /* There are at least 4 bytes in fifo */
+       if (sr & UARTDM_SR_RX_READY) {
+               p->chars_buf = readl(p->base + UARTDM_RF);
+               c = p->chars_buf & 0xFF;
+               p->chars_cnt = 3; /* 4 - one read */
+               p->chars_buf >>= 8;
+               return c;
+       }
+
+       /* Check if there is anything in fifo */
+       p->chars_cnt = readl(p->base + UARTDM_RXFS);
+       /* Extract number of characters in UART packing buffer */
+       p->chars_cnt = (p->chars_cnt >> UARTDM_RXFS_BUF_SHIFT) &
+                      UARTDM_RXFS_BUF_MASK;
+       if (!p->chars_cnt)
+               return -EAGAIN;
+

drivers/serial/serial_msm.c line 105

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+       /* There is at least one charcter, move it to fifo */
+       writel(UARTDM_CR_CMD_FORCE_STALE, p->base + UARTDM_CR);
+
+       p->chars_buf = readl(p->base + UARTDM_RF);
+       writel(UARTDM_CR_CMD_RESET_STALE_INT, p->base + UARTDM_CR);
+       writel(0xFFFFFF, p->base + UARTDM_DMRX);
+
+       c = p->chars_buf & 0xFF;
+       p->chars_buf >>= 8;
+       p->chars_cnt--;

Can you not rationalise this code a bit? E.g.

if (no chars in fifo) {
try to get some
}
if (no chars in fifo)
return -EAGAIN
extract char from fifo
return ch;

Quoted 1 line

You seem to have three copies of the same code.

That is good idea.
Just be warned that "try to get some" will have most of the current code inside.
Reason: Characters from FIFO are packed into 32-bit register.
There are different ways for extracting >=4 chars, and <4 chars.

Quoted 9 lines
Quoted 2 lines

+ uclass_get_device_by_of_offset(UCLASS_CLK, clkd[0], &clk);

Check return value. -ENODEV means there is no clk. Is it OK to have no clock?

drivers/serial/serial_msm.c line 157

Quoted 2 lines
drivers/serial/serial_msm.c new file +2 -0
+       if (clk)
+               clk_set_periph_rate(clk, clkd[1], clk_rate);

If is OK to

Of course will check ret value;

For now (at least when it comes to default UART) it's OK not to have clock, as U-Boot is chain-loaded from fastboot, but this will change once I get rid of fastboot dependency.

[...]

Quoted 8 lines

drivers/serial/serial_msm.c line 203

Quoted 5 lines
drivers/serial/serial_msm.c new file +5 -0
+       .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,
+       .flags = DM_FLAG_PRE_RELOC,

Do you need this? You can specify this with u-boot,dm-pre-reloc in the device tree.

Probably not, as I do it in dts :)

Regards,
Mateusz

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWceN5AAoJELvtohmVtQzBvvkH/21bJ573Y+MwKoFeezuupO9p /kmLNmJ3hNYFjoLv837wW2zNqrbyu5SLnM/Udm8ttbqBcbXWZUIjLhdHZLxGhXiR X0Zu/yXncb4MRua8QvTpsuuPlEHWqFsLc0XCYzgelwllbkhmC4430HDXuyEdY8+F iHhuDRTnRdvfUmby4VGwGCoAmpcn30TEcbyffjSnGjXTd+SQ3Vi/sHY+0qTIpSVS QRWwnQX3WqC0hK6nleLaNXymVzarZANzhMgP6G/aAiPk7GKvExZYJ5Ilko+Iewns z/bF0FX8bUXU/Yq4opgaTNQlcifQqjr8QIUqbEnSQNHVynoP3FAZj0dsZUVrJ28= =Nj9Z
-----END PGP SIGNATURE-----

#4 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

In reply to Simon Glass

2015-12-16 3:58 GMT+09:00 Simon Glass <[email protected]>:

Quoted 24 lines
Quoted 11 lines

+++ b/drivers/serial/serial_msm.c

drivers/serial/serial_msm.c new file +9 -0
@@ -0,0 +1,204 @@
+/*
+ * Qualcomm UART driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * UART will work in Data Mover mode.
+ * Based on Linux driver.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+

drivers/serial/serial_msm.c line 19

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <serial.h>
+#include <watchdog.h>

Ordering:

Quoted 10 lines

common.h
clk.h
dm.h
errno.h
serial.h
watchdog.h
asm/
linux/

No.

Put <linux/*.h> above <asm/*.h>, at least.
(the same order in Linux)

BTW, the "Include file order" in
http://www.denx.de/wiki/U-Boot/CodingStyle

Is this your opinion? Or community's opinion.

Did anybody review it?

Signature · 2 lines
Best Regards
Masahiro Yamada
#5 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

Hi Masahiro,

Quoted 44 lines · Masahiro Yamada

2015-12-16 3:58 GMT+09:00 Simon Glass <[email protected]>:

Quoted 24 lines
Quoted 11 lines

+++ b/drivers/serial/serial_msm.c

drivers/serial/serial_msm.c new file +9 -0
@@ -0,0 +1,204 @@
+/*
+ * Qualcomm UART driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * UART will work in Data Mover mode.
+ * Based on Linux driver.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+

drivers/serial/serial_msm.c line 19

Quoted 10 lines
drivers/serial/serial_msm.c new file +10 -0
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <serial.h>
+#include <watchdog.h>

Ordering:

Quoted 10 lines

common.h
clk.h
dm.h
errno.h
serial.h
watchdog.h
asm/
linux/

No.

Put <linux/*.h> above <asm/*.h>, at least.
(the same order in Linux)

Quoted 6 lines

BTW, the "Include file order" in
http://www.denx.de/wiki/U-Boot/CodingStyle

Is this your opinion? Or community's opinion.

Did anybody review it?

This came from Mike Frysinger some years ago on the mailing list and I have followed it since. I took it to be a U-Boot standard and added it to the Wiki at some point. Linux perhaps has linux/ above asm/ for its own reasons (e.g. because it is Linux and needs its headers first) but I don't think that is a good idea for U-Boot. It is unnecessary and makes the sort order more confusing.

Regards,
Simon

#6 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

Hi Simon,

Quoted 5 lines
Quoted 5 lines

BTW, the "Include file order" in
http://www.denx.de/wiki/U-Boot/CodingStyle

Is this your opinion? Or community's opinion.

Quoted 9 lines
Quoted 1 line

Did anybody review it?

This came from Mike Frysinger some years ago on the mailing list and I have followed it since. I took it to be a U-Boot standard and added it to the Wiki at some point. Linux perhaps has linux/ above asm/ for its own reasons (e.g. because it is Linux and needs its headers first) but I don't think that is a good idea for U-Boot. It is unnecessary and makes the sort order more confusing.

OK, but I want to know the reason.
Do you remember why Mike Frysinger suggested so?

I guess Linux sorts headers from global to local.

#include <linux/*.h>    global in the project
#include <asm/*.h>      arch-specific
#include "foo.h"        local in the directory

Likewise, the following makes sense for U-Boot

#include <common.h>

#include <*.h>              global in the project (U-boot orignal)
#include <linux/*.h>        global in the project (come from Linux)
#include <asm/*.h>          arch-specific
#include <asm/arch/*.h>     SoC-specific
#include "foo.h"            local in the directory

if I am not missing something...

Signature · 2 lines
Best Regards
Masahiro Yamada
#7 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

Hi Masahiro,

On 23.12.2015 04:52, Masahiro Yamada wrote:
[..]

Quoted 9 lines

I guess Linux sorts headers from global to local.

#include <linux/*.h>    global in the project
#include <asm/*.h>      arch-specific
#include "foo.h"        local in the directory

Likewise, the following makes sense for U-Boot

Quoted 10 lines

#include <common.h>

#include <*.h>              global in the project (U-boot orignal)
#include <linux/*.h>        global in the project (come from Linux)
#include <asm/*.h>          arch-specific
#include <asm/arch/*.h>     SoC-specific
#include "foo.h"            local in the directory

if I am not missing something...

Is it OK with you if for V1 (I'd like to post it soon) I'll use order proposed by Simon (and U-Boot page in general), and then depending on your discussion will swap (or not).

Regards,
Mateusz

#8 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

Hi Mateusz,

2015-12-28 1:51 GMT+09:00 Mateusz Kulikowski <[email protected]>:

Quoted 20 lines

Hi Masahiro,

On 23.12.2015 04:52, Masahiro Yamada wrote:
[..]

Quoted 16 lines

I guess Linux sorts headers from global to local.

#include <linux/*.h>    global in the project
#include <asm/*.h>      arch-specific
#include "foo.h"        local in the directory

Likewise, the following makes sense for U-Boot

#include <common.h>

#include <*.h>              global in the project (U-boot orignal)
#include <linux/*.h>        global in the project (come from Linux)
#include <asm/*.h>          arch-specific
#include <asm/arch/*.h>     SoC-specific
#include "foo.h"            local in the directory
Quoted 7 lines
Quoted 3 lines

if I am not missing something...

Is it OK with you if for V1 (I'd like to post it soon) I'll use order proposed by Simon (and U-Boot page in general), and then depending on your discussion will swap (or not).

I am OK with that.

Signature · 2 lines
Best Regards
Masahiro Yamada
#9 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

In reply to Masahiro Yamada

Hi Masahiro,

Quoted 31 lines · Masahiro Yamada

Hi Simon,

Quoted 5 lines
Quoted 5 lines

BTW, the "Include file order" in
http://www.denx.de/wiki/U-Boot/CodingStyle

Is this your opinion? Or community's opinion.

Quoted 9 lines
Quoted 1 line

Did anybody review it?

This came from Mike Frysinger some years ago on the mailing list and I have followed it since. I took it to be a U-Boot standard and added it to the Wiki at some point. Linux perhaps has linux/ above asm/ for its own reasons (e.g. because it is Linux and needs its headers first) but I don't think that is a good idea for U-Boot. It is unnecessary and makes the sort order more confusing.

OK, but I want to know the reason.
Do you remember why Mike Frysinger suggested so?

I guess Linux sorts headers from global to local.

#include <linux/*.h>    global in the project
#include <asm/*.h>      arch-specific
#include "foo.h"        local in the directory

Likewise, the following makes sense for U-Boot

Quoted 8 lines

#include <common.h>

#include <*.h>              global in the project (U-boot orignal)
#include <linux/*.h>        global in the project (come from Linux)
#include <asm/*.h>          arch-specific
#include <asm/arch/*.h>     SoC-specific
#include "foo.h"            local in the directory

if I am not missing something...

The only difference here seems to be the position of the linux headers. I don't think it is a big deal to change it if you like. The only think I don't like so much is that it seems easier to put 'linux' after 'asm', since it matches the alphabetical order and may avoid confusion. But it's not important to me - mostly we just need to be consistent. If you want to do this, perhaps get an ack from Tom and then update the wiki?

Quoted 5 lines

--
Best Regards
Masahiro Yamada

Regards,
Simon

#10 lore raw

RFC PATCH 1/11 serial: Add support for Qualcomm serial port

Hi Simon,

2015-12-28 13:29 GMT+09:00 Simon Glass <[email protected]>:

Quoted 44 lines

Hi Masahiro,

Quoted 31 lines · Masahiro Yamada

Hi Simon,

Quoted 5 lines
Quoted 5 lines

BTW, the "Include file order" in
http://www.denx.de/wiki/U-Boot/CodingStyle

Is this your opinion? Or community's opinion.

Quoted 9 lines
Quoted 1 line

Did anybody review it?

This came from Mike Frysinger some years ago on the mailing list and I have followed it since. I took it to be a U-Boot standard and added it to the Wiki at some point. Linux perhaps has linux/ above asm/ for its own reasons (e.g. because it is Linux and needs its headers first) but I don't think that is a good idea for U-Boot. It is unnecessary and makes the sort order more confusing.

OK, but I want to know the reason.
Do you remember why Mike Frysinger suggested so?

I guess Linux sorts headers from global to local.

#include <linux/*.h>    global in the project
#include <asm/*.h>      arch-specific
#include "foo.h"        local in the directory

Likewise, the following makes sense for U-Boot

Quoted 8 lines

#include <common.h>

#include <*.h>              global in the project (U-boot orignal)
#include <linux/*.h>        global in the project (come from Linux)
#include <asm/*.h>          arch-specific
#include <asm/arch/*.h>     SoC-specific
#include "foo.h"            local in the directory

if I am not missing something...

Quoted 8 lines

The only difference here seems to be the position of the linux headers. I don't think it is a big deal to change it if you like. The only think I don't like so much is that it seems easier to put 'linux' after 'asm', since it matches the alphabetical order and may avoid confusion. But it's not important to me - mostly we just need to be consistent. If you want to do this, perhaps get an ack from Tom and then update the wiki?

OK.

Perhaps, we can continue this discussion in a more suitable subject.

Signature · 2 lines
Best Regards
Masahiro Yamada
#11 lore raw

RFC PATCH 2/11 gpio: Add support for Qualcomm gpio controller

In reply to Mateusz Kulikowski

Add support for gpio controllers on Qualcomm Snapdragon devices. This devices are usually called Top Level Mode Multiplexing in Qualcomm documentation.

---

 drivers/gpio/Kconfig    |   7 +++
 drivers/gpio/Makefile   |   2 +-
 drivers/gpio/msm_gpio.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpio/msm_gpio.c
drivers/gpio/Kconfig +7 -0
index e60e9fd..1d9443b 100644
@@ -46,6 +46,13 @@ 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.
+
 config ROCKCHIP_GPIO
 	bool "Rockchip GPIO driver"
 	depends on DM_GPIO
drivers/gpio/Makefile +1 -1
index fb4fd25..9520b1e 100644
@@ -46,4 +46,4 @@ obj-$(CONFIG_STM32_GPIO)	+= stm32_gpio.o
 obj-$(CONFIG_ZYNQ_GPIO)		+= zynq_gpio.o
 obj-$(CONFIG_VYBRID_GPIO)	+= vybrid_gpio.o
 obj-$(CONFIG_HIKEY_GPIO)	+= hi6220_gpio.o
-
+obj-$(CONFIG_MSM_GPIO)		+= msm_gpio.o
drivers/gpio/msm_gpio.c new file +115 -0

115 lines not on this page · raw message

Signature · 1 line
2.5.0
#12 lore raw

RFC PATCH 2/11 gpio: Add support for Qualcomm gpio controller

Hi Mateusz,

Quoted 18 lines · Mateusz Kulikowski

Add support for gpio controllers on Qualcomm Snapdragon devices. This devices are usually called Top Level Mode Multiplexing in Qualcomm documentation.

---

 drivers/gpio/Kconfig    |   7 +++
 drivers/gpio/Makefile   |   2 +-
 drivers/gpio/msm_gpio.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpio/msm_gpio.c
drivers/gpio/Kconfig +0 -0
index e60e9fd..1d9443b 100644

drivers/gpio/Kconfig config LPC32XX_GPIO · line 54

Quoted 9 lines
drivers/gpio/Kconfig +6 -0
@@ -46,6 +46,13 @@ 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.

Any more details? How many banks? How are they named? What features does the driver support?

Quoted 23 lines
drivers/gpio/Kconfig +1 -0
+
 config ROCKCHIP_GPIO
        bool "Rockchip GPIO driver"
        depends on DM_GPIO
drivers/gpio/Makefile +1 -1
index fb4fd25..9520b1e 100644
@@ -46,4 +46,4 @@ obj-$(CONFIG_STM32_GPIO)      += stm32_gpio.o
 obj-$(CONFIG_ZYNQ_GPIO)                += zynq_gpio.o
 obj-$(CONFIG_VYBRID_GPIO)      += vybrid_gpio.o
 obj-$(CONFIG_HIKEY_GPIO)       += hi6220_gpio.o
-
+obj-$(CONFIG_MSM_GPIO)         += msm_gpio.o
drivers/gpio/msm_gpio.c new file +3 -0
new file mode 100644
index 0000000..9bb9e89
@@ -0,0 +1,115 @@
+/*
+ * Qualcomm GPIO driver
+ *

drivers/gpio/msm_gpio.c line 13

Quoted 10 lines
drivers/gpio/msm_gpio.c new file +10 -0
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>

Put errno.h below dm.h

Quoted 4 lines
drivers/gpio/msm_gpio.c new file +4 -0
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct msm_gpio_bank {

drivers/gpio/msm_gpio.c line 27

Quoted 10 lines
drivers/gpio/msm_gpio.c new file +10 -0
+       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 */
+       writel((readl(reg) & ~GPIO_OE_MASK) | GPIO_OE_DISABLE , reg);

How about:

clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_DISABLE)

Quoted 64 lines
drivers/gpio/msm_gpio.c new file +64 -0
+       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 */
+       writel((readl(reg) & ~GPIO_OE_MASK) | GPIO_OE_ENABLE , reg);
+       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;
+}
+
+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,

drivers/gpio/msm_gpio.c line 101

Quoted 10 lines
drivers/gpio/msm_gpio.c new file +10 -0
+                                            "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" },

Is there a device binding tree binding file you can put in doc/device-tree-bindings?

Quoted 15 lines
drivers/gpio/msm_gpio.c new file +14 -1
+       { }
+};
+
+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),
+};
+
+
--
Quoted 2 lines

2.5.0

Regards,
Simon

#13 lore raw

RFC PATCH 3/11 mmc: Add support for Qualcomm SDHCI controller

In reply to Mateusz Kulikowski

---

 drivers/mmc/Kconfig     |   6 ++
 drivers/mmc/Makefile    |   1 +
 drivers/mmc/msm_sdhci.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 drivers/mmc/msm_sdhci.c
drivers/mmc/Kconfig +6 -0
index ceae7bc..3f75fa7 100644
@@ -16,6 +16,12 @@ 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 manufactured by Qualcomm.
+
 config ROCKCHIP_DWMMC
 	bool "Rockchip SD/MMC controller support"
 	depends on DM_MMC && OF_CONTROL
drivers/mmc/Makefile +1 -0
index 5d35705..f4fdfca 100644
@@ -49,3 +49,4 @@ else
 obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
 endif
 
+obj-$(CONFIG_MSM_SDHCI) += msm_sdhci.o
drivers/mmc/msm_sdhci.c new file +149 -0

149 lines not on this page · raw message

Signature · 1 line
2.5.0
#14 lore raw

RFC PATCH 3/11 mmc: Add support for Qualcomm SDHCI controller

Hi Mateusz,

Quoted 2 lines · Mateusz Kulikowski

---

Please add a commit message.

Quoted 12 lines
 drivers/mmc/Kconfig     |   6 ++
 drivers/mmc/Makefile    |   1 +
 drivers/mmc/msm_sdhci.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 drivers/mmc/msm_sdhci.c
drivers/mmc/Kconfig +0 -0
index ceae7bc..3f75fa7 100644

drivers/mmc/Kconfig config DM_MMC · line 23

Quoted 8 lines
drivers/mmc/Kconfig +5 -0
@@ -16,6 +16,12 @@ 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 manufactured by Qualcomm.

Can you add any more detail here?

Quoted 25 lines
drivers/mmc/Kconfig +1 -0
+
 config ROCKCHIP_DWMMC
        bool "Rockchip SD/MMC controller support"
        depends on DM_MMC && OF_CONTROL
drivers/mmc/Makefile +1 -0
index 5d35705..f4fdfca 100644
@@ -49,3 +49,4 @@ else
 obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
 endif
 
+obj-$(CONFIG_MSM_SDHCI) += msm_sdhci.o
drivers/mmc/msm_sdhci.c new file +6 -0
new file mode 100644
index 0000000..96119f0
@@ -0,0 +1,149 @@
+/*
+ * Qualcomm SDHCI driver - SD/eMMC controller
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * Based on Linux driver

drivers/mmc/msm_sdhci.c line 16

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <linux/bitops.h>
+#include <sdhci.h>
+#include <clk.h>

Ordering:

common.h always goes first
clk.h
dm.h
sdhci.h
asm/
linux/

Quoted 13 lines
drivers/mmc/msm_sdhci.c new file +13 -0
+
+/* 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_HC_MODE 0x78
+

drivers/mmc/msm_sdhci.c line 39

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+/* 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;
+       phys_addr_t base;
+       unsigned width;

Comment - what is width?

Quoted 7 lines
drivers/mmc/msm_sdhci.c new file +7 -0
+};
+
+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,

drivers/mmc/msm_sdhci.c line 56

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+                                       "clock-frequency", 400000);
+       uint clkd[2]; /* clk_id and clk_no */
+       fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, 2);
+       clkd[0] = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
+
+       struct udevice *clk = NULL;
+       uclass_get_device_by_of_offset(UCLASS_CLK, clkd[0], &clk);
+       if (clk)
+               clk_set_periph_rate(clk, clkd[1], clk_rate);
+

See comments on the previous patch. Also you could move the DT decode code all into your ofdata_to_platdata function (if you like).

Quoted 11 lines
drivers/mmc/msm_sdhci.c new file +11 -0
+       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;
+
+       host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
+

drivers/mmc/msm_sdhci.c line 77

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+       /* Init clocks */
+       if (msm_sdc_clk_init(dev))
+               return -EIO;
+
+       /* Reset the core and Enable SDHC mode */
+       writel(readl(prv->base + SDCC_MCI_POWER) | SDCC_MCI_POWER_SW_RST,
+              prv->base + SDCC_MCI_POWER);
+
+       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
+       mdelay(2);

So why such a long delay? Perhaps you should put the code immediately below int a timeout loop?

start = get_timer(0);
while (readl...) {
if (get_timer(start) > 2)

      return -ETIMEDOUT;
}

drivers/mmc/msm_sdhci.c line 81

Quoted 4 lines
drivers/mmc/msm_sdhci.c new file +4 -0
+
+       if (readl(prv->base + SDCC_MCI_POWER) & SDCC_MCI_POWER_SW_RST) {
+               printf("msm_sdhci: stuck in reset\n");
+               return -1;

-ETIMEDOUT?

Quoted 22 lines
drivers/mmc/msm_sdhci.c new file +22 -0
+       }
+
+       /* 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);
+       }
+

drivers/mmc/msm_sdhci.c line 113

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+       /* 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);

blank line after decls

drivers/mmc/msm_sdhci.c line 115

Quoted 2 lines
drivers/mmc/msm_sdhci.c new file +2 -0
+        /* Disable host-controller mode */
+       writel(0, priv->base + SDCC_MCI_HC_MODE);

blank line before return

Quoted 7 lines
drivers/mmc/msm_sdhci.c new file +7 -0
+       return 0;
+}
+
+static int msm_ofdata_to_platdata(struct udevice *dev)
+{
+       struct msm_sdhc *priv = dev_get_priv(dev);
+       struct sdhci_host *host = &priv->host;

drivers/mmc/msm_sdhci.c line 132

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+
+       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 = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+                                                     dev->parent->of_offset,
+                                                     dev->of_offset, "reg",
+                                                     1, NULL);

Odd that you are reading the second cell. How come?

Quoted 18 lines
drivers/mmc/msm_sdhci.c new file +17 -1
+       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),
+};
--
Quoted 2 lines

2.5.0

Regards,
Simon

#15 lore raw

RFC PATCH 3/11 mmc: Add support for Qualcomm SDHCI controller

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 10 lines
Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+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 */
+       fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, 2);
+       clkd[0] = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
+
Quoted 8 lines

drivers/mmc/msm_sdhci.c line 56

Quoted 5 lines
drivers/mmc/msm_sdhci.c new file +5 -0
+       struct udevice *clk = NULL;
+       uclass_get_device_by_of_offset(UCLASS_CLK, clkd[0], &clk);
+       if (clk)
+               clk_set_periph_rate(clk, clkd[1], clk_rate);
+

See comments on the previous patch. Also you could move the DT decode code all into your ofdata_to_platdata function (if you like).

But requesting clock must be handled in probe (i.e. when clock is already bound) right?

Quoted 26 lines
Quoted 12 lines
drivers/mmc/msm_sdhci.c new file +11 -0
+       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;
+
+       host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
+

drivers/mmc/msm_sdhci.c line 77

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+       /* Init clocks */
+       if (msm_sdc_clk_init(dev))
+               return -EIO;
+
+       /* Reset the core and Enable SDHC mode */
+       writel(readl(prv->base + SDCC_MCI_POWER) | SDCC_MCI_POWER_SW_RST,
+              prv->base + SDCC_MCI_POWER);
+
+       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
+       mdelay(2);

So why such a long delay? Perhaps you should put the code immediately below int a timeout loop?

Quoted 6 lines

start = get_timer(0);

while (readl...) {
   if (get_timer(start) > 2)
      return -ETIMEDOUT;
}

I'm not sure if I can do that - I can test it, perhaps it will even work on my board, but it was put explicitly in Linux driver (1-5ms delay).

Documentation says:
"SW should wait until bit 0 (MCLK_REG_WR_ACTIVE) of MCI_STATUS2 register is 0, after writing to MCI_POWER register and before accessing this register again."

But this applies to all writes, not to reset request - I'm not sure how MCI_STATUS2 will behave during reset (it may get zeroed earlier).

Do you really think I should try to decrease this delay?

[...]

Quoted 10 lines
Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+}
+
+static int msm_ofdata_to_platdata(struct udevice *dev)
+{
+       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,
Quoted 8 lines

drivers/mmc/msm_sdhci.c line 132

Quoted 6 lines
drivers/mmc/msm_sdhci.c new file +6 -0
+                                        "bus-width", 4);
+       host->index = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "index", 0);
+       priv->base = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+                                                     dev->parent->of_offset,
+                                                     dev->of_offset, "reg",
+                                                     1, NULL);

Odd that you are reading the second cell. How come?

I tried to use as much parts of original qcom Linux dts as possible. For mmc controller, there are 2 addresses needed:
- - SDCC base (i.e. base of IP block with vendor-specific regs etc.)
- - SDHCI base (i.e. place where SDHCI "standard" registers start)

My assumption is that SDHCI offset may be different on different SoCs, and wanted to have generic driver.

[...]
Regards,
Mateusz

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWcenTAAoJELvtohmVtQzBddYH+waGw+OePJ8MdeMgI8BYJ295 3l+Op/2FGquWNIIoJRlO59JOeZqVkJJWOph19DQWpmybIra1HoRRmVTVqY2l2Fon vTdzZ+cZ3jY2bzLGzYARXCEJ4jNxUILkPS/r/SrRfhDVC4vxSROSA7Jh6EmnssDm kktzR98/o834uDQc0niGWYi9K1hpUnwQ3m8b1e8LmwdH3LcuHH7+UWntTnEesBai Ox3ES6y5S9VtCBnyZ/LSilqe30AVB4ccKlk69G41AQYPI5u5CZEfm1OP8AGjpkfV 0D4WrErh/CGmYpG0b4G14CYe39GekCmD9IAnMC4zxjRwwZCmp1kGoeunNwpiLjk= =scwU
-----END PGP SIGNATURE-----

#16 lore raw

RFC PATCH 3/11 mmc: Add support for Qualcomm SDHCI controller

Hi Mateusz,

Quoted 30 lines · Mateusz Kulikowski

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 10 lines
Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+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 */
+       fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, 2);
+       clkd[0] = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
+
Quoted 8 lines

drivers/mmc/msm_sdhci.c line 56

Quoted 5 lines
drivers/mmc/msm_sdhci.c new file +5 -0
+       struct udevice *clk = NULL;
+       uclass_get_device_by_of_offset(UCLASS_CLK, clkd[0], &clk);
+       if (clk)
+               clk_set_periph_rate(clk, clkd[1], clk_rate);
+

See comments on the previous patch. Also you could move the DT decode code all into your ofdata_to_platdata function (if you like).

Quoted 2 lines

But requesting clock must be handled in probe (i.e. when clock is already bound) right?

Yes. Although bear in mind that the ofdata_to_platdata() call is made just before probe() so it is OK to put 'get' calls in there. In general all devices are bound before any are probed.

Quoted 41 lines
Quoted 27 lines
Quoted 13 lines
drivers/mmc/msm_sdhci.c new file +11 -0
+       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;
+
+       host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
+

drivers/mmc/msm_sdhci.c line 77

Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+       /* Init clocks */
+       if (msm_sdc_clk_init(dev))
+               return -EIO;
+
+       /* Reset the core and Enable SDHC mode */
+       writel(readl(prv->base + SDCC_MCI_POWER) | SDCC_MCI_POWER_SW_RST,
+              prv->base + SDCC_MCI_POWER);
+
+       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
+       mdelay(2);

So why such a long delay? Perhaps you should put the code immediately below int a timeout loop?

Quoted 6 lines

start = get_timer(0);

while (readl...) {
   if (get_timer(start) > 2)
      return -ETIMEDOUT;
}

I'm not sure if I can do that - I can test it, perhaps it will even work on my board, but it was put explicitly in Linux driver (1-5ms delay).

Documentation says:
"SW should wait until bit 0 (MCLK_REG_WR_ACTIVE) of MCI_STATUS2 register is 0, after writing to MCI_POWER register and before accessing this register again."

Quoted 4 lines

But this applies to all writes, not to reset request - I'm not sure how MCI_STATUS2 will behave during reset (it may get zeroed earlier).

Do you really think I should try to decrease this delay?

Can you change the code to wait until bit 0 is 0, instead of having a delay?

Quoted 21 lines

[...]

Quoted 10 lines
Quoted 10 lines
drivers/mmc/msm_sdhci.c new file +10 -0
+}
+
+static int msm_ofdata_to_platdata(struct udevice *dev)
+{
+       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,
Quoted 8 lines

drivers/mmc/msm_sdhci.c line 132

Quoted 6 lines
drivers/mmc/msm_sdhci.c new file +6 -0
+                                        "bus-width", 4);
+       host->index = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "index", 0);
+       priv->base = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+                                                     dev->parent->of_offset,
+                                                     dev->of_offset, "reg",
+                                                     1, NULL);

Odd that you are reading the second cell. How come?

Quoted 7 lines

I tried to use as much parts of original qcom Linux dts as possible. For mmc controller, there are 2 addresses needed:
- - SDCC base (i.e. base of IP block with vendor-specific regs etc.)
- - SDHCI base (i.e. place where SDHCI "standard" registers start)

My assumption is that SDHCI offset may be different on different SoCs, and wanted to have generic driver.

OK I see, thanks.

Regards,
Simon

#17 lore raw

RFC PATCH 3/11 mmc: Add support for Qualcomm SDHCI controller

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 16 December 2015 at 15:46, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 8 lines
Quoted 8 lines

I'm not sure if I can do that - I can test it, perhaps it will even work on my board, but it was put explicitly in Linux driver (1-5ms delay).

Documentation says:
"SW should wait until bit 0 (MCLK_REG_WR_ACTIVE) of MCI_STATUS2 register is 0, after writing to MCI_POWER register and before accessing this register again."

Quoted 6 lines
Quoted 4 lines

But this applies to all writes, not to reset request - I'm not sure how MCI_STATUS2 will behave during reset (it may get zeroed earlier).

Do you really think I should try to decrease this delay?

Can you change the code to wait until bit 0 is 0, instead of having a delay?

This seems to work - at least on my board so will do it that way - thanks :)

Regards,
Mateusz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWdT3MAAoJELvtohmVtQzBjRUIAIwoq7nv3Ed/WrDi+azQscUD RvZe8KGFGy0VOVbrV4iMYmG6SJzN9cxrA4q1oGVsUWZyh1uHuDMlhdPLqaW6EIC5 wQFeY2zWffNKJlx1MGhJKwKB+plYXWzEp6LDYIgB+LaTOUCPZOsnxJvac6bDvXF/ FLR3AXGMzHL1nrty/7MToNB2AtRynBxwEPRmyu5e1aNd9rfq+CrkyIqcsQ9M7VQz y1UbJCUWDcwKKIDLUMfM9z67xx7O436M1fDSL1ELxuxI8C2UtdiycFu/uKm3XP+o Nt871BEKLwK5WnkuFERZaXd8kbUYq+j1iOlt+oL7pTOY8+8IBQABnHf3YT1TCUo= =0ZkP
-----END PGP SIGNATURE-----

#18 lore raw

RFC PATCH 4/11 ehci-hcd: Add init_after_reset

In reply to Mateusz Kulikowski

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.

---

 drivers/usb/host/ehci-hcd.c | 6 ++++++
 drivers/usb/host/ehci.h     | 1 +
 2 files changed, 7 insertions(+)
drivers/usb/host/ehci-hcd.c +6 -0
index c85dbce..a54f817 100644
@@ -1654,6 +1654,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;
drivers/usb/host/ehci.h +1 -0
index b41c04a..ed567fc 100644
@@ -239,6 +239,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 {
Signature · 1 line
2.5.0
#20 lore raw

RFC PATCH 4/11 ehci-hcd: Add init_after_reset

In reply to Mateusz Kulikowski
Quoted 5 lines · Mateusz Kulikowski

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.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151216/324262fe/attachment.sig>
#21 lore raw

RFC PATCH 5/11 ehci: Add support for Qualcomm EHCI

In reply to Mateusz Kulikowski

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.

---

 drivers/usb/host/Kconfig    |   8 ++
 drivers/usb/host/Makefile   |   1 +
 drivers/usb/host/ehci-msm.c | 198 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 207 insertions(+)
 create mode 100644 drivers/usb/host/ehci-msm.c
drivers/usb/host/Kconfig +8 -0
index 0096a2f..5a63475 100644
@@ -66,6 +66,14 @@ 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
+	default n
+	---help---
+	  Enables support for the on-chip EHCI controller on Qualcomm
+	  Snapdragon SoCs.
+
 config USB_EHCI_UNIPHIER
 	bool "Support for UniPhier on-chip EHCI USB controller"
 	depends on ARCH_UNIPHIER && OF_CONTROL
drivers/usb/host/Makefile +1 -0
index 0b4b458..d4a556a 100644
@@ -42,6 +42,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
drivers/usb/host/ehci-msm.c new file +198 -0

198 lines not on this page · raw message

Signature · 1 line
2.5.0
#22 lore raw

RFC PATCH 5/11 ehci: Add support for Qualcomm EHCI

Quoted 5 lines · Mateusz Kulikowski

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.

Hi,

minor nits below.

[...]

Quoted 21 lines
drivers/usb/host/ehci-msm.c new file +15 -0
new file mode 100644
index 0000000..d17a29a
@@ -0,0 +1,198 @@
+/*
+ * Qualcomm EHCI driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * Based on Linux driver
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/gpio.h>
+#include <asm-generic/errno.h>
+#include <linux/compat.h>
+#include <dm.h>

drivers/usb/host/ehci-msm.c line 25

Quoted 10 lines
drivers/usb/host/ehci-msm.c new file +10 -0
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/ulpi.h>
+#include "ehci.h"
+
+#ifndef CONFIG_USB_ULPI_VIEWPORT
+#error Please enable CONFIG_USB_ULPI_VIEWPORT
+#endif

The driver should select this in Kconfig instead of this check, right ?

Quoted 5 lines
drivers/usb/host/ehci-msm.c new file +5 -0
+#define MSM_USB_ULPI_OFFSET 0x170 /* ULPI viewport (PHY) */
+#define MSM_USB_EHCI_OFFSET 0x100 /* Start of EHCI registers */
+
+/* PHY viewport regs */
+#define ULPI_MISC_A_READ         0x96

drivers/usb/host/ehci-msm.c line 41

Quoted 10 lines
drivers/usb/host/ehci-msm.c new file +10 -0
+#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)
+
+/* qcom specific registers (OTG) */
+#define USB_GENCONFIG_2      0x00A0
+#define GEN2_SESS_VLD_CTRL_EN (1 << 7)
+
+#define USB_USBCMD           (0x0140)

Please drop the parenthesis.

btw. this register layout looks very similar to struct usb_ehci in include/usb/ehci-fsl.h , can the header be made more universal to cover your driver as well ? Then these macros here won't be needed.

Quoted 33 lines
drivers/usb/host/ehci-msm.c new file +33 -0
+#define SESS_VLD_CTRL         (1 << 25)
+#define USBCMD_RESET   2
+#define USBCMD_ATTACH  1
+
+/* USB2_HSIC_USB_OTG_HS_BASE_USB_OTG_HS_PORTSC */
+#define USB_PORTSC           0x0184
+#define USB_SBUSCFG          0x0090
+#define USB_AHB_MODE         0x0098
+
+#define USB_USBMODE          0x01A8
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST   3
+
+struct msm_ehci_priv {
+	struct ehci_ctrl ctrl; /* Needed by EHCI */
+	phys_addr_t base;
+	phys_addr_t ehci_base;
+	u32 ulpi_base;
+	u32 ulpi_port;
+};
+
+int __weak board_prepare_usb(enum usb_init_type type)
+{
+	return 0;
+}
+
+static void setup_usb_phy(struct msm_ehci_priv *priv)
+{
+	struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port,
+					.viewport_addr = priv->ulpi_base};
+
+	/* Select and enable external configuration with USB PHY */
+	ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_SET,

drivers/usb/host/ehci-msm.c line 84

Quoted 10 lines
drivers/usb/host/ehci-msm.c new file +10 -0
+		   ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
+}
+
+static void reset_usb_phy(struct msm_ehci_priv *priv)
+{
+	struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port,
+					.viewport_addr = priv->ulpi_base};
+
+	/* Disable VBUS mimicing in the controller. */
+	ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,

This should be a pointer to a field in struct ulpi_regs, so the (u8 *) cast does not seem right. See for example ehci-zynq.c

Quoted 2 lines
drivers/usb/host/ehci-msm.c new file +2 -0
+		   ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
+}

[...]

drivers/usb/host/ehci-msm.c line 154

Quoted 12 lines
drivers/usb/host/ehci-msm.c new file +12 -0
+static int ehci_usb_remove(struct udevice *dev)
+{
+	struct msm_ehci_priv *p = dev_get_priv(dev);
+	phys_addr_t reg = p->base + USB_USBCMD;
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	/* Stop controller. */
+	writel(readl(reg) & ~USBCMD_ATTACH, reg);

This should use clrbits_le32() instead.

drivers/usb/host/ehci-msm.c line 167

Quoted 12 lines
drivers/usb/host/ehci-msm.c new file +12 -0
+	reset_usb_phy(p);
+
+	ret = board_prepare_usb(USB_INIT_DEVICE); /* Board specific hook */
+	if (ret < 0)
+		return ret;
+
+	/* Reset controller */
+	writel(0x00080002, reg); /* reset usb */
+	mdelay(20);
+	/* Wait for completion */
+	while (readl(reg) & 2)
+		;

Look at wait_for_bit() implementations in the U-Boot tree and avoid the unbounded waiting here please.

Quoted 30 lines
drivers/usb/host/ehci-msm.c new file +30 -0
+	return 0;
+}
+
+static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+	struct msm_ehci_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_get_addr(dev);
+	priv->ehci_base = priv->base + MSM_USB_EHCI_OFFSET;
+	priv->ulpi_base = priv->base + MSM_USB_ULPI_OFFSET;
+	priv->ulpi_port = 0;
+	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,
+};
#23 lore raw

RFC PATCH 5/11 ehci: Add support for Qualcomm EHCI

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi,

Thanks for quick review;

Quoted 1 line · Marek Vasut

On Thursday, December 10, 2015 at 10:41:41 PM, Mateusz Kulikowski wrote:

[...]

Quoted 6 lines

drivers/usb/host/ehci-msm.c line 25

Quoted 4 lines
drivers/usb/host/ehci-msm.c new file +4 -0
+
+#ifndef CONFIG_USB_ULPI_VIEWPORT
+#error Please enable CONFIG_USB_ULPI_VIEWPORT
+#endif

The driver should select this in Kconfig instead of this check, right ?

That was my first attempt, but ULPI_VIEWPORT is not Kconfig option, and it seems it just doesn't work :(

It doesn't matter if I add it as
select USB_ULPI_VIEWPORT
in usb KConfig, or forcibly add CONFIG_USB_ULPI_VIEWPORT to .config

[...]

Quoted 3 lines
Quoted 1 line

+#define USB_USBCMD (0x0140)

Please drop the parenthesis.

Doh, missed this one - surely will do it.

Quoted 4 lines

btw. this register layout looks very similar to struct usb_ehci in include/usb/ehci-fsl.h , can the header be made more universal to cover your driver as well ? Then these macros here won't be needed.

You're right.. in fact contrary to what I expected, Qualcomm didn't implemented their own USB controller.

It is designed by Chipidea, and PHY as far as I see is made by Synapsys.

I can use fsl headers with little exception that two registers are marked as reserved: USB_AHB_MODE (0x98) and USB_GENCONFIG_2 (0xA0)

My guess is that it's just different revision/config of IP core.

Do you think it wouldn't look awkward if I use fsl headers?

I think once this series gets to mainline we can create shared driver that will support both vendors.

I also noticed that U-Boot have ci_udc already so there is a chance I make device controller working pretty fast (but I prefer not to include it in this series yet).

[...]

Quoted 9 lines

drivers/usb/host/ehci-msm.c line 84

Quoted 5 lines
drivers/usb/host/ehci-msm.c new file +5 -0
+	struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port,
+					.viewport_addr = priv->ulpi_base};
+
+	/* Disable VBUS mimicing in the controller. */
+	ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,

This should be a pointer to a field in struct ulpi_regs, so the (u8 *) cast does not seem right. See for example ehci-zynq.c

Perhaps I misussed ulpi_viewport code in that case;

The reason is I need to access MISC_A register (0x96+) that is not in ulpi_regs structure - afaik it's vendor-specific.

Any hints how to tackle that properly?

I can of course duplicate ulpi code, but it probably doesn't make much sense.

[...]

Quoted 5 lines

drivers/usb/host/ehci-msm.c line 154

Quoted 3 lines
drivers/usb/host/ehci-msm.c new file +3 -0
+
+	/* Stop controller. */
+	writel(readl(reg) & ~USBCMD_ATTACH, reg);

This should use clrbits_le32() instead.

Ok

[...]

Quoted 6 lines

drivers/usb/host/ehci-msm.c line 167

Quoted 3 lines
drivers/usb/host/ehci-msm.c new file +3 -0
+	/* Wait for completion */
+	while (readl(reg) & 2)
+		;

Look at wait_for_bit() implementations in the U-Boot tree and avoid the unbounded waiting here please.

Ok, btw I noticed there are 3 copies of almost the same code that does that :)

Perhaps I can add a patch to add this function to /lib as it seems it's common use case?

The following drivers would benefit: ehci-msm, zynq_gem, dwc2, ehci-mx6, ohci-lpc32xx

Regards,
Mateusz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWbWbJAAoJELvtohmVtQzBvEEH/iwqONAqWwqQzpUR4izzZ97Y CAEUWi4GacxwUVt0vZMcK5KV0sRJVP947daMxVkNoDWWkpREuPby+OecFe3mk7iJ cJzTAlYs/OOIkGBuza2wkfaxXq0AItpn2lBF/Vwe8u5hFGSPgYY0quek8SKma6NQ rtNFVdc+4+pgGMy1Pl8Fym9UXOJ/aVv806+XS34UrgGSsnv5qWudRiT3HA0ZR38A VPzgRXs+kIwVAhPe2AlXW0K8w/ipaEF41qAMvHUdXopi0h4Tgsc2QEijC0sIQmBf kSM6gvzYq+gFOJifxcEt3EJj6hOQ4U7nEOi/PqtjBl3BsTw6IdUWLdakCVzQq1I= =eUF2
-----END PGP SIGNATURE-----

#24 lore raw

RFC PATCH 5/11 ehci: Add support for Qualcomm EHCI

Quoted 15 lines · Mateusz Kulikowski

Hi,

Thanks for quick review;

Quoted 1 line · Marek Vasut

On Thursday, December 10, 2015 at 10:41:41 PM, Mateusz Kulikowski wrote:

[...]

Quoted 6 lines

drivers/usb/host/ehci-msm.c line 25

Quoted 4 lines
drivers/usb/host/ehci-msm.c new file +4 -0
+
+#ifndef CONFIG_USB_ULPI_VIEWPORT
+#error Please enable CONFIG_USB_ULPI_VIEWPORT
+#endif

The driver should select this in Kconfig instead of this check, right ?

Quoted 6 lines

That was my first attempt, but ULPI_VIEWPORT is not Kconfig option, and it seems it just doesn't work :(

It doesn't matter if I add it as
select USB_ULPI_VIEWPORT
in usb KConfig, or forcibly add CONFIG_USB_ULPI_VIEWPORT to .config

I think it should be quite easily possible to add this to USB Kconfig.

Quoted 6 lines

[...]

Quoted 3 lines
Quoted 1 line

+#define USB_USBCMD (0x0140)

Please drop the parenthesis.

Quoted 8 lines

Doh, missed this one - surely will do it.

Quoted 3 lines

btw. this register layout looks very similar to struct usb_ehci in include/usb/ehci-fsl.h , can the header be made more universal to cover your driver as well ? Then these macros here won't be needed.

You're right.. in fact contrary to what I expected, Qualcomm didn't implemented their own USB controller.

Well building a chip is like going to a IP block supermarket afterall ;-)

Quoted 1 line

It is designed by Chipidea, and PHY as far as I see is made by Synapsys.

All of the drivers/usb/host/ehci-{mxs,mx5,mx6,vf}.c are also chipidea cores. MXS and MX6 have chipidea PHY too.

Quoted 6 lines

I can use fsl headers with little exception that two registers are marked as reserved: USB_AHB_MODE (0x98) and USB_GENCONFIG_2 (0xA0)

My guess is that it's just different revision/config of IP core.

Do you think it wouldn't look awkward if I use fsl headers?

Just rename them to ehci-ci.h, that should be the quickest.

Quoted 2 lines

I think once this series gets to mainline we can create shared driver that will support both vendors.

I'm all for that.

Quoted 3 lines

I also noticed that U-Boot have ci_udc already so there is a chance I make device controller working pretty fast (but I prefer not to include it in this series yet).

Correct, that works too. I think it was also tested on some marvell chip.

Quoted 13 lines

[...]

Quoted 8 lines

drivers/usb/host/ehci-msm.c line 84

Quoted 5 lines
drivers/usb/host/ehci-msm.c new file +5 -0
+	struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port,
+					.viewport_addr = priv->ulpi_base};
+
+	/* Disable VBUS mimicing in the controller. */
+	ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,

This should be a pointer to a field in struct ulpi_regs, so the (u8 *) cast does not seem right. See for example ehci-zynq.c

Perhaps I misussed ulpi_viewport code in that case;

Quoted 7 lines

The reason is I need to access MISC_A register (0x96+) that is not in ulpi_regs structure - afaik it's vendor-specific.

Any hints how to tackle that properly?

I can of course duplicate ulpi code, but it probably doesn't make much sense.

I don't have a better suggestion, sorry. Let's keep this as-is unless someone can come up with something better. Code duplication is not a good idea, so we won't do that.

Quoted 19 lines

[...]

Quoted 5 lines

drivers/usb/host/ehci-msm.c line 154

Quoted 3 lines
drivers/usb/host/ehci-msm.c new file +3 -0
+
+	/* Stop controller. */
+	writel(readl(reg) & ~USBCMD_ATTACH, reg);

This should use clrbits_le32() instead.

Ok

[...]

Quoted 6 lines

drivers/usb/host/ehci-msm.c line 167

Quoted 3 lines
drivers/usb/host/ehci-msm.c new file +3 -0
+	/* Wait for completion */
+	while (readl(reg) & 2)
+		;

Look at wait_for_bit() implementations in the U-Boot tree and avoid the unbounded waiting here please.

Quoted 5 lines

Ok, btw I noticed there are 3 copies of almost the same code that does that :)

Perhaps I can add a patch to add this function to /lib as it seems it's common use case?

That'd be great, it was on my list to do it for a while, but I didn't get around doing that yet.

Quoted 2 lines

The following drivers would benefit: ehci-msm, zynq_gem, dwc2, ehci-mx6, ohci-lpc32xx

Thanks!

#25 lore raw

RFC PATCH 5/11 ehci: Add support for Qualcomm EHCI

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Marek,

Quoted 1 line · Marek Vasut

On Sunday, December 13, 2015 at 01:38:41 PM, Mateusz Kulikowski wrote:

[...]

Quoted 5 lines
Quoted 3 lines

It doesn't matter if I add it as
select USB_ULPI_VIEWPORT
in usb KConfig, or forcibly add CONFIG_USB_ULPI_VIEWPORT to .config

I think it should be quite easily possible to add this to USB Kconfig.

Will do.

Quoted 8 lines
Quoted 6 lines

I can use fsl headers with little exception that two registers are marked as reserved: USB_AHB_MODE (0x98) and USB_GENCONFIG_2 (0xA0)

My guess is that it's just different revision/config of IP core.

Do you think it wouldn't look awkward if I use fsl headers?

Just rename them to ehci-ci.h, that should be the quickest.

Will do.

[...]

Quoted 14 lines
Quoted 14 lines
Quoted 8 lines

drivers/usb/host/ehci-msm.c line 84

Quoted 5 lines
drivers/usb/host/ehci-msm.c new file +5 -0
+	struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port,
+					.viewport_addr = priv->ulpi_base};
+
+	/* Disable VBUS mimicing in the controller. */
+	ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,

This should be a pointer to a field in struct ulpi_regs, so the (u8 *) cast does not seem right. See for example ehci-zynq.c

Perhaps I misussed ulpi_viewport code in that case;

The reason is I need to access MISC_A register (0x96+) that is not in ulpi_regs structure - afaik it's vendor-specific.

Quoted 8 lines
Quoted 4 lines

Any hints how to tackle that properly?

I can of course duplicate ulpi code, but it probably doesn't make much sense.

I don't have a better suggestion, sorry. Let's keep this as-is unless someone can come up with something better. Code duplication is not a good idea, so we won't do that.

OK

Thanks,
Mateusz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWcerfAAoJELvtohmVtQzB1AMH/260Ioo6W6+skWJJhmm+g3yD B3kWhJWWyGPSkY4QcA7O/dgzU9i/n9a6gwlqcwYLhYlzyKG/p0aRBim0RWEFWK+S V1SMYA3iQhYLkjMdOfqNXdQ5NrG2osll1Nk2GK9wBthVtPkjqfQkOupw7oZq3kd5 3pNpbsREIuxfct26C7kaTJccRf7MIYdlslYu53h4T/t03oO8xBIrSDGAR+9UD841 yCWuATbg461uhPrD1/WBG/wiIzMaOsITyiXIkxr7Z0GNrOeaZ38YqSwASwLTUmxO NB+UkOvA9eM1oz79Qaoxyrfm/rDtds+CHXuFco2LY2gOl1280ffwKG1UQWCWDsk= =XMV7
-----END PGP SIGNATURE-----

#26 lore raw

RFC PATCH 6/11 drivers: Add SPMI bus uclass

In reply to Mateusz Kulikowski

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.

---

 drivers/Kconfig            |  2 ++
 drivers/Makefile           |  1 +
 drivers/spmi/Kconfig       | 10 +++++++++
 drivers/spmi/Makefile      |  7 ++++++
 drivers/spmi/spmi-uclass.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h     |  1 +
 include/spmi/spmi.h        | 44 ++++++++++++++++++++++++++++++++++++++
 7 files changed, 118 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
drivers/Kconfig +2 -0
index c481e93..4cbe976 100644
@@ -52,6 +52,8 @@ source "drivers/remoteproc/Kconfig"
 
 source "drivers/rtc/Kconfig"
 
+source "drivers/spmi/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/sound/Kconfig"
drivers/Makefile +1 -0
index c9031f2..7ae72c0 100644
@@ -53,6 +53,7 @@ obj-y += pcmcia/
 obj-y += dfu/
 obj-y += rtc/
 obj-y += sound/
+obj-y += spmi/
 obj-y += timer/
 obj-y += tpm/
 obj-y += twserial/
drivers/spmi/Kconfig new file +10 -0
new file mode 100644
index 0000000..2d8d78b
@@ -0,0 +1,10 @@
+menu "SPMI support"
+
+config DM_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
drivers/spmi/Makefile new file +7 -0
new file mode 100644
index 0000000..2015b1a
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_DM_SPMI)  += spmi-uclass.o
drivers/spmi/spmi-uclass.c new file +53 -0

53 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 27fa0b6..772e780 100644
@@ -57,6 +57,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 */
include/spmi/spmi.h new file +44 -0

44 lines not on this page · raw message

Signature · 1 line
2.5.0
#27 lore raw

RFC PATCH 6/11 drivers: Add SPMI bus uclass

Hi Matheusz,

Quoted 91 lines · Mateusz Kulikowski

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.

---

 drivers/Kconfig            |  2 ++
 drivers/Makefile           |  1 +
 drivers/spmi/Kconfig       | 10 +++++++++
 drivers/spmi/Makefile      |  7 ++++++
 drivers/spmi/spmi-uclass.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h     |  1 +
 include/spmi/spmi.h        | 44 ++++++++++++++++++++++++++++++++++++++
 7 files changed, 118 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
drivers/Kconfig +2 -0
index c481e93..4cbe976 100644
@@ -52,6 +52,8 @@ source "drivers/remoteproc/Kconfig"
 
 source "drivers/rtc/Kconfig"
 
+source "drivers/spmi/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/sound/Kconfig"
drivers/Makefile +1 -0
index c9031f2..7ae72c0 100644
@@ -53,6 +53,7 @@ obj-y += pcmcia/
 obj-y += dfu/
 obj-y += rtc/
 obj-y += sound/
+obj-y += spmi/
 obj-y += timer/
 obj-y += tpm/
 obj-y += twserial/
drivers/spmi/Kconfig new file +10 -0
new file mode 100644
index 0000000..2d8d78b
@@ -0,0 +1,10 @@
+menu "SPMI support"
+
+config DM_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
drivers/spmi/Makefile new file +7 -0
new file mode 100644
index 0000000..2015b1a
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_DM_SPMI)  += spmi-uclass.o
drivers/spmi/spmi-uclass.c new file +9 -0
new file mode 100644
index 0000000..981da68
@@ -0,0 +1,53 @@
+/*
+ * SPMI bus uclass driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>

drivers/spmi/spmi-uclass.c line 19

Quoted 10 lines
drivers/spmi/spmi-uclass.c new file +10 -0
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/root.h>
+#include <vsprintf.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <linux/ctype.h>
+#include <spmi/spmi.h>

Fix ordering

Quoted 53 lines
drivers/spmi/spmi-uclass.c new file +34 -0
+
+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 msm_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      = msm_spmi_post_bind,
+};
include/dm/uclass-id.h +1 -0
index 27fa0b6..772e780 100644
@@ -57,6 +57,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 */
include/spmi/spmi.h new file +1 -0
new file mode 100644
index 0000000..e06a79e
@@ -0,0 +1,44 @@
+#ifndef _SPMI_SPMI_H

include/spmi/spmi.h line 11

Quoted 10 lines
include/spmi/spmi.h new file +10 -0
+#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
+ * @write:     write register

You should describe the args also.

What is different between this and I2C? Could you use that uclass? It seems to have an additional address value (pid)- is that right?

If you do end up with a new uclass, please add a sandbox driver for it and a test.

Quoted 34 lines
include/spmi/spmi.h new file +33 -1
+ */
+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
+
--
Quoted 2 lines

2.5.0

Regards,
Simon

#28 lore raw

RFC PATCH 6/11 drivers: Add SPMI bus uclass

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Matheusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 11 lines

include/spmi/spmi.h line 11

Quoted 9 lines
include/spmi/spmi.h new file +9 -0
+
+/**
+ * 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
+ * @write:     write register

You should describe the args also.

OK

Quoted 3 lines

What is different between this and I2C? Could you use that uclass? It seems to have an additional address value (pid)- is that right?

That's a difficult question, as my knowledge about this bus is based only on drivers/SoC documentation/speculation (bus spec is not public :()

At wiring level it looks exactly like multi-master I2C
On logical level:
- - Each bus can have several slaves (up to 16).
- - Each slave can have several peripherals (up to 256),
- - Each peripheral can have up to 256 registers (I think each is 8-bit wide).
- - Each peripheral have 2 ID registers (type/subtype) that can be used for probing

PM8916 implements two slaves (but for some reason in Linux they are presented as 2 sibling nodes on SPMI bus).

But this is device perspective.

On SoC side, implementation is different and I fully don't understand all rationale behind it.

SoC has some kind of arbiter with 127 channels (2x - separate for reads called "observers" and separate for writers).

Each peripheral (not slave) has assigned single channel that I have to map in probe().
This means that (as far as I understand) there can be no more than 127 peripherals on single bus.

Weird think is that while doing reads/writes I have to use not only channel #, but also full slave/peripheral/register address.

Perhaps my driver oversimplified SPMI, or maybe SPMI is just I2C, using some simple protocol to charge royalty fees ;)

Quoted 3 lines

If you do end up with a new uclass, please add a sandbox driver for it and a test.

OK

Thanks,
Mateusz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWce82AAoJELvtohmVtQzBLUIH/1NX6eAd+eh+HTTdntsni109 yQKMJVPEE17znTtcYgW2hpgWLqUa9aZ6n97hWMiWF7N+3879kWJYLTgj2uFBiVgl nXS8DFdfE7BQlzwVrGLIoaIXC7Jx7w3O/+9k7XsTaU2QcX7E+rWjyj/Y88Uq8oen M/MdtU2eYY/SggdMd99dEn305LrhRpXhDx0qgPTwGGb7BPwB2Vfrvm7mUrXMGTTY GMbiKsNuiYzNdXGz65gmZ6fHHQM6Gmm5Lh5GYftMnn0qQA6D8PcDm8h+it1eqoW3 t1VpCmCp7k6eGzM6m+scwFHu0mCeGeYhYD+vRZIbxX0lu5UWIUuakVdjpJmn9Ig= =iZjm
-----END PGP SIGNATURE-----

#29 lore raw

RFC PATCH 7/11 drivers: spmi: Add support for Qualcomm SPMI bus driver

In reply to Mateusz Kulikowski

Support SPMI arbiter on Qualcomm Snapdragon devices.

---

 drivers/spmi/Kconfig    |   6 ++
 drivers/spmi/Makefile   |   1 +
 drivers/spmi/spmi-msm.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 drivers/spmi/spmi-msm.c
drivers/spmi/Kconfig +6 -0
index 2d8d78b..4f17df0 100644
@@ -7,4 +7,10 @@ config DM_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_MSM
+	boolean "Support Qualcomm SPMI bus"
+	depends on DM_SPMI
+	---help---
+	Support SPMI implementation found on Qualcomm Snapdragon SoCs.
 endmenu
drivers/spmi/Makefile +1 -0
index 2015b1a..419fe1d 100644
@@ -5,3 +5,4 @@
 #
 
 obj-$(CONFIG_DM_SPMI)  += spmi-uclass.o
+obj-$(CONFIG_SPMI_MSM) += spmi-msm.o
drivers/spmi/spmi-msm.c new file +183 -0

183 lines not on this page · raw message

Signature · 1 line
2.5.0
#30 lore raw

RFC PATCH 8/11 pmic: Add support for Qualcomm PM8916 PMIC

In reply to Mateusz Kulikowski

This PMIC is connected on SPMI bus so needs SPMI support enabled.

---

 drivers/power/pmic/Kconfig  | 14 +++++++
 drivers/power/pmic/Makefile |  1 +
 drivers/power/pmic/pm8916.c | 92 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+)
 create mode 100644 drivers/power/pmic/pm8916.c
drivers/power/pmic/Kconfig +14 -0
index fb29843..eb1dde0 100644
@@ -89,3 +89,17 @@ config PMIC_TPS65090
 	FETs and a battery charger. This driver provides register access
 	only, and you can enable the regulator/charger drivers separately if
 	required.
+
+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
drivers/power/pmic/Makefile +1 -0
index 91e78f8..ac653c7 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
 obj-$(CONFIG_PMIC_ACT8846) += act8846.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
 obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+obj-$(CONFIG_PMIC_PM8916) += pm8916.o
 
 obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
 obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
drivers/power/pmic/pm8916.c new file +92 -0

92 lines not on this page · raw message

Signature · 1 line
2.5.0
#31 lore raw

RFC PATCH 8/11 pmic: Add support for Qualcomm PM8916 PMIC

Hi Mateusz,

Quoted 23 lines · Mateusz Kulikowski

This PMIC is connected on SPMI bus so needs SPMI support enabled.

---

 drivers/power/pmic/Kconfig  | 14 +++++++
 drivers/power/pmic/Makefile |  1 +
 drivers/power/pmic/pm8916.c | 92 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+)
 create mode 100644 drivers/power/pmic/pm8916.c
drivers/power/pmic/Kconfig +4 -0
index fb29843..eb1dde0 100644
@@ -89,3 +89,17 @@ config PMIC_TPS65090
        FETs and a battery charger. This driver provides register access
        only, and you can enable the regulator/charger drivers separately if
        required.
+
+config PMIC_PM8916
+       bool "Enable Driver Model for Qualcomm PM8916 PMIC"
+       depends on DM_PMIC

drivers/power/pmic/Kconfig config PMIC_TPS65090 · line 105

Quoted 10 lines
drivers/power/pmic/Kconfig +10 -0
+       ---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

Nice help!

Quoted 23 lines
drivers/power/pmic/Makefile +1 -0
index 91e78f8..ac653c7 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
 obj-$(CONFIG_PMIC_ACT8846) += act8846.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
 obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+obj-$(CONFIG_PMIC_PM8916) += pm8916.o
 
 obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
 obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
drivers/power/pmic/pm8916.c new file +5 -0
new file mode 100644
index 0000000..5fe50ef
@@ -0,0 +1,92 @@
+/*
+ * Qualcomm pm8916 pmic driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *

drivers/power/pmic/pm8916.c line 15

Quoted 10 lines
drivers/power/pmic/pm8916.c new file +10 -0
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+#include <asm/gpio.h>
+#include <dm/root.h>

Fix ordering

drivers/power/pmic/pm8916.c line 20

Quoted 5 lines
drivers/power/pmic/pm8916.c new file +5 -0
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define EXTRACT_PID(x) (((x) >> 8) & 0xFF)
+#define EXTRACT_REG(x) ((x) & 0xFF)

Can you define

#define PID_SHIFT 8
#define PID_MASK (0xff << PID_SHIFT)

and use those? I prefer lower-case hex but there is no convention on that.

Quoted 37 lines
drivers/power/pmic/pm8916.c new file +37 -0
+
+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, EXTRACT_PID(reg),
+                             EXTRACT_REG(reg), *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, EXTRACT_PID(reg),
+                           EXTRACT_REG(reg));
+
+       if (val < 0)
+               return val;
+       *buff = val;
+       return 0;

drivers/power/pmic/pm8916.c line 67

Quoted 10 lines
drivers/power/pmic/pm8916.c new file +10 -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" },

Binding doc?

drivers/power/pmic/pm8916.c line 73

Quoted 6 lines
drivers/power/pmic/pm8916.c new file +6 -0
+       { }
+};
+
+static int pm8916_probe(struct udevice *dev)
+{
+       struct pm8916_priv *priv = dev_get_priv(dev);

blank line

Quoted 20 lines
drivers/power/pmic/pm8916.c new file +19 -1
+       priv->usid = dev_get_addr(dev);
+       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),
+};
--
Quoted 2 lines

2.5.0

Regards,
Simon

#32 lore raw

RFC PATCH 9/11 gpio: Add support for Qualcomm PM8916 gpios

In reply to Mateusz Kulikowski

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)

---

 drivers/gpio/Kconfig       |   7 ++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/pm8916_gpio.c | 306 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 314 insertions(+)
 create mode 100644 drivers/gpio/pm8916_gpio.c
drivers/gpio/Kconfig +7 -0
index 1d9443b..1fbdfeb 100644
@@ -53,6 +53,13 @@ config MSM_GPIO
 	help
 	  Support GPIO controllers on Qualcomm Snapdragon family of SoCs.
 
+config PM8916_GPIO
+	bool "Qualcomm PM8916 PMIC GPIO/keypad driver"
+	depends on DM_GPIO && PMIC_PM8916
+	help
+	  Support for GPIO1-GPIO4 pins and power/reset buttons found on
+	  Qualcomm PM8916 PMIC.
+
 config ROCKCHIP_GPIO
 	bool "Rockchip GPIO driver"
 	depends on DM_GPIO
drivers/gpio/Makefile +1 -0
index 9520b1e..aaa9f8d 100644
@@ -47,3 +47,4 @@ obj-$(CONFIG_ZYNQ_GPIO)		+= zynq_gpio.o
 obj-$(CONFIG_VYBRID_GPIO)	+= vybrid_gpio.o
 obj-$(CONFIG_HIKEY_GPIO)	+= hi6220_gpio.o
 obj-$(CONFIG_MSM_GPIO)		+= msm_gpio.o
+obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
drivers/gpio/pm8916_gpio.c new file +306 -0

306 lines not on this page · raw message

Signature · 1 line
2.5.0
#33 lore raw

RFC PATCH 9/11 gpio: Add support for Qualcomm PM8916 gpios

Hi Mateusz,

Quoted 52 lines · Mateusz Kulikowski

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)

---

 drivers/gpio/Kconfig       |   7 ++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/pm8916_gpio.c | 306 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 314 insertions(+)
 create mode 100644 drivers/gpio/pm8916_gpio.c
drivers/gpio/Kconfig +7 -0
index 1d9443b..1fbdfeb 100644
@@ -53,6 +53,13 @@ config MSM_GPIO
        help
          Support GPIO controllers on Qualcomm Snapdragon family of SoCs.
 
+config PM8916_GPIO
+       bool "Qualcomm PM8916 PMIC GPIO/keypad driver"
+       depends on DM_GPIO && PMIC_PM8916
+       help
+         Support for GPIO1-GPIO4 pins and power/reset buttons found on
+         Qualcomm PM8916 PMIC.
+
 config ROCKCHIP_GPIO
        bool "Rockchip GPIO driver"
        depends on DM_GPIO
drivers/gpio/Makefile +1 -0
index 9520b1e..aaa9f8d 100644
@@ -47,3 +47,4 @@ obj-$(CONFIG_ZYNQ_GPIO)               += zynq_gpio.o
 obj-$(CONFIG_VYBRID_GPIO)      += vybrid_gpio.o
 obj-$(CONFIG_HIKEY_GPIO)       += hi6220_gpio.o
 obj-$(CONFIG_MSM_GPIO)         += msm_gpio.o
+obj-$(CONFIG_PM8916_GPIO)      += pm8916_gpio.o
drivers/gpio/pm8916_gpio.c new file +5 -0
new file mode 100644
index 0000000..9214984
@@ -0,0 +1,306 @@
+/*
+ * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *

drivers/gpio/pm8916_gpio.c line 15

Quoted 10 lines
drivers/gpio/pm8916_gpio.c new file +10 -0
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <power/pmic.h>
+#include <spmi/spmi.h>
+#include <asm/gpio.h>

Ordering

Quoted 40 lines
drivers/gpio/pm8916_gpio.c new file +40 -0
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Register offset for each gpio */
+#define REG_OFFSET(x)          ((x) * 0x100)
+
+/* Register maps */
+#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_direction_input(struct udevice *dev, unsigned offset)
+{
+       struct pm8916_gpio_bank *priv = dev_get_priv(dev);
+       uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
+       int val, ret;

drivers/gpio/pm8916_gpio.c line 65

Quoted 10 lines
drivers/gpio/pm8916_gpio.c new file +10 -0
+
+       /* Disable the GPIO */
+       val = pmic_reg_read(dev->parent, gpio_base + REG_EN_CTL);
+       if (val < 0)
+               return val;
+
+       val &= ~REG_EN_CTL_ENABLE;
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_EN_CTL, val);
+       if (ret < 0)
+               return ret;

Can you use pmic_clrsetbits()?

Quoted 71 lines
drivers/gpio/pm8916_gpio.c new file +71 -0
+
+       /* Select the mode */
+       val = REG_CTL_MODE_INPUT;
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, val);
+       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;
+
+       /* 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;
+
+       /* Enable the GPIO */
+       val = pmic_reg_read(dev->parent, gpio_base + REG_EN_CTL);
+       if (val < 0)
+               return val;
+
+       val |= REG_EN_CTL_ENABLE;
+
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_EN_CTL, val);
+       return ret;
+}
+
+static int pm8916_gpio_direction_output(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);
+       int val, ret;
+
+       /* Disable the GPIO */
+       val = pmic_reg_read(dev->parent, gpio_base + REG_EN_CTL);
+       if (val < 0)
+               return val;
+
+       val &= REG_EN_CTL_ENABLE;
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_EN_CTL, val);
+       if (ret < 0)
+               return ret;
+
+       /* Select the mode and output value*/
+       val = REG_CTL_MODE_INOUT | (value ? 1 : 0);
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, val);
+       if (ret < 0)
+               return ret;
+
+       /* Set the right pull */
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
+                            REG_DIG_PULL_NO_PU);
+       if (ret < 0)
+               return ret;
+
+       /* Select the VIN - VIN0*/
+       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 */
+       val = REG_DIG_OUT_CTL_CMOS | REG_DIG_OUT_CTL_DRIVE_L;
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL, val);
+       if (ret < 0)
+               return ret;
+

drivers/gpio/pm8916_gpio.c line 146

Quoted 10 lines
drivers/gpio/pm8916_gpio.c new file +10 -0
+       /* Enable the GPIO */
+       val = pmic_reg_read(dev->parent, gpio_base + REG_EN_CTL);
+       if (val < 0)
+               return val;
+
+       val |= REG_EN_CTL_ENABLE;
+
+       ret = pmic_reg_write(dev->parent, gpio_base + REG_EN_CTL, val);
+       return ret;
+}

Any chance that the above two functions have some common elements that could go in a shared function?

drivers/gpio/pm8916_gpio.c line 159

Quoted 13 lines
drivers/gpio/pm8916_gpio.c new file +13 -0
+
+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;
+
+       if ((reg & REG_CTL_MODE_MASK) == REG_CTL_MODE_INPUT)

How about:

switch (reg & ...) {
case ...
}

drivers/gpio/pm8916_gpio.c line 172

Quoted 13 lines
drivers/gpio/pm8916_gpio.c new file +13 -0
+               return GPIOF_INPUT;
+       if ((reg & REG_CTL_MODE_MASK) == REG_CTL_MODE_INOUT)
+               return GPIOF_OUTPUT;
+       if ((reg & REG_CTL_MODE_MASK) == REG_CTL_MODE_OUTPUT)
+               return GPIOF_OUTPUT;
+       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;

Suggest ret as it is not always a register. pmic_reg_read() returns an error code sometimes.

Quoted 13 lines
drivers/gpio/pm8916_gpio.c new file +13 -0
+
+       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);

drivers/gpio/pm8916_gpio.c line 195

Quoted 10 lines
drivers/gpio/pm8916_gpio.c new file +10 -0
+       int reg;
+
+       /* Set the output value of the gpio */
+       reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
+       if (reg < 0)
+               return reg;
+
+       reg = (reg & ~REG_CTL_OUTPUT_MASK) | value;
+
+       return pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg);

pmic_clrsetbits()?

Quoted 22 lines
drivers/gpio/pm8916_gpio.c new file +22 -0
+}
+
+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);
+       priv->pid = dev_get_addr(dev);
+       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,

drivers/gpio/pm8916_gpio.c line 227

Quoted 10 lines
drivers/gpio/pm8916_gpio.c new file +10 -0
+                                            "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" },

Binding doc?

Quoted 80 lines
drivers/gpio/pm8916_gpio.c new file +79 -1
+       { }
+};
+
+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);
+
+       priv->pid = dev_get_addr(dev);
+       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;
+       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),
+};
--
Quoted 2 lines

2.5.0

Regards,
Simon

#34 lore raw

RFC PATCH 10/11 arm: Add support for Qualcomm Snapdragon family

In reply to Mateusz Kulikowski

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)

---

 arch/arm/Kconfig                                   |  12 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/mach-snapdragon/Kconfig                   |   6 +
 arch/arm/mach-snapdragon/Makefile                  |   8 +
 arch/arm/mach-snapdragon/clock-apq8016.c           | 262 +++++++++++++++++++++
 arch/arm/mach-snapdragon/include/mach/gpio.h       |  25 ++
 .../mach-snapdragon/include/mach/sysmap-apq8016.h  |  15 ++
 arch/arm/mach-snapdragon/reset.c                   |  40 ++++
 8 files changed, 369 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
arch/arm/Kconfig +12 -0
index fb9176b..0241980 100644
@@ -493,6 +493,16 @@ config OMAP54XX
 	select CPU_V7
 	select SUPPORT_SPL
 
+config ARCH_SNAPDRAGON
+	bool "Qualcomm Snapdragon SoCs"
+	select ARM64
+	select DM
+	select DM_GPIO
+	select DM_SERIAL
+	select DM_SPMI
+	select OF_CONTROL
+	select OF_SEPARATE
+
 config RMOBILE
 	bool "Renesas ARM SoCs"
 	select CPU_V7
@@ -745,6 +755,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-tegra/Kconfig"
arch/arm/Makefile +1 -0
index 18283d1..b977309 100644
@@ -54,6 +54,7 @@ machine-$(CONFIG_ARMADA_XP)		+= 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_TEGRA)			+= tegra
arch/arm/mach-snapdragon/Kconfig new file +6 -0
new file mode 100644
index 0000000..156e733
@@ -0,0 +1,6 @@
+if ARCH_SNAPDRAGON
+
+config SYS_SOC
+	default "snapdragon"
+
+endif
arch/arm/mach-snapdragon/Makefile new file +8 -0
new file mode 100644
index 0000000..8e84705
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += clock-apq8016.o
+obj-y += reset.o
arch/arm/mach-snapdragon/clock-apq8016.c new file +262 -0

262 lines not on this page · raw message

arch/arm/mach-snapdragon/include/mach/gpio.h new file +25 -0
new file mode 100644
index 0000000..e2ce28b
@@ -0,0 +1,25 @@
+/*
+ * Qualcomm GPIO definitions
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef _MACH_GPIO_H
+#define _MACH_GPIO_H
+
+/* 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
+
+#endif /* _ASM_ARCH_GPIO_H */
+
arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h new file +15 -0
new file mode 100644
index 0000000..32bc761
@@ -0,0 +1,15 @@
+/*
+ * Qualcomm APQ8916 sysmap
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef _MACH_APQ8016_SYSMAP_H
+#define _MACH_APQ8016_SYSMAP_H
+
+#define GICD_BASE 0x0b000000
+#define GICC_BASE 0x0a20c000
+
+#endif
+
arch/arm/mach-snapdragon/reset.c new file +40 -0
new file mode 100644
index 0000000..ade3237
@@ -0,0 +1,40 @@
+/*
+ * Qualcomm APQ8016 reset controller driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * 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(reset_sandbox) = {
+	.name		= "msm_reset",
+	.id		= UCLASS_RESET,
+	.of_match	= msm_reset_ids,
+	.ops		= &msm_reset_ops,
+};
Signature · 1 line
2.5.0
#35 lore raw

RFC PATCH 10/11 arm: Add support for Qualcomm Snapdragon family

Hi Mateusz,

arch/arm/mach-snapdragon/clock-apq8016.c

Quoted 98 lines · Mateusz Kulikowski

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)

---

 arch/arm/Kconfig                                   |  12 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/mach-snapdragon/Kconfig                   |   6 +
 arch/arm/mach-snapdragon/Makefile                  |   8 +
 arch/arm/mach-snapdragon/clock-apq8016.c           | 262 +++++++++++++++++++++
 arch/arm/mach-snapdragon/include/mach/gpio.h       |  25 ++
 .../mach-snapdragon/include/mach/sysmap-apq8016.h  |  15 ++
 arch/arm/mach-snapdragon/reset.c                   |  40 ++++
 8 files changed, 369 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
arch/arm/Kconfig +12 -0
index fb9176b..0241980 100644
@@ -493,6 +493,16 @@ config OMAP54XX
        select CPU_V7
        select SUPPORT_SPL
 
+config ARCH_SNAPDRAGON
+       bool "Qualcomm Snapdragon SoCs"
+       select ARM64
+       select DM
+       select DM_GPIO
+       select DM_SERIAL
+       select DM_SPMI
+       select OF_CONTROL
+       select OF_SEPARATE
+
 config RMOBILE
        bool "Renesas ARM SoCs"
        select CPU_V7
@@ -745,6 +755,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-tegra/Kconfig"
arch/arm/Makefile +1 -0
index 18283d1..b977309 100644
@@ -54,6 +54,7 @@ machine-$(CONFIG_ARMADA_XP)           += 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_TEGRA)                        += tegra
arch/arm/mach-snapdragon/Kconfig new file +6 -0
new file mode 100644
index 0000000..156e733
@@ -0,0 +1,6 @@
+if ARCH_SNAPDRAGON
+
+config SYS_SOC
+       default "snapdragon"
+
+endif
arch/arm/mach-snapdragon/Makefile new file +8 -0
new file mode 100644
index 0000000..8e84705
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y += clock-apq8016.o
+obj-y += reset.o
arch/arm/mach-snapdragon/clock-apq8016.c new file +0 -0
new file mode 100644
index 0000000..c8c15b4

Can this go in drivers/clk?

Quoted 7 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +6 -0
@@ -0,0 +1,262 @@
+/*
+ * Clock drivers for Qualcomm APQ8016
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * Based on Little Kernel driver, simplified

arch/arm/mach-snapdragon/clock-apq8016.c line 16

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+ *
+ * SPDX-License-Identifier:    BSD-3-Clause
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <clk.h>
+#include <common.h>
+#include <errno.h>
+#include <linux/bitops.h>

Ordering - please fix globally.

Quoted 5 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +5 -0
+
+/* GPLL0 clock control registers */
+#define GPLL0_STATUS        0x2101C
+#define GPLL0_STATUS_ACTIVE BIT(17)
+

arch/arm/mach-snapdragon/clock-apq8016.c line 31

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+#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 reset*/

/* block reset */

arch/arm/mach-snapdragon/clock-apq8016.c line 32

Quoted 1 line
arch/arm/mach-snapdragon/clock-apq8016.c new file +1 -0
+#define SDCC_BCR(n)                 (((n*0x1000)) + 0x41000)

Can you put spaces around operators? (n * 0x1000)

Quoted 22 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +22 -0
+/* 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

arch/arm/mach-snapdragon/clock-apq8016.c line 64

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+#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 {
+       void *base;

You might consider using a struct to access registers to avoid all the void * but it is up to you - we do both now.

arch/arm/mach-snapdragon/clock-apq8016.c line 70

Quoted 6 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +6 -0
+};
+
+/* Enable clock controlled by CBC soft macro */
+static void clk_enable_cbc(void *cbcr)
+{
+       uint32_t val = readl(cbcr);

blank line

Quoted 8 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +8 -0
+       val |= CBCR_BRANCH_ENABLE_BIT;
+       writel(val, cbcr);
+
+       while (readl(cbcr) & CBCR_BRANCH_OFF_BIT)
+               ;
+}
+
+/* clock has 800MHz */

arch/arm/mach-snapdragon/clock-apq8016.c line 88

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+static void clk_enable_gpll0(void *base)
+{
+       uint32_t ena;
+
+       if (readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE)
+               return; /* clock already enabled */
+
+       ena = readl(base + APCS_GPLL_ENA_VOTE);
+       ena |= APCS_GPLL_ENA_VOTE_GPLL0;
+       writel(ena, base + APCS_GPLL_ENA_VOTE);

setbits_le32(base + APCS_GPLL_ENA_VOTE, APCS_GPLL_ENA_VOTE_GPLL0)

Similarly below.

Quoted 32 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +32 -0
+
+       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(void *apps_cmd_rgcr)
+{
+       uint32_t cmd;
+
+       cmd  = readl(apps_cmd_rgcr);
+       cmd |= APPS_CMD_RGCR_UPDATE;
+       writel(cmd, apps_cmd_rgcr);
+
+       /* 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 */
+

arch/arm/mach-snapdragon/clock-apq8016.c line 130

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+/* 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 BM(msb, lsb)     (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))

Best to avoid these sorts of things if possible, and just use MASK and SHIFT #defines.

Quoted 7 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +7 -0
+
+/* root set rate for clocks with half integer and MND divider */
+static void clk_rcg_set_rate_mnd(void *base, const struct bcr_regs *regs,
+                                int div, int m, int n, int source)
+{
+       uint32_t cfg;
+       /* This register houses the M value for MND divider. */

arch/arm/mach-snapdragon/clock-apq8016.c line 147

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+       uint32_t m_val = m;
+       /* This register houses the NOT(N-M) value for MND divider. */
+       uint32_t n_val = ~((n)-(m)) * !!(n);
+       /* This register houses the NOT 2D value for MND divider. */
+       uint32_t d_val = ~(n);
+
+       /* Program MND values */
+       writel(m_val, base + regs->M); /* M */
+       writel(n_val, base + regs->N); /* N */
+       writel(d_val, base + regs->D); /* D */

Those 3 comments don't seem useful.

Quoted 36 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +36 -0
+
+       /* setup src select and divider */
+       cfg  = readl(base + regs->cfg_rcgr);
+       cfg &= ~CFG_MASK;
+       cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */
+       cfg |= BVAL(4, 0, (int)(2*(div) - 1))  | BVAL(10, 8, source);
+       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 *p, int slot, uint rate)
+{
+       int div = 8; /* 100MHz default */

arch/arm/mach-snapdragon/clock-apq8016.c line 193

Quoted 10 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +10 -0
+
+       if (rate == 200000000)
+               div = 4;
+
+       clk_enable_cbc(p->base + SDCC_AHB_CBCR(slot));
+       /* 800Mhz/div, gpll0 */
+       clk_rcg_set_rate_mnd(p->base, &sdc_regs[slot], div, 0, 0,
+                            CFG_CLK_SRC_GPLL0);
+       clk_enable_gpll0(p->base);
+       clk_enable_cbc(p->base + SDCC_APPS_CBCR(slot));

blank line before return

arch/arm/mach-snapdragon/include/mach/gpio.h

Quoted 74 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +69 -0
+       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 *p)
+{
+       /* Enable iface clk */
+       clk_enable_cbc(p->base + BLSP1_AHB_CBCR);
+       /* 7372800 uart block clock @ GPLL0 */
+       clk_rcg_set_rate_mnd(p->base, &uart2_regs, 1, 144, 15625,
+                            CFG_CLK_SRC_GPLL0);
+       clk_enable_gpll0(p->base);
+       /* Enable core clk */
+       clk_enable_cbc(p->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;
+       }
+       return 0;
+}
+
+static int msm_clk_probe(struct udevice *dev)
+{
+       struct msm_clk_priv *priv = dev_get_priv(dev);
+       priv->base = (void *)dev_get_addr(dev);
+       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" },
+       { }
+};
+
+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,
+};
arch/arm/mach-snapdragon/include/mach/gpio.h new file +0 -0
new file mode 100644
index 0000000..e2ce28b

Should this go in a different patch? I thought you had a GPIO driver earlier?

Quoted 34 lines
arch/arm/mach-snapdragon/include/mach/gpio.h new file +25 -0
@@ -0,0 +1,25 @@
+/*
+ * Qualcomm GPIO definitions
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#ifndef _MACH_GPIO_H
+#define _MACH_GPIO_H
+
+/* 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
+
+#endif /* _ASM_ARCH_GPIO_H */
+
arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h new file +2 -0
new file mode 100644
index 0000000..32bc761
@@ -0,0 +1,15 @@
+/*
+ * Qualcomm APQ8916 sysmap

arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h line 12

Quoted 10 lines
arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h new file +10 -0
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#ifndef _MACH_APQ8016_SYSMAP_H
+#define _MACH_APQ8016_SYSMAP_H
+
+#define GICD_BASE 0x0b000000
+#define GICC_BASE 0x0a20c000

Do you need these? Perhaps they can go in the device tree?

Quoted 50 lines
arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h new file +3 -0
+
+#endif
+
arch/arm/mach-snapdragon/reset.c new file +40 -1
new file mode 100644
index 0000000..ade3237
@@ -0,0 +1,40 @@
+/*
+ * Qualcomm APQ8016 reset controller driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * 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(reset_sandbox) = {
+       .name           = "msm_reset",
+       .id             = UCLASS_RESET,
+       .of_match       = msm_reset_ids,
+       .ops            = &msm_reset_ops,
+};
--
Quoted 2 lines

2.5.0

Regards,
Simon

#36 lore raw

RFC PATCH 10/11 arm: Add support for Qualcomm Snapdragon family

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 7 lines

arch/arm/mach-snapdragon/clock-apq8016.c

Quoted 5 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +0 -0
new file mode 100644
index 0000000..c8c15b4

Can this go in drivers/clk?

Yes, it can, but it's very SoC specific (at least for now). That is - it will probably work only on 2 devices (APQ8016 and MSM8916).

[...]

Quoted 3 lines
Quoted 1 line

+++ b/arch/arm/mach-snapdragon/include/mach/gpio.h

Should this go in a different patch? I thought you had a GPIO driver earlier?

Ouch... yeah, this should definitely go to msm_gpio

[...]

Quoted 6 lines

arch/arm/mach-snapdragon/clock-apq8016.c

Quoted 4 lines
arch/arm/mach-snapdragon/clock-apq8016.c new file +4 -0
+#define _MACH_APQ8016_SYSMAP_H
+
+#define GICD_BASE 0x0b000000
+#define GICC_BASE 0x0a20c000

Do you need these? Perhaps they can go in the device tree?

Nope, at least not for now.

It's required by armv8/start.S so must go either to board file or here :(

Regards,
Mateusz

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWdUmXAAoJELvtohmVtQzBsHwIAIgP+U8rmDlDEGDnFXeN+cuy xUv5wQQwOWI+KuIQtJnO99UTPmJqNkk/NrnKF5P2p9Mgo/yD3YK3teaaMkrtipbu D8Aw62XxhPXciy5ZC1pdrKXHt29halZZwSX4BAwf2Drtp7LVZ7UmUDQlQQF4p/9Z FAr4Ynk8B8Ut0XObX1hjs2IPcdRT2V2wU5Wd/mv4EixH7wfiGMhBmroxg94Y7W2q ZjlxUNdLmjqJkbDzkXwDv5emil5HWtKkUxe9y4qg7nwGQgOf4NP0r4dUDzGHRrGH 20pr2VfwMS2mR7nfFrLAFxTM1Q/o6e26o5hLtGqvGLzqmEwdHz06zOwzgB0hRlE= =rcwn
-----END PGP SIGNATURE-----

#37 lore raw

RFC PATCH 11/11 board: Add Qualcomm Dragonboard 410C support

In reply to Mateusz Kulikowski

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.

This is code is cleaned-up version of code I did last month that is already used by some people:
https://github.com/hallor/u-boot

---

 arch/arm/dts/Makefile                            |   2 +
 arch/arm/dts/dragonboard410c.dts                 | 157 +++++++++++++++++++
 arch/arm/mach-snapdragon/Kconfig                 |   9 ++
 board/qualcomm/dragonboard410c/Kconfig           |  15 ++
 board/qualcomm/dragonboard410c/Makefile          |   8 +
 board/qualcomm/dragonboard410c/dragonboard410c.c | 111 ++++++++++++++
 board/qualcomm/dragonboard410c/head.S            |  20 +++
 board/qualcomm/dragonboard410c/readme.txt        |  40 +++++
 board/qualcomm/dragonboard410c/u-boot.lds        |  90 +++++++++++
 configs/dragonboard410c_defconfig                |  29 ++++
 include/configs/dragonboard410c.h                | 184 +++++++++++++++++++++++
 11 files changed, 665 insertions(+)
 create mode 100644 arch/arm/dts/dragonboard410c.dts
 create mode 100644 board/qualcomm/dragonboard410c/Kconfig
 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
arch/arm/dts/Makefile +2 -0
index 521aa4c..1154993 100644
@@ -95,6 +95,8 @@ dtb-$(CONFIG_FSL_LSCH3) += fsl-ls2080a-qds.dtb \
 dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds.dtb \
 	fsl-ls1043a-rdb.dtb
 
+dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb
+
 dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-a1000.dtb \
 	sun4i-a10-ba10-tvbox.dtb \
arch/arm/dts/dragonboard410c.dts new file +157 -0

157 lines not on this page · raw message

arch/arm/mach-snapdragon/Kconfig +9 -0
index 156e733..61e0e9e 100644
@@ -3,4 +3,13 @@ if ARCH_SNAPDRAGON
 config SYS_SOC
 	default "snapdragon"
 
+choice
+	prompt "Snapdragon board select"
+
+config TARGET_DRAGONBOARD410C
+	bool "96Boards Dragonboard 410C"
+endchoice
+
+source "board/qualcomm/dragonboard410c/Kconfig"
+
 endif
board/qualcomm/dragonboard410c/Kconfig new file +15 -0
new file mode 100644
index 0000000..03bd7ae
@@ -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
board/qualcomm/dragonboard410c/Makefile new file +8 -0
new file mode 100644
index 0000000..cd67808
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= dragonboard410c.o
+extra-y += head.o
board/qualcomm/dragonboard410c/dragonboard410c.c new file +111 -0

111 lines not on this page · raw message

board/qualcomm/dragonboard410c/head.S new file +20 -0
new file mode 100644
index 0000000..00d6d97
@@ -0,0 +1,20 @@
+#include <config.h>
+
+.global _fastboot_header
+_fastboot_header:
+	b _start
+	add     x13, x18, #0x16
+	// 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
+	// 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
board/qualcomm/dragonboard410c/readme.txt new file +40 -0
new file mode 100644
index 0000000..0f575db
@@ -0,0 +1,40 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+Build & Run instructions:
+
+1) Install mkbootimg 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, use dtbTool to generate it
+$ dtbTool -o dt.img arch/arm/dts
+
+7) generate image with mkbootimg:
+$ mkbootimg --kernel=u-boot-dtb.bin --output=u-boot.img --dt=dt.img  --pagesize 2048 --base 0x80000000 --ramdisk=rd --cmdline=""
+
+Boot it with fastboot:
+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)
board/qualcomm/dragonboard410c/u-boot.lds new file +90 -0

90 lines not on this page · raw message

configs/dragonboard410c_defconfig new file +29 -0
new file mode 100644
index 0000000..7dd9aae
@@ -0,0 +1,29 @@
+CONFIG_ARM=y
+CONFIG_ARM64=y
+CONFIG_ARCH_SNAPDRAGON=y
+CONFIG_TARGET_DRAGONBOARD410C=y
+
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="dragonboard410c => "
+CONFIG_CMD_USB=y
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+CONFIG_DEFAULT_DEVICE_TREE="dragonboard410c"
+
+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_SPMI_MSM=y
+CONFIG_MSM_SERIAL=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_STORAGE=y
include/configs/dragonboard410c.h new file +184 -0

184 lines not on this page · raw message

Signature · 1 line
2.5.0
#38 lore raw

RFC PATCH 11/11 board: Add Qualcomm Dragonboard 410C support

Hi Mateusz,

Quoted 227 lines · Mateusz Kulikowski

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.

This is code is cleaned-up version of code I did last month that is already used by some people:
https://github.com/hallor/u-boot

---

 arch/arm/dts/Makefile                            |   2 +
 arch/arm/dts/dragonboard410c.dts                 | 157 +++++++++++++++++++
 arch/arm/mach-snapdragon/Kconfig                 |   9 ++
 board/qualcomm/dragonboard410c/Kconfig           |  15 ++
 board/qualcomm/dragonboard410c/Makefile          |   8 +
 board/qualcomm/dragonboard410c/dragonboard410c.c | 111 ++++++++++++++
 board/qualcomm/dragonboard410c/head.S            |  20 +++
 board/qualcomm/dragonboard410c/readme.txt        |  40 +++++
 board/qualcomm/dragonboard410c/u-boot.lds        |  90 +++++++++++
 configs/dragonboard410c_defconfig                |  29 ++++
 include/configs/dragonboard410c.h                | 184 +++++++++++++++++++++++
 11 files changed, 665 insertions(+)
 create mode 100644 arch/arm/dts/dragonboard410c.dts
 create mode 100644 board/qualcomm/dragonboard410c/Kconfig
 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
arch/arm/dts/Makefile +2 -0
index 521aa4c..1154993 100644
@@ -95,6 +95,8 @@ dtb-$(CONFIG_FSL_LSCH3) += fsl-ls2080a-qds.dtb \
 dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds.dtb \
        fsl-ls1043a-rdb.dtb
 
+dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb
+
 dtb-$(CONFIG_MACH_SUN4I) += \
        sun4i-a10-a1000.dtb \
        sun4i-a10-ba10-tvbox.dtb \
arch/arm/dts/dragonboard410c.dts new file +157 -0
new file mode 100644
index 0000000..04ad9eb
@@ -0,0 +1,157 @@
+/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 at 78b0000";
+       };
+
+
+       soc {
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+               ranges = <0x0 0x0 0x0 0xffffffff>;
+               compatible = "simple-bus";
+
+               clkc: qcom,gcc at 1800000 {
+                       compatible = "qcom,gcc-msm8916";
+                       reg = <0x1800000 0x80000>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+               };
+
+               serial at 78b0000 {
+                       compatible = "qcom,msm-uartdm-v1.4";
+                       reg = <0x78b0000 0x200>;
+                       u-boot,dm-pre-reloc;
+                       clock = <&clkc 4>;
+               };
+
+               restart at 4ab000 {
+                       compatible = "qcom,pshold";
+                       reg = <0x4ab000 0x4>;
+               };
+
+               soc_gpios: pinctrl at 1000000 {
+                       compatible = "qcom,msm8916-pinctrl";
+                       reg = <0x1000000 0x300000>;
+                       gpio-controller;
+                       gpio-count = <122>;
+                       gpio-bank-name="soc";
+                       #gpio-cells = <1>;
+               };
+
+               ehci at 78d9000 {
+                       compatible = "qcom,ehci-host";
+                       reg = <0x78d9000 0x400>;
+               };
+
+               sdhci at 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 at 07864000 {
+                       compatible = "qcom,sdhci-msm-v4";
+                       reg = <0x7864900 0x11c 0x7864000 0x800>;
+                       index = <0x1>;
+                       bus-width = <0x4>;
+                       clock = <&clkc 1>;
+                       clock-frequency = <200000000>;
+               };
+
+               spmi at 200f000 {
+                       compatible = "qcom,spmi-pmic-arb";
+                       reg = <0x200f000 0x1000 0x2400000 0x400000 0x2c00000 0x400000 0x3800000 0x200000 0x200a000 0x2100>;
+                       reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+                       #address-cells = <0x1>;
+                       #size-cells = <0x1>;
+                       pm8916 at 0 {
+                               compatible = "qcom,spmi-pmic";
+                               reg = <0x0 0x2>;
+                               #address-cells = <0x1>;
+                               #size-cells = <0x1>;
+
+                               pmic_pon: pon at 800 {
+                                       compatible = "qcom,pm8916-pwrkey";
+                                       reg = <0x800 0x96>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                               };
+
+                               pmic_gpios: gpios at c000 {
+                                       compatible = "qcom,pm8916-gpio";
+                                       reg = <0xc000 0x400>;
+                                       gpio-controller;
+                                       gpio-count = <4>;
+                                       #gpio-cells = <2>;
+                                       gpio-bank-name="pmic";
+                               };
+                       };
+
+                       pm8916 at 1 {
+                               compatible = "qcom,spmi-pmic";
+                               reg = <0x1>;
+                               #address-cells = <0x1>;
+                               #size-cells = <0x0>;
+                       };
+               };
+       };
+
+       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 = <&pmic_gpios 0 0>;
+               };
+
+               user4 {
+                       label = "green:user4";
+                       gpios = <&pmic_gpios 1 0>;
+               };
+       };
+
+       usb_hub_reset_n_pm {
+               gpios = <&pmic_gpios 2 0>;
+       };
+
+       usb_sw_sel_pm {
+               gpios = <&pmic_gpios 3 0>;
+       };
+
+       key_vol_down {
+               gpios = <&pmic_pon 1 0>;
+       };
+
+       key_power {
+               gpios = <&pmic_pon 0 0>;
+       };
+};
arch/arm/mach-snapdragon/Kconfig +0 -0
index 156e733..61e0e9e 100644

arch/arm/mach-snapdragon/Kconfig if ARCH_SNAPDRAGON · line 10

Quoted 8 lines
arch/arm/mach-snapdragon/Kconfig +5 -0
@@ -3,4 +3,13 @@ if ARCH_SNAPDRAGON
 config SYS_SOC
        default "snapdragon"
 
+choice
+       prompt "Snapdragon board select"
+
+config TARGET_DRAGONBOARD410C
+       bool "96Boards Dragonboard 410C"

help

Rough description of the board and its peripherals. Should be 3-4 lines.

Quoted 64 lines
arch/arm/mach-snapdragon/Kconfig +4 -0
+endchoice
+
+source "board/qualcomm/dragonboard410c/Kconfig"
+
 endif
board/qualcomm/dragonboard410c/Kconfig new file +15 -0
new file mode 100644
index 0000000..03bd7ae
@@ -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
board/qualcomm/dragonboard410c/Makefile new file +8 -0
new file mode 100644
index 0000000..cd67808
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y  := dragonboard410c.o
+extra-y += head.o
board/qualcomm/dragonboard410c/dragonboard410c.c new file +18 -0
new file mode 100644
index 0000000..7057a2c
@@ -0,0 +1,111 @@
+/*
+ * Board init file for Dragonboard 410C
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+
+ * 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;

board/qualcomm/dragonboard410c/dragonboard410c.c line 28

Quoted 10 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +10 -0
+       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;
+}
+
+static struct gpio_desc hub_reset, usb_sel;

Can these just be local variables in the function below? I doubt the function is called more than once.

board/qualcomm/dragonboard410c/dragonboard410c.c line 37

Quoted 9 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +9 -0
+
+int board_prepare_usb(enum usb_init_type type)
+{
+       int ret = 0, node;
+
+       /* 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, 0,
+                                         "usb_hub_reset_n_pm");

Is this really the standard binding? I would expect a USB node with a reset-gpios property.

Quoted 46 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +46 -0
+               if (node < 0) {
+                       printf("Failed to find usb_hub_reset_n_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_n_pm gpio.\n");
+                       return ret;
+               }
+       }
+
+       if (!dm_gpio_is_valid(&usb_sel)) {
+               node = fdt_subnode_offset(gd->fdt_blob, 0, "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)
+{

board/qualcomm/dragonboard410c/dragonboard410c.c line 93

Quoted 10 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +10 -0
+       return 0;
+}
+
+/* Check for vol- button - if pressed - stop autoboot */
+int misc_init_r(void)
+{
+       int node;
+       struct gpio_desc resin;
+
+       node = fdt_subnode_offset(gd->fdt_blob, 0, "key_vol_down");

Should this be a GPIO key?

Quoted 99 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +18 -0
+       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;
+}
board/qualcomm/dragonboard410c/head.S new file +20 -0
new file mode 100644
index 0000000..00d6d97
@@ -0,0 +1,20 @@
+#include <config.h>
+
+.global _fastboot_header
+_fastboot_header:
+       b _start
+       add     x13, x18, #0x16
+       // 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
+       // 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
board/qualcomm/dragonboard410c/readme.txt new file +40 -0
new file mode 100644
index 0000000..0f575db
@@ -0,0 +1,40 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+Build & Run instructions:
+
+1) Install mkbootimg 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, use dtbTool to generate it
+$ dtbTool -o dt.img arch/arm/dts
+
+7) generate image with mkbootimg:
+$ mkbootimg --kernel=u-boot-dtb.bin --output=u-boot.img --dt=dt.img  --pagesize 2048 --base 0x80000000 --ramdisk=rd --cmdline=""
+
+Boot it with fastboot:
+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)
board/qualcomm/dragonboard410c/u-boot.lds new file +3 -0
new file mode 100644
index 0000000..3fb4235
@@ -0,0 +1,90 @@
+/*
+ * Override linker script for fastboot-readable images
+ *

board/qualcomm/dragonboard410c/u-boot.lds line 13

Quoted 10 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +10 -0
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * 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(_fastboot_header)

I wonder if you could use the standard .lds file and amend it to support fastboot?

Quoted 102 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +77 -0
+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*) }
+}
configs/dragonboard410c_defconfig new file +19 -0
new file mode 100644
index 0000000..7dd9aae
@@ -0,0 +1,29 @@
+CONFIG_ARM=y
+CONFIG_ARM64=y
+CONFIG_ARCH_SNAPDRAGON=y
+CONFIG_TARGET_DRAGONBOARD410C=y
+
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="dragonboard410c => "
+CONFIG_CMD_USB=y
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+CONFIG_DEFAULT_DEVICE_TREE="dragonboard410c"
+
+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

configs/dragonboard410c_defconfig line 29

Quoted 10 lines
configs/dragonboard410c_defconfig new file +10 -0
+CONFIG_MSM_SDHCI=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_PM8916=y
+CONFIG_SPMI_MSM=y
+CONFIG_MSM_SERIAL=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_STORAGE=y

CONFIG_DM_ETH=y

Quoted 191 lines
include/configs/dragonboard410c.h new file +184 -1
new file mode 100644
index 0000000..132ed75
@@ -0,0 +1,184 @@
+/*
+ * Board configuration file for Dragonboard 410C
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
+ *
+ * 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 */
+
+/* Flat Device Tree Definitions */
+#define CONFIG_OF_LIBFDT
+
+/* 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
+/* Needed for Host Controller driver */
+#define CONFIG_USB_ULPI_VIEWPORT
+
+#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_DHCP
+#define CONFIG_CMD_ENV
+#define CONFIG_CMD_FAT         /* FAT support                  */
+#define CONFIG_CMD_GPIO
+#define CONFIG_CMD_GPT
+#define CONFIG_CMD_MD5SUM
+#define CONFIG_CMD_MEMINFO     /* 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_PING
+#define CONFIG_CMD_REGINFO     /* Register dump                */
+#define CONFIG_CMD_TFTP
+#define CONFIG_CMD_TIMER
+#define CONFIG_CMD_UNZIP
+#define CONFIG_CMD_BOOTZ
+#define CONFIG_CMD_BOOTI
+
+/* Command line configuration */
+#define CONFIG_MENU
+#define CONFIG_SYS_LONGHELP
+
+/* Partition table support */
+#define HAVE_BLOCK_DEVICE /* Needed for partition commands */
+#define CONFIG_DOS_PARTITION
+#define CONFIG_EFI_PARTITION
+#define CONFIG_PARTITION_UUIDS
+
+/* BOOTP options */
+#define CONFIG_BOOTP_BOOTFILESIZE
+
+/* Environment - Boot*/
+#define CONFIG_BOOTDELAY               2       /* autoboot after 2 seconds */
+
+#define CONFIG_NFSBOOTCOMMAND ""
+#define CONFIG_BOOTCOMMAND "usb start && dhcp && tftp && usb stop && bootm"
+#define CONFIG_BOOTARGS "console=ttyMSM0,115200n8"
+
+/* 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"
+
+#define CONFIG_UBOOT_REFLASH \
+"mmc dev 0 &&"\
+"usb start &&"\
+"dhcp &&"\
+"part start mmc 0 8 start && "\
+"setenv size 0x800  &&"\
+"tftp $loadaddr dragonboard/u-boot.img &&" \
+"mmc write $loadaddr $start $size &&"\
+"usb stop &&"\
+"echo Reflash completed &&" \
+"reset"
+
+/* Environment */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+       "reflash="CONFIG_ENV_REFLASH"\0"\
+       "reflash_uboot="CONFIG_UBOOT_REFLASH"\0"\
+       "loadaddr=0x81000000\0" \
+       "fdt_high=0xffffffffffffffff\0" \
+       "initrd_high=0xffffffffffffffff\0" \
+       "linux_image=dragonboard/Image\0" \
+       "linux_addr=0x81000000\0"\
+       "fdt_image=dragonboard/apq8016-sbc.dtb\0" \
+       "fdt_addr=0x83000000\0"\
+       "ramdisk_addr=0x84000000\0"\
+       "ramdisk_image=dragonboard/initrd.img\0" \
+       "dl_uboot=tftp $loadaddr dragonboard/u-boot.img\0"\
+       "dl_kernel=tftp $linux_addr $linux_image " \
+               "&& tftp $fdt_addr $fdt_image\0"\
+       "dl_ramdisk=tftp $ramdisk_addr $ramdisk_image\0"\
+       "nboot_nord=usb start && run dl_kernel && usb stop && " \
+                   "booti $linux_addr - $fdt_addr\0"\
+       "nboot_rd=usb start && run dl_kernel && run dl_ramdisk && "\
+                 "booti $linux_addr $ramdisk_addr $fdt_addr\0"
+
+#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_LONGHELP
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_SYS_MAXARGS             64      /* max command args */
+
+
+#endif
--
Quoted 2 lines

2.5.0

Regards,
Simon

#39 lore raw

RFC PATCH 11/11 board: Add Qualcomm Dragonboard 410C support

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 14 lines

board/qualcomm/dragonboard410c/dragonboard410c.c line 37

Quoted 10 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +9 -0
+
+int board_prepare_usb(enum usb_init_type type)
+{
+       int ret = 0, node;
+
+       /* 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, 0,
+                                         "usb_hub_reset_n_pm");

Is this really the standard binding? I would expect a USB node with a reset-gpios property.

That's a good idea.

[...]

Quoted 10 lines

board/qualcomm/dragonboard410c/dragonboard410c.c line 93

Quoted 8 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +8 -0
+
+/* Check for vol- button - if pressed - stop autoboot */
+int misc_init_r(void)
+{
+       int node;
+       struct gpio_desc resin;
+
+       node = fdt_subnode_offset(gd->fdt_blob, 0, "key_vol_down");

Should this be a GPIO key?

Yes, but I couldn't find something like that in U-Boot.. did I missed it?

[...]

Quoted 7 lines

board/qualcomm/dragonboard410c/u-boot.lds line 13

Quoted 4 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +4 -0
+
+OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(_fastboot_header)

I wonder if you could use the standard .lds file and amend it to support fastboot?

Perhaps it's a good idea to make it generic option (at least for ARMv8 devices).

I'm not sure is it "generic" fastboot header or only works for Little Kernel on Qualcomm devices though.

@Albert what do you think?

Quoted 14 lines
Quoted 4 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +3 -0
+SECTIONS
+{
+       . = 0x00000000;

board/qualcomm/dragonboard410c/u-boot.lds line 26

Quoted 10 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +10 -0
+
+       . = ALIGN(8);
+       .text :
+       {
+               *(.__image_copy_start)
+               board/qualcomm/dragonboard410c/head.o (.text*)
+               CPUDIR/start.o (.text*)
+               *(.text*)
+       }
+

Regards,
Mateusz

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWdUxgAAoJELvtohmVtQzBSV0IAIeIJSDENgvWvR5Q7hkmGYWQ y+M0QWFaZpAD+iyOsHBelRWpaOTlrjrnG7n9aAsUf6VUJ8d70p8dPDgycxoRyrtw QdWGTfamlO3V9/cw0iLKlWpz3xXZXIVkMrLyhggZkA4anGMSopvNkuOs42LQSgnp dOUJAEbLgwZBlALlZH3uAdpSuAYywbfDhyyXGXH4sCHhx2wNnLJjr4sXLoamz8Jd 2o9ITZfr5TAl3fWTxSRN0XHxUeFRYLUywpSyqmI9A3ajtsRSh8uPzde2v3PP6qjI Qw94RrF2QWKSLu/OMehajcWzG6VYYKaGc0nMMmLV6aHL1VNI9FjRpUcSraHhU0A= =AVPb
-----END PGP SIGNATURE-----

#40 lore raw

RFC PATCH 11/11 board: Add Qualcomm Dragonboard 410C support

Hi Mateusz,

Quoted 51 lines · Mateusz Kulikowski

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Simon,

Quoted 4 lines · Simon Glass

Hi Mateusz,

On 10 December 2015 at 14:41, Mateusz Kulikowski
<[email protected]> wrote:

[...]

Quoted 14 lines

board/qualcomm/dragonboard410c/dragonboard410c.c line 37

Quoted 10 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +9 -0
+
+int board_prepare_usb(enum usb_init_type type)
+{
+       int ret = 0, node;
+
+       /* 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, 0,
+                                         "usb_hub_reset_n_pm");

Is this really the standard binding? I would expect a USB node with a reset-gpios property.

That's a good idea.

[...]

Quoted 10 lines

board/qualcomm/dragonboard410c/dragonboard410c.c line 93

Quoted 8 lines
board/qualcomm/dragonboard410c/dragonboard410c.c new file +8 -0
+
+/* Check for vol- button - if pressed - stop autoboot */
+int misc_init_r(void)
+{
+       int node;
+       struct gpio_desc resin;
+
+       node = fdt_subnode_offset(gd->fdt_blob, 0, "key_vol_down");

Should this be a GPIO key?

Yes, but I couldn't find something like that in U-Boot.. did I missed it?

[...]

Quoted 7 lines

board/qualcomm/dragonboard410c/u-boot.lds line 13

Quoted 4 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +4 -0
+
+OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(_fastboot_header)

I wonder if you could use the standard .lds file and amend it to support fastboot?

Quoted 6 lines

Perhaps it's a good idea to make it generic option (at least for ARMv8 devices).

I'm not sure is it "generic" fastboot header or only works for Little Kernel on Qualcomm devices though.

@Albert what do you think?

I see later that you plan to remove this one day, so perhaps it is fine to keep it as it is.

Quoted 15 lines
Quoted 15 lines
Quoted 5 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +3 -0
+SECTIONS
+{
+       . = 0x00000000;

board/qualcomm/dragonboard410c/u-boot.lds line 26

Quoted 10 lines
board/qualcomm/dragonboard410c/u-boot.lds new file +10 -0
+
+       . = ALIGN(8);
+       .text :
+       {
+               *(.__image_copy_start)
+               board/qualcomm/dragonboard410c/head.o (.text*)
+               CPUDIR/start.o (.text*)
+               *(.text*)
+       }
+

Regards,
Simon

#41 lore raw

cover Add support for 96boards Dragonboard410C board

In reply to Mateusz Kulikowski
Quoted 3 lines

With a slight delay (Sorry Syed) I'm finally ready to show code I've been working recently on.

Thanks for the patches. I will update my git tree for snapdragon_810 with these changes. I only have serial and cache support working on 810 and it boots to u-boot prompt. The arch/arm/cpu/armv8/cache_v8.c/mmu_setup() causes the board to reset. I didn't dig deeper. I switched to use
mmu_setup() as implemented in arch/arm/cpu/armv8/zynqmp/cpu.c and everything works fine.

Quoted 1 line

create mode 100644 arch/arm/mach-snapdragon/reset.c

Can you rename this arch/arm/mach-snapdragon/reset-apq8016.c as I have arch/arm/mach-snapdragon/reset-apq8094.c to be added.

Will provide more feedback going forward.

Thanks
-syed

#42 lore raw

cover Add support for 96boards Dragonboard410C board

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Quoted 11 lines · On 15.12.2015 19:57, sk.syed2 wrote:
Quoted 3 lines

With a slight delay (Sorry Syed) I'm finally ready to show code I've been working recently on.

Thanks for the patches. I will update my git tree for snapdragon_810 with these changes. I only have serial and cache support working on 810 and it boots to u-boot prompt. The arch/arm/cpu/armv8/cache_v8.c/mmu_setup() causes the board to reset. I didn't dig deeper. I switched to use
mmu_setup() as implemented in arch/arm/cpu/armv8/zynqmp/cpu.c and everything works fine.

Try to make it able to boot Linux somehow (either via mmc or usb or somehow).

After I'm done with this series for 410C I can take a look at drivers / dts for 810 and try to give you some hints.

Quoted 4 lines
Quoted 2 lines

create mode 100644 arch/arm/mach-snapdragon/reset.c

Can you rename this arch/arm/mach-snapdragon/reset-apq8016.c as I have arch/arm/mach-snapdragon/reset-apq8094.c to be added.

Sure - will do that.

Quoted 2 lines

Will provide more feedback going forward.

Great

Quoted 4 lines

Thanks
-syed

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAEBCAAGBQJWcIVEAAoJELvtohmVtQzB1YIH/i5cO7hcGlDW38FwuKnLe5RH uq2FgoX4OCHMNMZ86o5qEf61UZqCbeMi6jCzvsSH/9KS62Uwlacnl7yMhec/QQ00 644TyyhchyelVmXfbjTouydCObirIJu2SMwn4bn7ThEnBq+CiIKI5dWFAFALhDVD wHs9HGBK6F2ypP7adjgTcV5pspKV0vghPIdyQSf+ees5q/dbM3oxnBkTGyj3DvAE sc/2Ip0yu0whUgX4ra+ZVi7zssOQkbSBJfCTcqXVlDOI7Ct87VKkTCWXT8aS9wLK KRgP2IEkfDCdqOjC5lrhmqG3BnaabeV6U0dWKAcU/ZdudxCnUrNUy3UsmNJzB6o= =SxKo
-----END PGP SIGNATURE-----