[ sunxi64 ] Moved A64 boards to mainline u-boot 2019.04 Tested basic functions with eMMC install on A64 Notebooks and Olinuxino

This commit is contained in:
Igor Pecovnik 2019-04-12 20:29:43 +02:00
parent 564969e58e
commit c474e35fe1
15 changed files with 933 additions and 1567 deletions

View file

@ -0,0 +1,507 @@
From 7f25d8179776226a8ecfbaad3d3a88e9acd89f28 Mon Sep 17 00:00:00 2001
From: Stefan Mavrodiev <stefan@olimex.com>
Date: Tue, 6 Feb 2018 15:14:33 +0200
Subject: [PATCH] arm: sunxi: Allwinner A10 SPI driver
Add spi driver for sun4i, sun5i and sun7i SoCs. The driver is
adapted from mailine kernel.
Signed-off-by: Stefan Mavrodiev <stefan@olimex.com>
Reviewed-by: Jagan Teki <jagan@openedev.com>
---
drivers/spi/Kconfig | 5 +
drivers/spi/Makefile | 1 +
drivers/spi/sun4i_spi.c | 456 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 462 insertions(+)
create mode 100644 drivers/spi/sun4i_spi.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b85fca56289..dcd719ff0ac 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -174,6 +174,11 @@ config STM32_QSPI
used to access the SPI NOR flash chips on platforms embedding
this ST IP core.
+config SUN4I_SPI
+ bool "Allwinner A10 SoCs SPI controller"
+ help
+ SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
+
config TEGRA114_SPI
bool "nVidia Tegra114 SPI driver"
help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 95b03a29dc0..728e30c5383 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
obj-$(CONFIG_SH_SPI) += sh_spi.o
obj-$(CONFIG_SH_QSPI) += sh_qspi.o
obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o
+obj-$(CONFIG_SUN4I_SPI) += sun4i_spi.o
obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c
new file mode 100644
index 00000000000..b86b5a00adb
--- /dev/null
+++ b/drivers/spi/sun4i_spi.c
@@ -0,0 +1,456 @@
+/*
+ * (C) Copyright 2017 Whitebox Systems / Northend Systems B.V.
+ * S.J.R. van Schaik <stephan@whiteboxsystems.nl>
+ * M.B.W. Wajer <merlijn@whiteboxsystems.nl>
+ *
+ * (C) Copyright 2017 Olimex Ltd..
+ * Stefan Mavrodiev <stefan@olimex.com>
+ *
+ * Based on linux spi driver. Original copyright follows:
+ * linux/drivers/spi/spi-sun4i.c
+ *
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi.h>
+#include <errno.h>
+#include <fdt_support.h>
+#include <wait_bit.h>
+
+#include <asm/bitops.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include <asm/arch/clock.h>
+
+#define SUN4I_FIFO_DEPTH 64
+
+#define SUN4I_RXDATA_REG 0x00
+
+#define SUN4I_TXDATA_REG 0x04
+
+#define SUN4I_CTL_REG 0x08
+#define SUN4I_CTL_ENABLE BIT(0)
+#define SUN4I_CTL_MASTER BIT(1)
+#define SUN4I_CTL_CPHA BIT(2)
+#define SUN4I_CTL_CPOL BIT(3)
+#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
+#define SUN4I_CTL_LMTF BIT(6)
+#define SUN4I_CTL_TF_RST BIT(8)
+#define SUN4I_CTL_RF_RST BIT(9)
+#define SUN4I_CTL_XCH_MASK 0x0400
+#define SUN4I_CTL_XCH BIT(10)
+#define SUN4I_CTL_CS_MASK 0x3000
+#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
+#define SUN4I_CTL_DHB BIT(15)
+#define SUN4I_CTL_CS_MANUAL BIT(16)
+#define SUN4I_CTL_CS_LEVEL BIT(17)
+#define SUN4I_CTL_TP BIT(18)
+
+#define SUN4I_INT_CTL_REG 0x0c
+#define SUN4I_INT_CTL_RF_F34 BIT(4)
+#define SUN4I_INT_CTL_TF_E34 BIT(12)
+#define SUN4I_INT_CTL_TC BIT(16)
+
+#define SUN4I_INT_STA_REG 0x10
+
+#define SUN4I_DMA_CTL_REG 0x14
+
+#define SUN4I_WAIT_REG 0x18
+
+#define SUN4I_CLK_CTL_REG 0x1c
+#define SUN4I_CLK_CTL_CDR2_MASK 0xff
+#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
+#define SUN4I_CLK_CTL_CDR1_MASK 0xf
+#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN4I_CLK_CTL_DRS BIT(12)
+
+#define SUN4I_MAX_XFER_SIZE 0xffffff
+
+#define SUN4I_BURST_CNT_REG 0x20
+#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
+
+#define SUN4I_XMIT_CNT_REG 0x24
+#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
+
+#define SUN4I_FIFO_STA_REG 0x28
+#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_RF_CNT_BITS 0
+#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_TF_CNT_BITS 16
+
+#define SUN4I_SPI_MAX_RATE 24000000
+#define SUN4I_SPI_MIN_RATE 3000
+#define SUN4I_SPI_DEFAULT_RATE 1000000
+#define SUN4I_SPI_TIMEOUT_US 1000000
+
+/* sun4i spi register set */
+struct sun4i_spi_regs {
+ u32 rxdata;
+ u32 txdata;
+ u32 ctl;
+ u32 intctl;
+ u32 st;
+ u32 dmactl;
+ u32 wait;
+ u32 cctl;
+ u32 bc;
+ u32 tc;
+ u32 fifo_sta;
+};
+
+struct sun4i_spi_platdata {
+ u32 base_addr;
+ u32 max_hz;
+};
+
+struct sun4i_spi_priv {
+ struct sun4i_spi_regs *regs;
+ u32 freq;
+ u32 mode;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
+{
+ u8 byte;
+
+ while (len--) {
+ byte = readb(&priv->regs->rxdata);
+ *priv->rx_buf++ = byte;
+ }
+}
+
+static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len)
+{
+ u8 byte;
+
+ while (len--) {
+ byte = priv->tx_buf ? *priv->tx_buf++ : 0;
+ writeb(byte, &priv->regs->txdata);
+ }
+}
+
+static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
+{
+ struct sun4i_spi_priv *priv = dev_get_priv(bus);
+ u32 reg;
+
+ reg = readl(&priv->regs->ctl);
+
+ reg &= ~SUN4I_CTL_CS_MASK;
+ reg |= SUN4I_CTL_CS(cs);
+
+ if (enable)
+ reg &= ~SUN4I_CTL_CS_LEVEL;
+ else
+ reg |= SUN4I_CTL_CS_LEVEL;
+
+ writel(reg, &priv->regs->ctl);
+}
+
+static int sun4i_spi_parse_pins(struct udevice *dev)
+{
+ const void *fdt = gd->fdt_blob;
+ const char *pin_name;
+ const fdt32_t *list;
+ u32 phandle;
+ int drive, pull = 0, pin, i;
+ int offset;
+ int size;
+
+ list = fdt_getprop(fdt, dev_of_offset(dev), "pinctrl-0", &size);
+ if (!list) {
+ printf("WARNING: sun4i_spi: cannot find pinctrl-0 node\n");
+ return -EINVAL;
+ }
+
+ while (size) {
+ phandle = fdt32_to_cpu(*list++);
+ size -= sizeof(*list);
+
+ offset = fdt_node_offset_by_phandle(fdt, phandle);
+ if (offset < 0)
+ return offset;
+
+ drive = fdt_getprop_u32_default_node(fdt, offset, 0,
+ "drive-strength", 0);
+ if (drive) {
+ if (drive <= 10)
+ drive = 0;
+ else if (drive <= 20)
+ drive = 1;
+ else if (drive <= 30)
+ drive = 2;
+ else
+ drive = 3;
+ } else {
+ drive = fdt_getprop_u32_default_node(fdt, offset, 0,
+ "allwinner,drive",
+ 0);
+ drive = min(drive, 3);
+ }
+
+ if (fdt_get_property(fdt, offset, "bias-disable", NULL))
+ pull = 0;
+ else if (fdt_get_property(fdt, offset, "bias-pull-up", NULL))
+ pull = 1;
+ else if (fdt_get_property(fdt, offset, "bias-pull-down", NULL))
+ pull = 2;
+ else
+ pull = fdt_getprop_u32_default_node(fdt, offset, 0,
+ "allwinner,pull",
+ 0);
+ pull = min(pull, 2);
+
+ for (i = 0; ; i++) {
+ pin_name = fdt_stringlist_get(fdt, offset,
+ "pins", i, NULL);
+ if (!pin_name) {
+ pin_name = fdt_stringlist_get(fdt, offset,
+ "allwinner,pins",
+ i, NULL);
+ if (!pin_name)
+ break;
+ }
+
+ pin = name_to_gpio(pin_name);
+ if (pin < 0)
+ break;
+
+ sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0);
+ sunxi_gpio_set_drv(pin, drive);
+ sunxi_gpio_set_pull(pin, pull);
+ }
+ }
+ return 0;
+}
+
+static inline void sun4i_spi_enable_clock(void)
+{
+ struct sunxi_ccm_reg *const ccm =
+ (struct sunxi_ccm_reg *const)SUNXI_CCM_BASE;
+
+ setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_SPI0));
+ writel((1 << 31), &ccm->spi0_clk_cfg);
+}
+
+static int sun4i_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
+ int node = dev_of_offset(bus);
+
+ plat->base_addr = devfdt_get_addr(bus);
+ plat->max_hz = fdtdec_get_int(gd->fdt_blob, node,
+ "spi-max-frequency",
+ SUN4I_SPI_DEFAULT_RATE);
+
+ if (plat->max_hz > SUN4I_SPI_MAX_RATE)
+ plat->max_hz = SUN4I_SPI_MAX_RATE;
+
+ return 0;
+}
+
+static int sun4i_spi_probe(struct udevice *bus)
+{
+ struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
+ struct sun4i_spi_priv *priv = dev_get_priv(bus);
+
+ sun4i_spi_enable_clock();
+ sun4i_spi_parse_pins(bus);
+
+ priv->regs = (struct sun4i_spi_regs *)(uintptr_t)plat->base_addr;
+ priv->freq = plat->max_hz;
+
+ return 0;
+}
+
+static int sun4i_spi_claim_bus(struct udevice *dev)
+{
+ struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
+
+ writel(SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP |
+ SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW,
+ &priv->regs->ctl);
+ return 0;
+}
+
+static int sun4i_spi_release_bus(struct udevice *dev)
+{
+ struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
+ u32 reg;
+
+ reg = readl(&priv->regs->ctl);
+ reg &= ~SUN4I_CTL_ENABLE;
+ writel(reg, &priv->regs->ctl);
+
+ return 0;
+}
+
+static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct sun4i_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ u32 len = bitlen / 8;
+ u32 reg;
+ u8 nbytes;
+ int ret;
+
+ priv->tx_buf = dout;
+ priv->rx_buf = din;
+
+ if (bitlen % 8) {
+ debug("%s: non byte-aligned SPI transfer.\n", __func__);
+ return -ENAVAIL;
+ }
+
+ if (flags & SPI_XFER_BEGIN)
+ sun4i_spi_set_cs(bus, slave_plat->cs, true);
+
+ reg = readl(&priv->regs->ctl);
+
+ /* Reset FIFOs */
+ writel(reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST, &priv->regs->ctl);
+
+ while (len) {
+ /* Setup the transfer now... */
+ nbytes = min(len, (u32)(SUN4I_FIFO_DEPTH - 1));
+
+ /* Setup the counters */
+ writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bc);
+ writel(SUN4I_XMIT_CNT(nbytes), &priv->regs->tc);
+
+ /* Fill the TX FIFO */
+ sun4i_spi_fill_fifo(priv, nbytes);
+
+ /* Start the transfer */
+ reg = readl(&priv->regs->ctl);
+ writel(reg | SUN4I_CTL_XCH, &priv->regs->ctl);
+
+ /* Wait transfer to complete */
+ ret = wait_for_bit_le32(&priv->regs->ctl, SUN4I_CTL_XCH_MASK,
+ false, SUN4I_SPI_TIMEOUT_US, false);
+ if (ret) {
+ printf("ERROR: sun4i_spi: Timeout transferring data\n");
+ sun4i_spi_set_cs(bus, slave_plat->cs, false);
+ return ret;
+ }
+
+ /* Drain the RX FIFO */
+ sun4i_spi_drain_fifo(priv, nbytes);
+
+ len -= nbytes;
+ }
+
+ if (flags & SPI_XFER_END)
+ sun4i_spi_set_cs(bus, slave_plat->cs, false);
+
+ return 0;
+}
+
+static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
+{
+ struct sun4i_spi_platdata *plat = dev_get_platdata(dev);
+ struct sun4i_spi_priv *priv = dev_get_priv(dev);
+ unsigned int div;
+ u32 reg;
+
+ if (speed > plat->max_hz)
+ speed = plat->max_hz;
+
+ if (speed < SUN4I_SPI_MIN_RATE)
+ speed = SUN4I_SPI_MIN_RATE;
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Whether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+
+ div = SUN4I_SPI_MAX_RATE / (2 * speed);
+ reg = readl(&priv->regs->cctl);
+
+ if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
+ reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
+ } else {
+ div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(speed);
+ reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
+ reg |= SUN4I_CLK_CTL_CDR1(div);
+ }
+
+ priv->freq = speed;
+ writel(reg, &priv->regs->cctl);
+
+ return 0;
+}
+
+static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
+{
+ struct sun4i_spi_priv *priv = dev_get_priv(dev);
+ u32 reg;
+
+ reg = readl(&priv->regs->ctl);
+ reg &= ~(SUN4I_CTL_CPOL | SUN4I_CTL_CPHA);
+
+ if (mode & SPI_CPOL)
+ reg |= SUN4I_CTL_CPOL;
+
+ if (mode & SPI_CPHA)
+ reg |= SUN4I_CTL_CPHA;
+
+ priv->mode = mode;
+ writel(reg, &priv->regs->ctl);
+
+ return 0;
+}
+
+static const struct dm_spi_ops sun4i_spi_ops = {
+ .claim_bus = sun4i_spi_claim_bus,
+ .release_bus = sun4i_spi_release_bus,
+ .xfer = sun4i_spi_xfer,
+ .set_speed = sun4i_spi_set_speed,
+ .set_mode = sun4i_spi_set_mode,
+};
+
+static const struct udevice_id sun4i_spi_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(sun4i_spi) = {
+ .name = "sun4i_spi",
+ .id = UCLASS_SPI,
+ .of_match = sun4i_spi_ids,
+ .ops = &sun4i_spi_ops,
+ .ofdata_to_platdata = sun4i_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct sun4i_spi_platdata),
+ .priv_auto_alloc_size = sizeof(struct sun4i_spi_priv),
+ .probe = sun4i_spi_probe,
+};

View file

@ -0,0 +1,21 @@
diff --git a/arch/arm/dts/sun50i-a64-olinuxino.dts b/arch/arm/dts/sun50i-a64-olinuxino.dts
index f7a4bcc..9d77afb 100644
--- a/arch/arm/dts/sun50i-a64-olinuxino.dts
+++ b/arch/arm/dts/sun50i-a64-olinuxino.dts
@@ -155,6 +155,16 @@
};
};
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins>;
+ vmmc-supply = <&reg_dcdc1>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "okay";
+};
+
&ohci0 {
status = "okay";
};

View file

@ -0,0 +1,13 @@
diff --git a/configs/a64-olinuxino_defconfig b/configs/a64-olinuxino_defconfig
index 01fcb86..528fe16 100644
--- a/configs/a64-olinuxino_defconfig
+++ b/configs/a64-olinuxino_defconfig
@@ -1,6 +1,8 @@
CONFIG_ARM=y
CONFIG_ARCH_SUNXI=y
CONFIG_SPL=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUNXI=y
CONFIG_MACH_SUN50I=y
CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
CONFIG_MMC_SUNXI_SLOT_EXTRA=2

View file

@ -1,44 +1,24 @@
From 0e9350e3ff11c91eb6959d0d4589a4cc5e576e35 Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <anarsoul@gmail.com>
Date: Sat, 16 Sep 2017 07:44:11 -0700
Subject: [PATCH] sunxi: add support for Pinebook
From 960ae79950a2b0a8d2e62bb3dfb5727764512a8b Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Mon, 22 Jan 2018 00:49:10 +0800
Subject: [PATCH] test
Pinebook is a laptop produced by Pine64, with USB-connected keyboard,
I2C-connected touchpad and an eDP LCD panel connected via a RGB-eDP
bridge by Analogix.
Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
arch/arm/dts/Makefile | 3 +-
arch/arm/dts/sun50i-a64-pinebook.dts | 114 +++++++++++++++++++++++++++++++++++
configs/pinebook_defconfig | 36 +++++++++++
3 files changed, 152 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/dts/sun50i-a64-pinebook.dts
create mode 100644 configs/pinebook_defconfig
arch/arm/dts/sun50i-a64-teres-i.dts | 114 ++++++++++++++++++++++++++++++++++++
configs/teres_i_defconfig | 35 +++++++++++
2 files changed, 149 insertions(+)
create mode 100644 arch/arm/dts/sun50i-a64-teres-i.dts
create mode 100644 configs/teres_i_defconfig
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index fee4680057..130d1944be 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -342,7 +342,8 @@ dtb-$(CONFIG_MACH_SUN50I) += \
sun50i-a64-olinuxino.dtb \
sun50i-a64-orangepi-win.dtb \
sun50i-a64-pine64-plus.dtb \
- sun50i-a64-pine64.dtb
+ sun50i-a64-pine64.dtb \
+ sun50i-a64-pinebook.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
sun9i-a80-cubieboard4.dtb \
diff --git a/arch/arm/dts/sun50i-a64-pinebook.dts b/arch/arm/dts/sun50i-a64-pinebook.dts
diff --git a/arch/arm/dts/sun50i-a64-teres-i.dts b/arch/arm/dts/sun50i-a64-teres-i.dts
new file mode 100644
index 0000000000..17d4c598b8
index 0000000000..1b836c1f49
--- /dev/null
+++ b/arch/arm/dts/sun50i-a64-pinebook.dts
@@ -0,0 +1,112 @@
+++ b/arch/arm/dts/sun50i-a64-teres-i.dts
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016 ARM Ltd.
+ * Copyright (c) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
@ -79,12 +59,14 @@ index 0000000000..17d4c598b8
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sun50i-a64-pine64.dts"
+/dts-v1/;
+
+#include <dt-bindings/pwm/pwm.h>
+#include "sun50i-a64-pine64.dts"
+
+/ {
+ model = "Pinebook";
+ compatible = "pine64,pinebook", "allwinner,sun50i-a64";
+ model = "TERES I";
+ compatible = "olimex,teres-i", "allwinner,sun50i-a64";
+
+ aliases {
+ serial0 = &uart0;
@ -110,8 +92,8 @@ index 0000000000..17d4c598b8
+ soc {
+ i2c_gpio@0 {
+ compatible = "i2c-gpio";
+ gpios = <&r_pio 0 9 GPIO_ACTIVE_HIGH>, /* sda - PL9 */
+ <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* scl - PL8 */
+ gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>, /* sda - PL9 */
+ <&pio 7 0 GPIO_ACTIVE_HIGH>; /* scl - PL8 */
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
@ -122,7 +104,7 @@ index 0000000000..17d4c598b8
+ anx6345: edp-bridge@38 {
+ compatible = "analogix,anx6345";
+ reg = <0x38>;
+ sleep-gpios = <&pio 7 6 GPIO_ACTIVE_LOW>; /* PH6 */
+ sleep-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 dummy */
+ reset-gpios = <&pio 3 24 GPIO_ACTIVE_LOW>; /* PD24 */
+ status = "okay";
+
@ -149,22 +131,21 @@ index 0000000000..17d4c598b8
+&pwm {
+ status = "okay";
+};
diff --git a/configs/pinebook-a64_defconfig b/configs/pinebook-a64_defconfig
diff --git a/configs/teres_i_defconfig b/configs/teres_i_defconfig
new file mode 100644
index 0000000000..e90c863f76
index 0000000000..da33b4131d
--- /dev/null
+++ b/configs/pinebook-a64_defconfig
@@ -0,0 +1,36 @@
+++ b/configs/teres_i_defconfig
@@ -0,0 +1,35 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_MACH_SUN50I=y
+CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
+CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y
+CONFIG_DRAM_CLK=552
+CONFIG_DRAM_ZQ=3881949
+CONFIG_DRAM_ODT_EN=y
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pinebook"
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-teres-i"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SPL=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
@ -180,10 +161,10 @@ index 0000000000..e90c863f76
+# CONFIG_SPL_EFI_PARTITION is not set
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_DM_I2C_GPIO=y
+CONFIG_SPL_SPI_SUNXI=y
+# CONFIG_SPL_SPI_SUNXI is not set
+CONFIG_DM_REGULATOR=y
+CONFIG_AXP_DLDO2_VOLT=2500
+CONFIG_AXP_FLDO1_VOLT=1200
+CONFIG_AXP_DLDO3_VOLT=1200
+CONFIG_AXP_SW_ON=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_SUNXI=y
@ -191,3 +172,15 @@ index 0000000000..e90c863f76
+CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
+CONFIG_VIDEO_BRIDGE=y
+CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345=y
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -406,7 +406,8 @@ dtb-$(CONFIG_MACH_SUN50I) += \
sun50i-a64-pine64-plus.dtb \
sun50i-a64-pine64.dtb \
sun50i-a64-pinebook.dtb \
- sun50i-a64-sopine-baseboard.dtb
+ sun50i-a64-sopine-baseboard.dtb \
+ sun50i-a64-teres-i.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
sun9i-a80-cubieboard4.dtb \

View file

@ -1,45 +0,0 @@
--- a/arch/arm/dts/sun50i-a64-olinuxino.dts
+++ b/arch/arm/dts/sun50i-a64-olinuxino.dts
@@ -66,6 +66,16 @@
};
};
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ status = "okay";
+};
+
+&i2c1_pins {
+ bias-pull-up;
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins>;
@@ -77,6 +87,25 @@
status = "okay";
};
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;

View file

@ -1,206 +0,0 @@
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 98f57e0..c4321f6 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -338,7 +338,8 @@ dtb-$(CONFIG_MACH_SUN50I) += \
sun50i-a64-olinuxino.dtb \
sun50i-a64-orangepi-win.dtb \
sun50i-a64-pine64-plus.dtb \
- sun50i-a64-pine64.dtb
+ sun50i-a64-pine64.dtb \
+ sun50i-a64-sopine-baseboard.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
sun9i-a80-cubieboard4.dtb \
diff --git a/configs/sopine_baseboard_defconfig b/configs/sopine_baseboard_defconfig
index 122bba3..8659bc3 100644
--- a/configs/sopine_baseboard_defconfig
+++ b/configs/sopine_baseboard_defconfig
@@ -8,7 +8,7 @@ CONFIG_DRAM_ZQ=3881949
CONFIG_DRAM_ODT_EN=y
CONFIG_MMC0_CD_PIN=""
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
-CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-plus"
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-sopine-baseboard"
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL=y
# CONFIG_CMD_IMLS is not set
diff --git a/arch/arm/dts/sun50i-a64-sopine-baseboard.dts b/arch/arm/dts/sun50i-a64-sopine-baseboard.dts
new file mode 100644
index 0000000..42c0f10
--- /dev/null
+++ b/arch/arm/dts/sun50i-a64-sopine-baseboard.dts
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * Based on sun50i-a64-pine64.dts, which is:
+ * Copyright (c) 2016 ARM Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "sun50i-a64-sopine.dtsi"
+
+/ {
+ model = "SoPine with baseboard";
+ compatible = "pine64,sopine-baseboard", "pine64,sopine",
+ "allwinner,sun50i-a64";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ reg_vcc1v8: vcc1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins>;
+ vmmc-supply = <&reg_vcc3v3>;
+ vqmmc-supply = <&reg_vcc1v8>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-a64-sopine.dtsi b/arch/arm/dts/sun50i-a64-sopine.dtsi
new file mode 100644
index 0000000..475518b
--- /dev/null
+++ b/arch/arm/dts/sun50i-a64-sopine.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * Based on sun50i-a64-pine64.dts, which is:
+ * Copyright (c) 2016 ARM Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sun50i-a64.dtsi"
+
+/ {
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>;
+ vmmc-supply = <&reg_vcc3v3>;
+ non-removable;
+ disable-wp;
+ bus-width = <4>;
+ status = "okay";
+};

View file

@ -0,0 +1,343 @@
diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c
index c1706dcec1..2e06ee4ed2 100644
--- a/arch/arm/cpu/armv8/generic_timer.c
+++ b/arch/arm/cpu/armv8/generic_timer.c
@@ -66,7 +66,7 @@ unsigned long timer_read_counter(void)
isb();
do {
asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));
- } while (((cntpct + 1) & GENMASK(10, 0)) <= 1);
+ } while (((cntpct + 1) & GENMASK(9, 0)) <= 1);
return cntpct;
}
diff --git a/arch/arm/dts/sun50i-a64-sopine-baseboard.dts b/arch/arm/dts/sun50i-a64-sopine-baseboard.dts
index 53fcc9098d..8dac3f135b 100644
--- a/arch/arm/dts/sun50i-a64-sopine-baseboard.dts
+++ b/arch/arm/dts/sun50i-a64-sopine-baseboard.dts
@@ -55,6 +55,7 @@
aliases {
ethernet0 = &emac;
serial0 = &uart0;
+ spi0 = &spi0;
};
chosen {
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index ee387127f3..4aaa0932d7 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -321,6 +321,7 @@ struct sunxi_ccm_reg {
#define AHB_GATE_OFFSET_MMC(n) (AHB_GATE_OFFSET_MMC0 + (n))
#define AHB_GATE_OFFSET_DMA 6
#define AHB_GATE_OFFSET_SS 5
+#define AHB_GATE_OFFSET_SPI0 20
/* ahb_gate1 offsets */
#define AHB_GATE_OFFSET_DRC0 25
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun9i.h b/arch/arm/include/asm/arch-sunxi/clock_sun9i.h
index 530e0dd73b..9bbd4d319e 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun9i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun9i.h
@@ -194,6 +194,7 @@ struct sunxi_ccm_reg {
/* ahb gate1 field */
#define AHB_GATE_OFFSET_DMA 24
+#define AHB_GATE_OFFSET_SPI0 20
/* apb1_gate fields */
#define APB1_GATE_UART_SHIFT 16
diff --git a/configs/sopine_baseboard_defconfig b/configs/sopine_baseboard_defconfig
index 9ede081c08..af690c11c5 100644
--- a/configs/sopine_baseboard_defconfig
+++ b/configs/sopine_baseboard_defconfig
@@ -18,3 +18,20 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-sopine-baseboard"
CONFIG_SUN8I_EMAC=y
CONFIG_USB_EHCI_HCD=y
CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI=y
+CONFIG_SUN4I_SPI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_PHY_REALTEK=y
+CONFIG_RTL8211E_PINE64_GIGABIT_FIX=y
\ No newline at end of file
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a7bb5b35c2..88e772cb1a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -219,9 +219,9 @@ config STM32_QSPI
this ST IP core.
config SUN4I_SPI
- bool "Allwinner A10 SoCs SPI controller"
+ bool "Allwinner SoCs SPI driver"
help
- SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
+ SPI driver for Allwinner SoCs
config TEGRA114_SPI
bool "nVidia Tegra114 SPI driver"
diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c
index 38cc743c61..7af8be15cf 100644
--- a/drivers/spi/sun4i_spi.c
+++ b/drivers/spi/sun4i_spi.c
@@ -37,6 +37,30 @@
#define SUN4I_TXDATA_REG 0x04
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+#define SUN4I_CTL_REG 0x04
+#define SUN4I_CTL_ENABLE BIT(0)
+#define SUN4I_CTL_MASTER BIT(1)
+#define SUN4I_CTL_TP BIT(7)
+#define SUN4I_CTL_SRST BIT(31)
+
+#define SUN4I_CTL_CPHA BIT(0)
+#define SUN4I_CTL_CPOL BIT(1)
+#define SUN4I_CTL_CS_ACTIVE_LOW BIT(2)
+#define SUN4I_CTL_CS_MASK 0x30
+#define SUN4I_CTL_CS(cs) (((cs) << 4) & SUN4I_CTL_CS_MASK)
+#define SUN4I_CTL_CS_MANUAL BIT(6)
+#define SUN4I_CTL_CS_LEVEL BIT(7)
+#define SUN4I_CTL_DHB BIT(8)
+#define SUN4I_CTL_XCH_MASK 0x80000000
+#define SUN4I_CTL_XCH BIT(31)
+
+#define SUN4I_CTL_RF_RST BIT(15)
+#define SUN4I_CTL_TF_RST BIT(31)
+
+#else
+#define SUN4I_CTL_SRST 0
+
#define SUN4I_CTL_REG 0x08
#define SUN4I_CTL_ENABLE BIT(0)
#define SUN4I_CTL_MASTER BIT(1)
@@ -54,6 +78,7 @@
#define SUN4I_CTL_CS_MANUAL BIT(16)
#define SUN4I_CTL_CS_LEVEL BIT(17)
#define SUN4I_CTL_TP BIT(18)
+#endif
#define SUN4I_INT_CTL_REG 0x0c
#define SUN4I_INT_CTL_RF_F34 BIT(4)
@@ -92,11 +117,39 @@
#define SUN4I_SPI_DEFAULT_RATE 1000000
#define SUN4I_SPI_TIMEOUT_US 1000000
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+/* sun6i spi register set */
+struct sun4i_spi_regs {
+ u32 res0;
+ u32 ctl; /* 0x04 */
+ u32 tctl; /* 0x08 */
+ u32 res1;
+ u32 intctl; /* 0x10 */
+ u32 st; /* 0x14 */
+ u32 fifo_ctl; /* 0x18 */
+ u32 fifo_sta; /* 0x1c */
+ u32 wait; /* 0x20 */
+ u32 cctl; /* 0x24 */
+ u32 res2[2];
+ u32 bc; /* 0x30 */
+ u32 tc; /* 0x34 */
+ u32 bctl; /* 0x38 */
+ u32 res3[113];
+ u32 txdata; /* 0x200 */
+ u32 res4[63];
+ u32 rxdata; /* 0x300 */
+};
+#else
/* sun4i spi register set */
struct sun4i_spi_regs {
u32 rxdata;
u32 txdata;
- u32 ctl;
+ union {
+ u32 ctl;
+ u32 tctl;
+ u32 fifo_ctl;
+ u32 bctl;
+ };
u32 intctl;
u32 st;
u32 dmactl;
@@ -106,6 +159,7 @@ struct sun4i_spi_regs {
u32 tc;
u32 fifo_sta;
};
+#endif
struct sun4i_spi_platdata {
u32 base_addr;
@@ -149,7 +203,7 @@ static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
struct sun4i_spi_priv *priv = dev_get_priv(bus);
u32 reg;
- reg = readl(&priv->regs->ctl);
+ reg = readl(&priv->regs->tctl);
reg &= ~SUN4I_CTL_CS_MASK;
reg |= SUN4I_CTL_CS(cs);
@@ -159,7 +213,7 @@ static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
else
reg |= SUN4I_CTL_CS_LEVEL;
- writel(reg, &priv->regs->ctl);
+ writel(reg, &priv->regs->tctl);
}
static int sun4i_spi_parse_pins(struct udevice *dev)
@@ -231,7 +285,10 @@ static int sun4i_spi_parse_pins(struct udevice *dev)
if (pin < 0)
break;
- sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0);
+ if (IS_ENABLED(CONFIG_MACH_SUN50I))
+ sunxi_gpio_set_cfgpin(pin, SUN50I_GPC_SPI0);
+ else
+ sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0);
sunxi_gpio_set_drv(pin, drive);
sunxi_gpio_set_pull(pin, pull);
}
@@ -244,10 +301,27 @@ static inline void sun4i_spi_enable_clock(void)
struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *const)SUNXI_CCM_BASE;
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+ setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_SPI0));
+#endif
+
setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_SPI0));
writel((1 << 31), &ccm->spi0_clk_cfg);
}
+static inline void sun4i_spi_disable_clock(void)
+{
+ struct sunxi_ccm_reg *const ccm =
+ (struct sunxi_ccm_reg *const)SUNXI_CCM_BASE;
+
+ writel(0, &ccm->spi0_clk_cfg);
+ clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_SPI0));
+
+#ifdef CONFIG_SUNXI_GEN_SUN6I
+ clrbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_SPI0));
+#endif
+}
+
static int sun4i_spi_ofdata_to_platdata(struct udevice *bus)
{
struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
@@ -269,7 +343,6 @@ static int sun4i_spi_probe(struct udevice *bus)
struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
struct sun4i_spi_priv *priv = dev_get_priv(bus);
- sun4i_spi_enable_clock();
sun4i_spi_parse_pins(bus);
priv->regs = (struct sun4i_spi_regs *)(uintptr_t)plat->base_addr;
@@ -282,9 +355,17 @@ static int sun4i_spi_claim_bus(struct udevice *dev)
{
struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
+ sun4i_spi_enable_clock();
writel(SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP |
- SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW,
+ SUN4I_CTL_SRST,
&priv->regs->ctl);
+
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ while (readl(&priv->regs->ctl) & SUN4I_CTL_SRST)
+ ;
+
+ setbits_le32(&priv->regs->tctl, SUN4I_CTL_CS_MANUAL |
+ SUN4I_CTL_CS_ACTIVE_LOW);
return 0;
}
@@ -296,6 +377,7 @@ static int sun4i_spi_release_bus(struct udevice *dev)
reg = readl(&priv->regs->ctl);
reg &= ~SUN4I_CTL_ENABLE;
writel(reg, &priv->regs->ctl);
+ sun4i_spi_disable_clock();
return 0;
}
@@ -323,10 +405,10 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (flags & SPI_XFER_BEGIN)
sun4i_spi_set_cs(bus, slave_plat->cs, true);
- reg = readl(&priv->regs->ctl);
+ reg = readl(&priv->regs->fifo_ctl);
/* Reset FIFOs */
- writel(reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST, &priv->regs->ctl);
+ writel(reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST, &priv->regs->fifo_ctl);
while (len) {
/* Setup the transfer now... */
@@ -335,16 +417,18 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Setup the counters */
writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bc);
writel(SUN4I_XMIT_CNT(nbytes), &priv->regs->tc);
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bctl);
/* Fill the TX FIFO */
sun4i_spi_fill_fifo(priv, nbytes);
/* Start the transfer */
- reg = readl(&priv->regs->ctl);
- writel(reg | SUN4I_CTL_XCH, &priv->regs->ctl);
+ reg = readl(&priv->regs->tctl);
+ writel(reg | SUN4I_CTL_XCH, &priv->regs->tctl);
/* Wait transfer to complete */
- ret = wait_for_bit_le32(&priv->regs->ctl, SUN4I_CTL_XCH_MASK,
+ ret = wait_for_bit_le32(&priv->regs->tctl, SUN4I_CTL_XCH_MASK,
false, SUN4I_SPI_TIMEOUT_US, false);
if (ret) {
printf("ERROR: sun4i_spi: Timeout transferring data\n");
@@ -417,7 +501,7 @@ static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
struct sun4i_spi_priv *priv = dev_get_priv(dev);
u32 reg;
- reg = readl(&priv->regs->ctl);
+ reg = readl(&priv->regs->tctl);
reg &= ~(SUN4I_CTL_CPOL | SUN4I_CTL_CPHA);
if (mode & SPI_CPOL)
@@ -427,7 +511,7 @@ static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
reg |= SUN4I_CTL_CPHA;
priv->mode = mode;
- writel(reg, &priv->regs->ctl);
+ writel(reg, &priv->regs->tctl);
return 0;
}
@@ -441,7 +525,13 @@ static const struct dm_spi_ops sun4i_spi_ops = {
};
static const struct udevice_id sun4i_spi_ids[] = {
+#ifndef CONFIG_SUNXI_GEN_SUN6I
{ .compatible = "allwinner,sun4i-a10-spi" },
+#else
+ { .compatible = "allwinner,sun6i-a31-spi" },
+ { .compatible = "allwinner,sun8i-h3-spi" },
+ { .compatible = "allwinner,sun50i-a64-spi" },
+#endif
{ }
};

View file

@ -1,274 +0,0 @@
From 485a09477c96edda8dd737493efd6f6e03ecf06e Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <anarsoul@gmail.com>
Date: Sun, 17 Sep 2017 09:19:52 -0700
Subject: [PATCH] pwm: sunxi: add support for PWM found on Allwinner A64 and H3
This commit adds basic support for PWM found on Allwinner A64 and H3
It can be used for pwm_backlight driver (e.g. for Pinebook)
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
arch/arm/include/asm/arch-sunxi/gpio.h | 1 +
arch/arm/include/asm/arch-sunxi/pwm.h | 12 +++
drivers/pwm/Kconfig | 7 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/sunxi_pwm.c | 184 +++++++++++++++++++++++++++++++++
5 files changed, 205 insertions(+)
create mode 100644 drivers/pwm/sunxi_pwm.c
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 24f85206c8..7265d18099 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -173,6 +173,7 @@ enum sunxi_gpio_number {
#define SUN8I_GPD_SDC1 3
#define SUNXI_GPD_LCD0 2
#define SUNXI_GPD_LVDS0 3
+#define SUNXI_GPD_PWM 2
#define SUN5I_GPE_SDC2 3
#define SUN8I_GPE_TWI2 3
diff --git a/arch/arm/include/asm/arch-sunxi/pwm.h b/arch/arm/include/asm/arch-sunxi/pwm.h
index 5884b5dbe7..673e0eb7b5 100644
--- a/arch/arm/include/asm/arch-sunxi/pwm.h
+++ b/arch/arm/include/asm/arch-sunxi/pwm.h
@@ -11,8 +11,15 @@
#define SUNXI_PWM_CH0_PERIOD (SUNXI_PWM_BASE + 4)
#define SUNXI_PWM_CTRL_PRESCALE0(x) ((x) & 0xf)
+#define SUNXI_PWM_CTRL_PRESCALE0_MASK (0xf)
#define SUNXI_PWM_CTRL_ENABLE0 (0x5 << 4)
#define SUNXI_PWM_CTRL_POLARITY0(x) ((x) << 5)
+#define SUNXI_PWM_CTRL_POLARITY0_MASK (1 << 5)
+#define SUNXI_PWM_CTRL_CLK_GATE (1 << 6)
+
+#define SUNXI_PWM_CH0_PERIOD_MAX (0xffff)
+#define SUNXI_PWM_CH0_PERIOD_PRD(x) ((x & 0xffff) << 16)
+#define SUNXI_PWM_CH0_PERIOD_DUTY(x) ((x) & 0xffff)
#define SUNXI_PWM_PERIOD_80PCT 0x04af03c0
@@ -31,4 +38,9 @@
#define SUNXI_PWM_MUX SUN8I_GPH_PWM
#endif
+struct sunxi_pwm {
+ u32 ctrl;
+ u32 ch0_period;
+};
+
#endif
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e827558052..2984b79766 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -43,3 +43,10 @@ config PWM_TEGRA
four channels with a programmable period and duty cycle. Only a
32KHz clock is supported by the driver but the duty cycle is
configurable.
+
+config PWM_SUNXI
+ bool "Enable support for the Allwinner Sunxi PWM"
+ depends on DM_PWM
+ help
+ This PWM is found on H3, A64 and other Allwinner SoCs. It supports a
+ programmable period and duty cycle. A 16-bit counter is used.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 29d59916cb..1a8f8a58bc 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o
obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
+obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c
new file mode 100644
index 0000000000..cfea7d69f3
--- /dev/null
+++ b/drivers/pwm/sunxi_pwm.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <dm.h>
+#include <pwm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/pwm.h>
+#include <asm/arch/gpio.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sunxi_pwm_priv {
+ struct sunxi_pwm *regs;
+ ulong freq;
+ bool invert;
+ uint32_t prescaler;
+};
+
+static const uint32_t prescaler_table[] = {
+ 120, /* 0000 */
+ 180, /* 0001 */
+ 240, /* 0010 */
+ 360, /* 0011 */
+ 480, /* 0100 */
+ 0, /* 0101 */
+ 0, /* 0110 */
+ 0, /* 0111 */
+ 12000, /* 1000 */
+ 24000, /* 1001 */
+ 36000, /* 1010 */
+ 48000, /* 1011 */
+ 72000, /* 1100 */
+ 0, /* 1101 */
+ 0, /* 1110 */
+ 1, /* 1111 */
+};
+
+static const uint64_t nsecs_per_sec = 1000000000L;
+
+static int sunxi_pwm_config_pinmux(void)
+{
+#ifdef CONFIG_MACH_SUN50I
+ sunxi_gpio_set_cfgpin(SUNXI_GPD(22), SUNXI_GPD_PWM);
+#endif
+ return 0;
+}
+
+static int sunxi_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
+{
+ struct sunxi_pwm_priv *priv = dev_get_priv(dev);
+
+ debug("%s: polarity=%u\n", __func__, polarity);
+ priv->invert = polarity;
+
+ return 0;
+}
+
+static int sunxi_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
+ uint duty_ns)
+{
+ struct sunxi_pwm_priv *priv = dev_get_priv(dev);
+ struct sunxi_pwm *regs = priv->regs;
+ int prescaler;
+ u32 v, period, duty;
+ uint64_t div = 0, pval = 0, scaled_freq = 0;
+
+ debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
+
+ for (prescaler = 0; prescaler < SUNXI_PWM_CTRL_PRESCALE0_MASK; prescaler++) {
+ if (!prescaler_table[prescaler])
+ continue;
+ div = priv->freq;
+ pval = prescaler_table[prescaler];
+ scaled_freq = lldiv(div, pval);
+ div = scaled_freq * period_ns;
+ div = lldiv(div, nsecs_per_sec);
+ if (div - 1 <= SUNXI_PWM_CH0_PERIOD_MAX)
+ break;
+ }
+
+ if (div - 1 > SUNXI_PWM_CH0_PERIOD_MAX) {
+ debug("%s: failed to find prescaler value\n", __func__);
+ return -EINVAL;
+ }
+
+ period = div;
+ div = scaled_freq * duty_ns;
+ div = lldiv(div, nsecs_per_sec);
+ duty = div;
+
+ if (priv->prescaler != prescaler) {
+ /* Mask clock to update prescaler */
+ v = readl(&regs->ctrl);
+ v &= ~SUNXI_PWM_CTRL_CLK_GATE;
+ writel(v, &regs->ctrl);
+ v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK;
+ v |= (priv->prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
+ writel(v, &regs->ctrl);
+ v |= SUNXI_PWM_CTRL_CLK_GATE;
+ writel(v, &regs->ctrl);
+ priv->prescaler = prescaler;
+ }
+
+ writel(SUNXI_PWM_CH0_PERIOD_PRD(period) |
+ SUNXI_PWM_CH0_PERIOD_DUTY(duty), &regs->ch0_period);
+
+ debug("%s: prescaler: %d, period: %d, duty: %d\n", __func__, priv->prescaler,
+ period, duty);
+
+ return 0;
+}
+
+static int sunxi_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+ struct sunxi_pwm_priv *priv = dev_get_priv(dev);
+ struct sunxi_pwm *regs = priv->regs;
+ uint32_t v;
+
+ debug("%s: Enable '%s'\n", __func__, dev->name);
+
+ v = readl(&regs->ctrl);
+ if (!enable) {
+ v &= ~SUNXI_PWM_CTRL_ENABLE0;
+ writel(v, &regs->ctrl);
+ return 0;
+ }
+
+ sunxi_pwm_config_pinmux();
+
+ v &= ~SUNXI_PWM_CTRL_POLARITY0_MASK;
+ v |= priv->invert ? SUNXI_PWM_CTRL_POLARITY0(0) :
+ SUNXI_PWM_CTRL_POLARITY0(1);
+ v |= SUNXI_PWM_CTRL_ENABLE0;
+ writel(v, &regs->ctrl);
+
+ return 0;
+}
+
+static int sunxi_pwm_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sunxi_pwm_priv *priv = dev_get_priv(dev);
+
+ priv->regs = (struct sunxi_pwm *)devfdt_get_addr(dev);
+
+ return 0;
+}
+
+static int sunxi_pwm_probe(struct udevice *dev)
+{
+ struct sunxi_pwm_priv *priv = dev_get_priv(dev);
+
+ priv->freq = 24000000;
+
+ return 0;
+}
+
+static const struct pwm_ops sunxi_pwm_ops = {
+ .set_invert = sunxi_pwm_set_invert,
+ .set_config = sunxi_pwm_set_config,
+ .set_enable = sunxi_pwm_set_enable,
+};
+
+static const struct udevice_id sunxi_pwm_ids[] = {
+ { .compatible = "allwinner,sun8i-h3-pwm" },
+ { }
+};
+
+U_BOOT_DRIVER(sunxi_pwm) = {
+ .name = "sunxi_pwm",
+ .id = UCLASS_PWM,
+ .of_match = sunxi_pwm_ids,
+ .ops = &sunxi_pwm_ops,
+ .ofdata_to_platdata = sunxi_pwm_ofdata_to_platdata,
+ .probe = sunxi_pwm_probe,
+ .priv_auto_alloc_size = sizeof(struct sunxi_pwm_priv),
+};

View file

@ -1,821 +0,0 @@
From 15d68b2115b24dcf3a20f67942db867e5887b624 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.xyz>
Date: Mon, 27 Mar 2017 19:22:34 +0200
Subject: [PATCH] sunxi: add AXP803 support
The A64 uses the AXP803 as its PMIC.
Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/mach-sunxi/Makefile | 3 +
arch/arm/mach-sunxi/pmic_bus.c | 6 +-
arch/arm/mach-sunxi/rsb.c | 2 +-
board/sunxi/board.c | 31 ++---
drivers/power/Kconfig | 85 +++++++++-----
drivers/power/Makefile | 1 +
drivers/power/axp803.c | 259 +++++++++++++++++++++++++++++++++++++++++
drivers/power/axp818.c | 2 +-
include/axp803.h | 73 ++++++++++++
include/axp_pmic.h | 3 +
10 files changed, 415 insertions(+), 50 deletions(-)
create mode 100644 drivers/power/axp803.c
create mode 100644 include/axp803.h
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 2a3c379b72..0bbfda9364 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -19,9 +19,11 @@ endif
obj-$(CONFIG_MACH_SUN6I) += prcm.o
obj-$(CONFIG_MACH_SUN8I) += prcm.o
obj-$(CONFIG_MACH_SUN9I) += prcm.o
+obj-$(CONFIG_MACH_SUN50I) += prcm.o
obj-$(CONFIG_MACH_SUN6I) += p2wi.o
obj-$(CONFIG_MACH_SUN8I) += rsb.o
obj-$(CONFIG_MACH_SUN9I) += rsb.o
+obj-$(CONFIG_MACH_SUN50I) += rsb.o
obj-$(CONFIG_MACH_SUN4I) += clock_sun4i.o
obj-$(CONFIG_MACH_SUN5I) += clock_sun4i.o
obj-$(CONFIG_MACH_SUN6I) += clock_sun6i.o
@@ -37,6 +39,7 @@ obj-$(CONFIG_MACH_SUN9I) += clock_sun9i.o gtbus_sun9i.o
obj-$(CONFIG_AXP152_POWER) += pmic_bus.o
obj-$(CONFIG_AXP209_POWER) += pmic_bus.o
obj-$(CONFIG_AXP221_POWER) += pmic_bus.o
+obj-$(CONFIG_AXP803_POWER) += pmic_bus.o
obj-$(CONFIG_AXP809_POWER) += pmic_bus.o
obj-$(CONFIG_AXP818_POWER) += pmic_bus.o
diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
index f917c3e070..e021b58b60 100644
--- a/arch/arm/mach-sunxi/pmic_bus.c
+++ b/arch/arm/mach-sunxi/pmic_bus.c
@@ -36,7 +36,7 @@ int pmic_bus_init(void)
if (!needs_init)
return 0;
-#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
# ifdef CONFIG_MACH_SUN6I
p2wi_init();
ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
@@ -65,7 +65,7 @@ int pmic_bus_read(u8 reg, u8 *data)
return i2c_read(AXP152_I2C_ADDR, reg, 1, data, 1);
#elif defined CONFIG_AXP209_POWER
return i2c_read(AXP209_I2C_ADDR, reg, 1, data, 1);
-#elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
+#elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
# ifdef CONFIG_MACH_SUN6I
return p2wi_read(reg, data);
# elif defined CONFIG_MACH_SUN8I_R40
@@ -82,7 +82,7 @@ int pmic_bus_write(u8 reg, u8 data)
return i2c_write(AXP152_I2C_ADDR, reg, 1, &data, 1);
#elif defined CONFIG_AXP209_POWER
return i2c_write(AXP209_I2C_ADDR, reg, 1, &data, 1);
-#elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
+#elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
# ifdef CONFIG_MACH_SUN6I
return p2wi_write(reg, data);
# elif defined CONFIG_MACH_SUN8I_R40
diff --git a/arch/arm/mach-sunxi/rsb.c b/arch/arm/mach-sunxi/rsb.c
index 6fd11f1529..28d05e962a 100644
--- a/arch/arm/mach-sunxi/rsb.c
+++ b/arch/arm/mach-sunxi/rsb.c
@@ -20,7 +20,7 @@ static int rsb_set_device_mode(void);
static void rsb_cfg_io(void)
{
-#ifdef CONFIG_MACH_SUN8I
+#if defined CONFIG_MACH_SUN8I || defined CONFIG_MACH_SUN50I
sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB);
sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB);
sunxi_gpio_set_pull(SUNXI_GPL(0), 1);
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 70e01437c4..192cf8ca45 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -519,26 +519,27 @@ void sunxi_board_init(void)
#endif
#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \
- defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
- defined CONFIG_AXP818_POWER
+ defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || \
+ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
power_failed = axp_init();
-#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
- defined CONFIG_AXP818_POWER
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || \
+ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
power_failed |= axp_set_dcdc1(CONFIG_AXP_DCDC1_VOLT);
#endif
power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT);
power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT);
-#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER)
+#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP803_POWER) && \
+ !defined(CONFIG_AXP818_POWER)
power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT);
#endif
-#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
- defined CONFIG_AXP818_POWER
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || \
+ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
power_failed |= axp_set_dcdc5(CONFIG_AXP_DCDC5_VOLT);
#endif
-#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
- defined CONFIG_AXP818_POWER
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP803_POWER || \
+ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
power_failed |= axp_set_aldo1(CONFIG_AXP_ALDO1_VOLT);
#endif
power_failed |= axp_set_aldo2(CONFIG_AXP_ALDO2_VOLT);
@@ -549,8 +550,8 @@ void sunxi_board_init(void)
power_failed |= axp_set_aldo4(CONFIG_AXP_ALDO4_VOLT);
#endif
-#if defined(CONFIG_AXP221_POWER) || defined(CONFIG_AXP809_POWER) || \
- defined(CONFIG_AXP818_POWER)
+#if defined(CONFIG_AXP221_POWER) || defined(CONFIG_AXP803_POWER) || \
+ defined(CONFIG_AXP809_POWER) || defined(CONFIG_AXP818_POWER)
power_failed |= axp_set_dldo(1, CONFIG_AXP_DLDO1_VOLT);
power_failed |= axp_set_dldo(2, CONFIG_AXP_DLDO2_VOLT);
#if !defined CONFIG_AXP809_POWER
@@ -562,13 +563,17 @@ void sunxi_board_init(void)
power_failed |= axp_set_eldo(3, CONFIG_AXP_ELDO3_VOLT);
#endif
-#ifdef CONFIG_AXP818_POWER
+#if defined CONFIG_AXP803_POWER || defined CONFIG_AXP818_POWER
power_failed |= axp_set_fldo(1, CONFIG_AXP_FLDO1_VOLT);
power_failed |= axp_set_fldo(2, CONFIG_AXP_FLDO2_VOLT);
+#endif
+
+#ifdef CONFIG_AXP818_POWER
power_failed |= axp_set_fldo(3, CONFIG_AXP_FLDO3_VOLT);
#endif
-#if defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
+#if defined CONFIG_AXP803_POWER || defined CONFIG_AXP809_POWER || \
+ defined CONFIG_AXP818_POWER
power_failed |= axp_set_sw(IS_ENABLED(CONFIG_AXP_SW_ON));
#endif
#endif
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d8c107e206..2da80ae04b 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -11,8 +11,9 @@ choice
depends on ARCH_SUNXI
default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40
+ default AXP803_POWER if MACH_SUN50I
default AXP818_POWER if MACH_SUN8I_A83T
- default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5 || MACH_SUN50I
+ default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5
config SUNXI_NO_PMIC
bool "board without a pmic"
@@ -43,6 +44,13 @@ config AXP221_POWER
Select this to enable support for the axp221/axp223 pmic found on most
A23 and A31 boards.
+config AXP803_POWER
+ bool "axp803 pmic support"
+ depends on MACH_SUN50I
+ select CMD_POWEROFF
+ ---help---
+ Say y here to enable support for the axp803 pmic found on A64 boards.
+
config AXP809_POWER
bool "axp809 pmic support"
depends on MACH_SUN9I
@@ -69,25 +77,25 @@ endchoice
config AXP_DCDC1_VOLT
int "axp pmic dcdc1 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
- default 3300 if AXP818_POWER || MACH_SUN8I_R40
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
+ default 3300 if AXP818_POWER || MACH_SUN8I_R40 || MACH_SUN50I
default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
---help---
Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to
disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for
generic 3.3V IO voltage for external devices like the lcd-panal and
sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to
- save battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T
- dcdc1 is used for VCC-IO, nand, usb0, sd , etc. On A80 dcdc1 normally
- powers some of the pingroups, NAND/eMMC, SD/MMC, and USB OTG.
+ save battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T and
+ A64 dcdc1 is used for VCC-IO, nand, usb0, sd , etc. On A80 dcdc1
+ normally powers some of the pingroups, NAND/eMMC, SD/MMC, and USB OTG.
config AXP_DCDC2_VOLT
int "axp pmic dcdc2 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 900 if AXP818_POWER
default 1400 if AXP152_POWER || AXP209_POWER
default 1200 if MACH_SUN6I
- default 1100 if MACH_SUN8I
+ default 1100 if MACH_SUN8I || MACH_SUN50I
default 0 if MACH_SUN9I
---help---
Set the voltage (mV) to program the axp pmic dcdc2 at, set to 0 to
@@ -98,14 +106,15 @@ config AXP_DCDC2_VOLT
On A80 boards dcdc2 powers the GPU and can be left off.
On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V.
On R40 boards dcdc2 is VDD-CPU and should be 1.1V
+ On A64 boards dcdc2 is used with dcdc3 for VDD-CPU and should be 1.1V.
config AXP_DCDC3_VOLT
int "axp pmic dcdc3 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 900 if AXP809_POWER || AXP818_POWER
default 1500 if AXP152_POWER
default 1250 if AXP209_POWER
- default 1100 if MACH_SUN8I_R40
+ default 1100 if MACH_SUN8I_R40 || MACH_SUN50I
default 1200 if MACH_SUN6I || MACH_SUN8I
---help---
Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to
@@ -117,39 +126,42 @@ config AXP_DCDC3_VOLT
On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V.
On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V.
On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V.
+ On A64 boards dcdc3 is used with dcdc2 for VDD-CPU and should be 1.1V.
config AXP_DCDC4_VOLT
int "axp pmic dcdc4 voltage"
- depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 1250 if AXP152_POWER
default 1200 if MACH_SUN6I
- default 0 if MACH_SUN8I
+ default 0 if MACH_SUN8I || MACH_SUN50I
default 900 if MACH_SUN9I
---help---
Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to
disable dcdc4.
On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V.
On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V.
- On A23 / A33 boards dcdc4 is unused and should be disabled.
+ On A23 / A33 / A64 boards dcdc4 is unused and should be disabled.
On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V.
On A83T boards dcdc4 is used for VDD-GPU.
config AXP_DCDC5_VOLT
int "axp pmic dcdc5 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 1500 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
+ default 1350 if MACH_SUN50I
---help---
Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to
disable dcdc5.
- On A23 / A31 / A33 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and
+ On A23 / A31 / A33 / A64 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and
should be 1.5V, 1.35V if DDR3L is used.
config AXP_ALDO1_VOLT
int "axp pmic (a)ldo1 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 0 if MACH_SUN6I || MACH_SUN8I_R40
default 1800 if MACH_SUN8I_A83T
default 3000 if MACH_SUN8I || MACH_SUN9I
+ default 2800 if MACH_SUN50I
---help---
Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to
disable aldo1.
@@ -158,14 +170,16 @@ config AXP_ALDO1_VOLT
On A80 boards aldo1 powers the USB hosts and should be 3.0V.
On A83T / H8 boards aldo1 is used for MIPI CSI, DSI, HDMI, EFUSE, and
should be 1.8V.
+ On A64 boards aldo1 powers PE pingroup and CSI and should be 2.8V.
config AXP_ALDO2_VOLT
int "axp pmic (a)ldo2 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 3000 if AXP152_POWER || AXP209_POWER
default 0 if MACH_SUN6I || MACH_SUN9I
default 1800 if MACH_SUN8I_A83T
default 2500 if MACH_SUN8I
+ default 1800 if MACH_SUN50I
---help---
Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to
disable aldo2.
@@ -176,17 +190,18 @@ config AXP_ALDO2_VOLT
On A80 boards aldo2 powers PB pingroup and camera IO and can be left off.
On A83T / H8 boards aldo2 powers VDD-DLL, VCC18-PLL, CPVDD, VDD18-ADC,
LPDDR2, and the codec. It should be 1.8V.
+ On A64 boards aldo2 powers PL pingroup and should be 1.8V.
config AXP_ALDO3_VOLT
int "axp pmic (a)ldo3 voltage"
- depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP209_POWER || AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 0 if AXP209_POWER || MACH_SUN9I
- default 3000 if MACH_SUN6I || MACH_SUN8I
+ default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN50I
---help---
Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to
disable aldo3.
On A10(s) / A13 / A20 boards aldo3 should be 2.8V.
- On A23 / A31 / A33 / R40 boards aldo3 is VCC-PLL and AVCC and should
+ On A23 / A31 / A33 / A64 / R40 boards aldo3 is VCC-PLL and AVCC and should
be 3.0V.
On A80 boards aldo3 is normally not used.
On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be
@@ -203,17 +218,19 @@ config AXP_ALDO4_VOLT
config AXP_DLDO1_VOLT
int "axp pmic dldo1 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
+ default 3300 if MACH_SUN50I
default 0
---help---
Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to
disable dldo1. On sun6i (A31) boards with ethernet dldo1 is often used
to power the ethernet phy. On A23, A33 and A80 boards this is often
- used to power the wifi.
+ used to power the wifi. On A64 boards this is often used to power the
+ HDMI.
config AXP_DLDO2_VOLT
int "axp pmic dldo2 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 3000 if MACH_SUN9I
default 0
---help---
@@ -223,7 +240,7 @@ config AXP_DLDO2_VOLT
config AXP_DLDO3_VOLT
int "axp pmic dldo3 voltage"
- depends on AXP221_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP818_POWER
default 0
---help---
Set the voltage (mV) to program the axp pmic dldo3 at, set to 0 to
@@ -231,7 +248,7 @@ config AXP_DLDO3_VOLT
config AXP_DLDO4_VOLT
int "axp pmic dldo4 voltage"
- depends on AXP221_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP818_POWER
default 0
---help---
Set the voltage (mV) to program the axp pmic dldo4 at, set to 0 to
@@ -239,15 +256,17 @@ config AXP_DLDO4_VOLT
config AXP_ELDO1_VOLT
int "axp pmic eldo1 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
+ default 1800 if MACH_SUN50I
default 0
---help---
Set the voltage (mV) to program the axp pmic eldo1 at, set to 0 to
disable eldo1.
+ On A64 boards it's used for the codec and should be 1.8V.
config AXP_ELDO2_VOLT
int "axp pmic eldo2 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 0
---help---
Set the voltage (mV) to program the axp pmic eldo2 at, set to 0 to
@@ -255,7 +274,7 @@ config AXP_ELDO2_VOLT
config AXP_ELDO3_VOLT
int "axp pmic eldo3 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP803_POWER || AXP809_POWER || AXP818_POWER
default 3000 if MACH_SUN9I
default 0
---help---
@@ -267,8 +286,8 @@ config AXP_ELDO3_VOLT
config AXP_FLDO1_VOLT
int "axp pmic fldo1 voltage"
- depends on AXP818_POWER
- default 0 if MACH_SUN8I_A83T
+ depends on AXP803_POWER || AXP818_POWER
+ default 0
---help---
Set the voltage (mV) to program the axp pmic fldo1 at, set to 0 to
disable fldo1.
@@ -277,11 +296,13 @@ config AXP_FLDO1_VOLT
config AXP_FLDO2_VOLT
int "axp pmic fldo2 voltage"
- depends on AXP818_POWER
+ depends on AXP803_POWER || AXP818_POWER
+ default 1100 if MACH_SUN50I
default 900 if MACH_SUN8I_A83T
---help---
Set the voltage (mV) to program the axp pmic fldo2 at, set to 0 to
disable fldo2.
+ On A64 boards fldo2 is VCC-CPUS and should be 1.1V.
On A83T / H8 boards fldo2 is VCC-CPUS and should be 0.9V.
config AXP_FLDO3_VOLT
@@ -294,7 +315,7 @@ config AXP_FLDO3_VOLT
config AXP_SW_ON
bool "axp pmic sw on"
- depends on AXP809_POWER || AXP818_POWER
+ depends on AXP803_POWER || AXP809_POWER || AXP818_POWER
default n
---help---
Enable to turn on axp pmic sw.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 90a3b00a7c..55413a66d2 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_AXP152_POWER) += axp152.o
obj-$(CONFIG_AXP209_POWER) += axp209.o
obj-$(CONFIG_AXP221_POWER) += axp221.o
+obj-$(CONFIG_AXP803_POWER) += axp803.o
obj-$(CONFIG_AXP809_POWER) += axp809.o
obj-$(CONFIG_AXP818_POWER) += axp818.o
obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
diff --git a/drivers/power/axp803.c b/drivers/power/axp803.c
new file mode 100644
index 0000000000..af20fce8b1
--- /dev/null
+++ b/drivers/power/axp803.c
@@ -0,0 +1,259 @@
+/*
+ * AXP803 driver based on AXP818 driver
+ *
+ * Based on axp818.c
+ * (C) Copyright 2015 Vishnu Patekar <vishnuptekar0510@gmail.com>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+static u8 axp803_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp803_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC1_EN);
+
+ ret = pmic_bus_write(AXP803_DCDC1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC1_EN);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1220)
+ cfg = 70 + axp803_mvolt_to_cfg(mvolt, 1220, 1300, 20);
+ else
+ cfg = axp803_mvolt_to_cfg(mvolt, 500, 1200, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC2_EN);
+
+ ret = pmic_bus_write(AXP803_DCDC2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC2_EN);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1220)
+ cfg = 70 + axp803_mvolt_to_cfg(mvolt, 1220, 1300, 20);
+ else
+ cfg = axp803_mvolt_to_cfg(mvolt, 500, 1200, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC3_EN);
+
+ ret = pmic_bus_write(AXP803_DCDC3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC3_EN);
+}
+
+int axp_set_dcdc5(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1140)
+ cfg = 32 + axp803_mvolt_to_cfg(mvolt, 1140, 1840, 20);
+ else
+ cfg = axp803_mvolt_to_cfg(mvolt, 800, 1120, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC5_EN);
+
+ ret = pmic_bus_write(AXP803_DCDC5_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL1,
+ AXP803_OUTPUT_CTRL1_DCDC5_EN);
+}
+
+int axp_set_aldo(int aldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (aldo_num < 1 || aldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL3,
+ AXP803_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1));
+
+ cfg = axp803_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ ret = pmic_bus_write(AXP803_ALDO1_CTRL + (aldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL3,
+ AXP803_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1));
+}
+
+/* TODO: re-work other AXP drivers to consolidate ALDO functions. */
+int axp_set_aldo1(unsigned int mvolt)
+{
+ return axp_set_aldo(1, mvolt);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+ return axp_set_aldo(2, mvolt);
+}
+
+int axp_set_aldo3(unsigned int mvolt)
+{
+ return axp_set_aldo(3, mvolt);
+}
+
+int axp_set_dldo(int dldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (dldo_num < 1 || dldo_num > 4)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL2,
+ AXP803_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+
+ cfg = axp803_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ if (dldo_num == 2 && mvolt > 3300)
+ cfg += 1 + axp803_mvolt_to_cfg(mvolt, 3400, 4200, 200);
+ ret = pmic_bus_write(AXP803_DLDO1_CTRL + (dldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL2,
+ AXP803_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+}
+
+int axp_set_eldo(int eldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (eldo_num < 1 || eldo_num > 3)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL2,
+ AXP803_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+
+ cfg = axp803_mvolt_to_cfg(mvolt, 700, 1900, 50);
+ ret = pmic_bus_write(AXP803_ELDO1_CTRL + (eldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL2,
+ AXP803_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+}
+
+int axp_set_fldo(int fldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (fldo_num < 1 || fldo_num > 2)
+ return -EINVAL;
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL3,
+ AXP803_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1));
+
+ cfg = axp803_mvolt_to_cfg(mvolt, 700, 1450, 50);
+ ret = pmic_bus_write(AXP803_FLDO1_CTRL + (fldo_num - 1), cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL3,
+ AXP803_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1));
+}
+
+int axp_set_sw(bool on)
+{
+ if (on)
+ return pmic_bus_setbits(AXP803_OUTPUT_CTRL2,
+ AXP803_OUTPUT_CTRL2_SW_EN);
+
+ return pmic_bus_clrbits(AXP803_OUTPUT_CTRL2,
+ AXP803_OUTPUT_CTRL2_SW_EN);
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP803_CHIP_ID, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if (!(axp_chip_id == 0x51))
+ return -ENODEV;
+ else
+ return ret;
+
+ return 0;
+}
+
+/* ARM64 has its own poweroff implementation using PSCI */
+#ifndef CONFIG_ARM64
+int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ pmic_bus_write(AXP803_SHUTDOWN, AXP803_SHUTDOWN_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1)
+ ;
+
+ /* not reached */
+ return 0;
+}
+#endif
diff --git a/drivers/power/axp818.c b/drivers/power/axp818.c
index af4d7a6903..ad0c330ca5 100644
--- a/drivers/power/axp818.c
+++ b/drivers/power/axp818.c
@@ -162,7 +162,7 @@ int axp_set_dldo(int dldo_num, unsigned int mvolt)
cfg = axp818_mvolt_to_cfg(mvolt, 700, 3300, 100);
if (dldo_num == 2 && mvolt > 3300)
cfg += 1 + axp818_mvolt_to_cfg(mvolt, 3400, 4200, 200);
- ret = pmic_bus_write(AXP818_ELDO1_CTRL + (dldo_num - 1), cfg);
+ ret = pmic_bus_write(AXP818_DLDO1_CTRL + (dldo_num - 1), cfg);
if (ret)
return ret;
diff --git a/include/axp803.h b/include/axp803.h
new file mode 100644
index 0000000000..b382f3a5ec
--- /dev/null
+++ b/include/axp803.h
@@ -0,0 +1,73 @@
+/*
+ * (C) Copyright 2016 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * Based on axp818.h, which is:
+ * (C) Copyright 2015 Vishnu Patekar <vishnupatekar0510@gmail.com>
+ *
+ * X-Powers AXP803 Power Management IC driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define AXP803_CHIP_ID 0x03
+
+#define AXP803_OUTPUT_CTRL1 0x10
+#define AXP803_OUTPUT_CTRL1_DCDC1_EN (1 << 0)
+#define AXP803_OUTPUT_CTRL1_DCDC2_EN (1 << 1)
+#define AXP803_OUTPUT_CTRL1_DCDC3_EN (1 << 2)
+#define AXP803_OUTPUT_CTRL1_DCDC4_EN (1 << 3)
+#define AXP803_OUTPUT_CTRL1_DCDC5_EN (1 << 4)
+#define AXP803_OUTPUT_CTRL1_DCDC6_EN (1 << 5)
+#define AXP803_OUTPUT_CTRL2 0x12
+#define AXP803_OUTPUT_CTRL2_ELDO1_EN (1 << 0)
+#define AXP803_OUTPUT_CTRL2_ELDO2_EN (1 << 1)
+#define AXP803_OUTPUT_CTRL2_ELDO3_EN (1 << 2)
+#define AXP803_OUTPUT_CTRL2_DLDO1_EN (1 << 3)
+#define AXP803_OUTPUT_CTRL2_DLDO2_EN (1 << 4)
+#define AXP803_OUTPUT_CTRL2_DLDO3_EN (1 << 5)
+#define AXP803_OUTPUT_CTRL2_DLDO4_EN (1 << 6)
+#define AXP803_OUTPUT_CTRL2_SW_EN (1 << 7)
+#define AXP803_OUTPUT_CTRL3 0x13
+#define AXP803_OUTPUT_CTRL3_FLDO1_EN (1 << 2)
+#define AXP803_OUTPUT_CTRL3_FLDO2_EN (1 << 3)
+#define AXP803_OUTPUT_CTRL3_ALDO1_EN (1 << 5)
+#define AXP803_OUTPUT_CTRL3_ALDO2_EN (1 << 6)
+#define AXP803_OUTPUT_CTRL3_ALDO3_EN (1 << 7)
+
+#define AXP803_DLDO1_CTRL 0x15
+#define AXP803_DLDO2_CTRL 0x16
+#define AXP803_DLDO3_CTRL 0x17
+#define AXP803_DLDO4_CTRL 0x18
+#define AXP803_ELDO1_CTRL 0x19
+#define AXP803_ELDO2_CTRL 0x1a
+#define AXP803_ELDO3_CTRL 0x1b
+#define AXP803_FLDO1_CTRL 0x1c
+#define AXP803_FLDO2_CTRL 0x1d
+#define AXP803_DCDC1_CTRL 0x20
+#define AXP803_DCDC2_CTRL 0x21
+#define AXP803_DCDC3_CTRL 0x22
+#define AXP803_DCDC4_CTRL 0x23
+#define AXP803_DCDC5_CTRL 0x24
+#define AXP803_DCDC6_CTRL 0x25
+
+#define AXP803_ALDO1_CTRL 0x28
+#define AXP803_ALDO2_CTRL 0x29
+#define AXP803_ALDO3_CTRL 0x2a
+
+#define AXP803_SHUTDOWN 0x32
+#define AXP803_SHUTDOWN_POWEROFF (1 << 7)
+
+/* For axp_gpio.c */
+#define AXP_POWER_STATUS 0x00
+#define AXP_POWER_STATUS_VBUS_PRESENT (1 << 5)
+#define AXP_VBUS_IPSOUT 0x30
+#define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+#define AXP_MISC_CTRL 0x8f
+#define AXP_MISC_CTRL_N_VBUSEN_FUNC (1 << 4)
+#define AXP_GPIO0_CTRL 0x90
+#define AXP_GPIO1_CTRL 0x92
+#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */
+#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */
+#define AXP_GPIO_STATE 0x94
+#define AXP_GPIO_STATE_OFFSET 0
diff --git a/include/axp_pmic.h b/include/axp_pmic.h
index d789ad8086..8cb4d5763c 100644
--- a/include/axp_pmic.h
+++ b/include/axp_pmic.h
@@ -16,6 +16,9 @@
#ifdef CONFIG_AXP221_POWER
#include <axp221.h>
#endif
+#ifdef CONFIG_AXP803_POWER
+#include <axp803.h>
+#endif
#ifdef CONFIG_AXP809_POWER
#include <axp809.h>
#endif

View file

@ -1,62 +0,0 @@
From 732153bd114162e8afa22a025d065c5c1d5359f5 Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <anarsoul@gmail.com>
Date: Sun, 17 Sep 2017 09:21:33 -0700
Subject: [PATCH] video: pwm_backlight: make regulator optional
u-boot doesn't have dummy regulators, so pwm_backlight probe
will fail if regulator is missing. Make it optional to get this
driver working on platforms where there's no backlight regultor.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
drivers/video/pwm_backlight.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index fbd7bf7838..05e56ffead 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -32,16 +32,21 @@ static int pwm_backlight_enable(struct udevice *dev)
uint duty_cycle;
int ret;
- plat = dev_get_uclass_platdata(priv->reg);
- debug("%s: Enable '%s', regulator '%s'/'%s'\n", __func__, dev->name,
- priv->reg->name, plat->name);
- ret = regulator_set_enable(priv->reg, true);
- if (ret) {
- debug("%s: Cannot enable regulator for PWM '%s'\n", __func__,
- dev->name);
- return ret;
+ if (priv->reg) {
+ plat = dev_get_uclass_platdata(priv->reg);
+ debug("%s: Enable '%s', regulator '%s'/'%s'\n", __func__, dev->name,
+ priv->reg->name, plat->name);
+ ret = regulator_set_enable(priv->reg, true);
+ if (ret) {
+ debug("%s: Cannot enable regulator for PWM '%s'\n", __func__,
+ dev->name);
+ return ret;
+ }
+ mdelay(120);
}
- mdelay(120);
+
+ debug("%s: default: %d, min: %d, max: %d\n", __func__,
+ priv->default_level, priv->min_level, priv->max_level);
duty_cycle = priv->period_ns * (priv->default_level - priv->min_level) /
(priv->max_level - priv->min_level + 1);
@@ -68,10 +73,9 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev)
debug("%s: start\n", __func__);
ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
"power-supply", &priv->reg);
- if (ret) {
+ if (ret)
debug("%s: Cannot get power supply: ret=%d\n", __func__, ret);
- return ret;
- }
+
ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
GPIOD_IS_OUT);
if (ret) {

View file

@ -1,31 +0,0 @@
From 4644c442c8b14585881995f1c901782c3dad0e46 Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <anarsoul@gmail.com>
Date: Sun, 17 Sep 2017 09:24:13 -0700
Subject: [PATCH] dts: sunxi: add PWM node for sun50i
Add PWM definition to sun50i-a64.dtsi - it's compatible with PWM found on H3
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
arch/arm/dts/sun50i-a64.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi
index 65a344d9ce..00132855ff 100644
--- a/arch/arm/dts/sun50i-a64.dtsi
+++ b/arch/arm/dts/sun50i-a64.dtsi
@@ -319,6 +319,14 @@
};
};
+ pwm: pwm@01c21400 {
+ compatible = "allwinner,sun8i-h3-pwm";
+ reg = <0x01c21400 0x8>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
uart0: serial@1c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;

View file

@ -1,36 +0,0 @@
diff --git a/configs/A20-OLinuXino-Lime2-eMMC_defconfig b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
index f817b8c..ee7b429
--- a/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+++ b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
@@ -27,7 +27,6 @@ CONFIG_DFU_RAM=y
CONFIG_ETH_DESIGNWARE=y
CONFIG_RGMII=y
CONFIG_SUN7I_GMAC=y
-CONFIG_AXP_ALDO3_VOLT=2800
CONFIG_AXP_ALDO4_VOLT=2800
CONFIG_SCSI=y
CONFIG_USB_EHCI_HCD=y
diff --git a/configs/A20-OLinuXino-Lime2_defconfig b/configs/A20-OLinuXino-Lime2_defconfig
index 6d7c588..7a85e20
--- a/configs/A20-OLinuXino-Lime2_defconfig
+++ b/configs/A20-OLinuXino-Lime2_defconfig
@@ -26,7 +26,6 @@ CONFIG_DFU_RAM=y
CONFIG_ETH_DESIGNWARE=y
CONFIG_RGMII=y
CONFIG_SUN7I_GMAC=y
-CONFIG_AXP_ALDO3_VOLT=2800
CONFIG_AXP_ALDO4_VOLT=2800
CONFIG_SCSI=y
CONFIG_USB_EHCI_HCD=y
diff --git a/configs/A20-OLinuXino_MICRO_eMMC_defconfig b/configs/A20-OLinuXino_MICRO_eMMC_defconfig
index 046a805..fb966e1
--- a/configs/A20-OLinuXino_MICRO_eMMC_defconfig
+++ b/configs/A20-OLinuXino_MICRO_eMMC_defconfig
@@ -20,7 +20,6 @@ CONFIG_SPL_I2C_SUPPORT=y
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_ETH_DESIGNWARE=y
CONFIG_SUN7I_GMAC=y
-CONFIG_AXP_ALDO3_VOLT=2800
CONFIG_AXP_ALDO4_VOLT=2800
CONFIG_USB_EHCI_HCD=y
CONFIG_SCSI=y

View file

@ -1,36 +0,0 @@
diff --git a/configs/A20-OLinuXino-Lime2-eMMC_defconfig b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
index f817b8c..ee7b429
--- a/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+++ b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
@@ -27,7 +27,6 @@ CONFIG_DFU_RAM=y
CONFIG_ETH_DESIGNWARE=y
CONFIG_RGMII=y
CONFIG_SUN7I_GMAC=y
-CONFIG_AXP_ALDO3_VOLT=2800
CONFIG_AXP_ALDO4_VOLT=2800
CONFIG_SCSI=y
CONFIG_USB_EHCI_HCD=y
diff --git a/configs/A20-OLinuXino-Lime2_defconfig b/configs/A20-OLinuXino-Lime2_defconfig
index 6d7c588..7a85e20
--- a/configs/A20-OLinuXino-Lime2_defconfig
+++ b/configs/A20-OLinuXino-Lime2_defconfig
@@ -26,7 +26,6 @@ CONFIG_DFU_RAM=y
CONFIG_ETH_DESIGNWARE=y
CONFIG_RGMII=y
CONFIG_SUN7I_GMAC=y
-CONFIG_AXP_ALDO3_VOLT=2800
CONFIG_AXP_ALDO4_VOLT=2800
CONFIG_SCSI=y
CONFIG_USB_EHCI_HCD=y
diff --git a/configs/A20-OLinuXino_MICRO_eMMC_defconfig b/configs/A20-OLinuXino_MICRO_eMMC_defconfig
index 046a805..fb966e1
--- a/configs/A20-OLinuXino_MICRO_eMMC_defconfig
+++ b/configs/A20-OLinuXino_MICRO_eMMC_defconfig
@@ -20,7 +20,6 @@ CONFIG_SPL_I2C_SUPPORT=y
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_ETH_DESIGNWARE=y
CONFIG_SUN7I_GMAC=y
-CONFIG_AXP_ALDO3_VOLT=2800
CONFIG_AXP_ALDO4_VOLT=2800
CONFIG_USB_EHCI_HCD=y
CONFIG_SCSI=y

View file

@ -1,13 +1,13 @@
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1f3fa15..3e1e9b8 100644
index 53eae8953e..1e931a0eb0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -843,6 +845,8 @@ config ARCH_SUNXI
@@ -843,6 +843,8 @@ config ARCH_SUNXI
select USB_KEYBOARD if DISTRO_DEFAULTS
select USB_STORAGE if DISTRO_DEFAULTS
select USE_TINY_PRINTF
+ imply AUTOBOOT_KEYED
+ imply AUTOBOOT_KEYED_CTRLC
+ imply AUTOBOOT_KEYED_CTRLC
imply CMD_DM
imply CMD_GPT
imply CMD_UBI if NAND