summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/Kconfig7
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/sti_sdhci.c141
-rw-r--r--drivers/pinctrl/Kconfig10
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/pinctrl-sti.c320
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_sti_asc.c211
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset_sti.c82
-rw-r--r--drivers/timer/Kconfig7
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/sti-timer.c78
14 files changed, 869 insertions, 0 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 01d1dbf..ddef59a 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -299,6 +299,13 @@ config MMC_SDHCI_SPEAR
If unsure, say N.
+config MMC_SDHCI_STI
+ bool "SDHCI support for STMicroelectronics SoC"
+ depends on MMC_SDHCI && OF_CONTROL
+ help
+ This selects the Secure Digital Host Controller Interface (SDHCI)
+ on STMicroelectronics STiH410 SoC.
+
config MMC_SDHCI_XENON
bool "SDHCI support for the Xenon SDHCI controller"
depends on MMC_SDHCI && DM_MMC && OF_CONTROL
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 8e922db..6a488f1 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_PIC32) += pic32_sdhci.o
obj-$(CONFIG_MMC_SDHCI_ROCKCHIP) += rockchip_sdhci.o
obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += spear_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_STI) += sti_sdhci.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += tegra_mmc.o
obj-$(CONFIG_MMC_SDHCI_XENON) += xenon_sdhci.o
obj-$(CONFIG_MMC_SDHCI_ZYNQ) += zynq_sdhci.o
diff --git a/drivers/mmc/sti_sdhci.c b/drivers/mmc/sti_sdhci.c
new file mode 100644
index 0000000..2a07082
--- /dev/null
+++ b/drivers/mmc/sti_sdhci.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017
+ * Patrice Chotard <patrice.chotard@st.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mmc.h>
+#include <sdhci.h>
+#include <asm/arch/sdhci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sti_sdhci_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+/*
+ * used to get access to MMC1 reset,
+ * will be removed when STi reset driver will be available
+ */
+#define STIH410_SYSCONF5_BASE 0x092b0000
+
+/**
+ * sti_mmc_core_config: configure the Arasan HC
+ * @regbase: base address
+ * @mmc_instance: mmc instance id
+ * Description: this function is to configure the Arasan MMC HC.
+ * This should be called when the system starts in case of, on the SoC,
+ * it is needed to configure the host controller.
+ * This happens on some SoCs, i.e. StiH410, where the MMC0 inside the flashSS
+ * needs to be configured as MMC 4.5 to have full capabilities.
+ * W/o these settings the SDHCI could configure and use the embedded controller
+ * with limited features.
+ */
+static void sti_mmc_core_config(const u32 regbase, int mmc_instance)
+{
+ unsigned long *sysconf;
+
+ /* only MMC1 has a reset line */
+ if (mmc_instance) {
+ sysconf = (unsigned long *)(STIH410_SYSCONF5_BASE +
+ ST_MMC_CCONFIG_REG_5);
+ generic_set_bit(SYSCONF_MMC1_ENABLE_BIT, sysconf);
+ }
+
+ writel(STI_FLASHSS_MMC_CORE_CONFIG_1,
+ regbase + FLASHSS_MMC_CORE_CONFIG_1);
+
+ if (mmc_instance) {
+ writel(STI_FLASHSS_MMC_CORE_CONFIG2,
+ regbase + FLASHSS_MMC_CORE_CONFIG_2);
+ writel(STI_FLASHSS_MMC_CORE_CONFIG3,
+ regbase + FLASHSS_MMC_CORE_CONFIG_3);
+ } else {
+ writel(STI_FLASHSS_SDCARD_CORE_CONFIG2,
+ regbase + FLASHSS_MMC_CORE_CONFIG_2);
+ writel(STI_FLASHSS_SDCARD_CORE_CONFIG3,
+ regbase + FLASHSS_MMC_CORE_CONFIG_3);
+ }
+ writel(STI_FLASHSS_MMC_CORE_CONFIG4,
+ regbase + FLASHSS_MMC_CORE_CONFIG_4);
+}
+
+static int sti_sdhci_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct sti_sdhci_plat *plat = dev_get_platdata(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ int ret, mmc_instance;
+
+ /*
+ * identify current mmc instance, mmc1 has a reset, not mmc0
+ * MMC0 is wired to the SD slot,
+ * MMC1 is wired on the high speed connector
+ */
+
+ if (fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "resets", NULL))
+ mmc_instance = 1;
+ else
+ mmc_instance = 0;
+
+ sti_mmc_core_config((const u32) host->ioaddr, mmc_instance);
+
+ host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
+ SDHCI_QUIRK_32BIT_DMA_ADDR |
+ SDHCI_QUIRK_NO_HISPD_BIT;
+
+ host->host_caps = MMC_MODE_DDR_52MHz;
+
+ ret = sdhci_setup_cfg(&plat->cfg, host, 50000000, 400000);
+ if (ret)
+ return ret;
+
+ host->mmc = &plat->mmc;
+ host->mmc->priv = host;
+ host->mmc->dev = dev;
+ upriv->mmc = host->mmc;
+
+ return sdhci_probe(dev);
+}
+
+static int sti_sdhci_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sdhci_host *host = dev_get_priv(dev);
+
+ host->name = strdup(dev->name);
+ host->ioaddr = (void *)dev_get_addr(dev);
+
+ host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "bus-width", 4);
+
+ return 0;
+}
+
+static int sti_sdhci_bind(struct udevice *dev)
+{
+ struct sti_sdhci_plat *plat = dev_get_platdata(dev);
+
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id sti_sdhci_ids[] = {
+ { .compatible = "st,sdhci" },
+ { }
+};
+
+U_BOOT_DRIVER(sti_mmc) = {
+ .name = "sti_sdhci",
+ .id = UCLASS_MMC,
+ .of_match = sti_sdhci_ids,
+ .bind = sti_sdhci_bind,
+ .ops = &sdhci_ops,
+ .ofdata_to_platdata = sti_sdhci_ofdata_to_platdata,
+ .probe = sti_sdhci_probe,
+ .priv_auto_alloc_size = sizeof(struct sdhci_host),
+ .platdata_auto_alloc_size = sizeof(struct sti_sdhci_plat),
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index efcb4c0..0c832e1 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -175,6 +175,16 @@ config PIC32_PINCTRL
by a device tree node which contains both GPIO defintion and pin control
functions.
+config PINCTRL_STI
+ bool "STMicroelectronics STi pin-control and pin-mux driver"
+ depends on DM && ARCH_STI
+ default y
+ help
+ Support pin multiplexing control on STMicrolectronics STi SoCs.
+ The driver is controlled by a device tree node which contains both
+ the GPIO definitions and pin control functions for each available multiplex
+ function.
+
endif
source "drivers/pinctrl/meson/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 512112a..a2f8101 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o
obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/
obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/
+obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o
diff --git a/drivers/pinctrl/pinctrl-sti.c b/drivers/pinctrl/pinctrl-sti.c
new file mode 100644
index 0000000..40341b4
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sti.c
@@ -0,0 +1,320 @@
+/*
+ * Pinctrl driver for STMicroelectronics STi SoCs
+ *
+ * Copyright (c) 2017
+ * Patrice Chotard <patrice.chotard@st.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MAX_STI_PINCONF_ENTRIES 7
+/* Output enable */
+#define OE (1 << 27)
+/* Pull Up */
+#define PU (1 << 26)
+/* Open Drain */
+#define OD (1 << 25)
+
+/* User-frendly defines for Pin Direction */
+ /* oe = 0, pu = 0, od = 0 */
+#define IN (0)
+ /* oe = 0, pu = 1, od = 0 */
+#define IN_PU (PU)
+ /* oe = 1, pu = 0, od = 0 */
+#define OUT (OE)
+ /* oe = 1, pu = 1, od = 0 */
+#define OUT_PU (OE | PU)
+ /* oe = 1, pu = 0, od = 1 */
+#define BIDIR (OE | OD)
+ /* oe = 1, pu = 1, od = 1 */
+#define BIDIR_PU (OE | PU | OD)
+
+struct sti_pinctrl_platdata {
+ struct regmap *regmap;
+};
+
+struct sti_pin_desc {
+ unsigned char bank;
+ unsigned char pin;
+ unsigned char alt;
+ int dir;
+};
+
+/*
+ * PIO alternative Function selector
+ */
+void sti_alternate_select(struct udevice *dev, struct sti_pin_desc *pin_desc)
+{
+ struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
+ unsigned long sysconf, *sysconfreg;
+ int alt = pin_desc->alt;
+ int bank = pin_desc->bank;
+ int pin = pin_desc->pin;
+
+ sysconfreg = (unsigned long *)plat->regmap->base;
+
+ switch (bank) {
+ case 0 ... 5: /* in "SBC Bank" */
+ sysconfreg += bank;
+ break;
+ case 10 ... 20: /* in "FRONT Bank" */
+ sysconfreg += bank - 10;
+ break;
+ case 30 ... 35: /* in "REAR Bank" */
+ sysconfreg += bank - 30;
+ break;
+ case 40 ... 42: /* in "FLASH Bank" */
+ sysconfreg += bank - 40;
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ sysconf = readl(sysconfreg);
+ sysconf = bitfield_replace(sysconf, pin * 4, 3, alt);
+ writel(sysconf, sysconfreg);
+}
+
+/* pin configuration */
+void sti_pin_configure(struct udevice *dev, struct sti_pin_desc *pin_desc)
+{
+ struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
+ int bit;
+ int oe = 0, pu = 0, od = 0;
+ unsigned long *sysconfreg;
+ int bank = pin_desc->bank;
+
+ sysconfreg = (unsigned long *)plat->regmap->base + 40;
+
+ /*
+ * NOTE: The PIO configuration for the PIO pins in the
+ * "FLASH Bank" are different from all the other banks!
+ * Specifically, the output-enable pin control register
+ * (SYS_CFG_3040) and the pull-up pin control register
+ * (SYS_CFG_3050), are both classed as being "reserved".
+ * Hence, we do not write to these registers to configure
+ * the OE and PU features for PIOs in this bank. However,
+ * the open-drain pin control register (SYS_CFG_3060)
+ * follows the style of the other banks, and so we can
+ * treat that register normally.
+ *
+ * Being pedantic, we should configure the PU and PD features
+ * in the "FLASH Bank" explicitly instead using the four
+ * SYS_CFG registers: 3080, 3081, 3085, and 3086. However, this
+ * would necessitate passing in the alternate function number
+ * to this function, and adding some horrible complexity here.
+ * Alternatively, we could just perform 4 32-bit "pokes" to
+ * these four SYS_CFG registers early in the initialization.
+ * In practice, these four SYS_CFG registers are correct
+ * after a reset, and U-Boot does not need to change them, so
+ * we (cheat and) rely on these registers being correct.
+ * WARNING: Please be aware of this (pragmatic) behaviour!
+ */
+ int flashss = 0; /* bool: PIO in the Flash Sub-System ? */
+
+ switch (pin_desc->dir) {
+ case IN:
+ oe = 0; pu = 0; od = 0;
+ break;
+ case IN_PU:
+ oe = 0; pu = 1; od = 0;
+ break;
+ case OUT:
+ oe = 1; pu = 0; od = 0;
+ break;
+ case BIDIR:
+ oe = 1; pu = 0; od = 1;
+ break;
+ case BIDIR_PU:
+ oe = 1; pu = 1; od = 1;
+ break;
+
+ default:
+ error("%s invalid direction value: 0x%x\n",
+ __func__, pin_desc->dir);
+ BUG();
+ break;
+ }
+
+ switch (bank) {
+ case 0 ... 5: /* in "SBC Bank" */
+ sysconfreg += bank / 4;
+ break;
+ case 10 ... 20: /* in "FRONT Bank" */
+ bank -= 10;
+ sysconfreg += bank / 4;
+ break;
+ case 30 ... 35: /* in "REAR Bank" */
+ bank -= 30;
+ sysconfreg += bank / 4;
+ break;
+ case 40 ... 42: /* in "FLASH Bank" */
+ bank -= 40;
+ sysconfreg += bank / 4;
+ flashss = 1; /* pin is in the Flash Sub-System */
+ break;
+ default:
+ BUG();
+ return;
+ }
+
+ bit = ((bank * 8) + pin_desc->pin) % 32;
+
+ /*
+ * set the "Output Enable" pin control
+ * but, do nothing if in the flashSS
+ */
+ if (!flashss) {
+ if (oe)
+ generic_set_bit(bit, sysconfreg);
+ else
+ generic_clear_bit(bit, sysconfreg);
+ }
+
+ sysconfreg += 10; /* skip to next set of syscfg registers */
+
+ /*
+ * set the "Pull Up" pin control
+ * but, do nothing if in the FlashSS
+ */
+
+ if (!flashss) {
+ if (pu)
+ generic_set_bit(bit, sysconfreg);
+ else
+ generic_clear_bit(bit, sysconfreg);
+ }
+
+ sysconfreg += 10; /* skip to next set of syscfg registers */
+
+ /* set the "Open Drain Enable" pin control */
+ if (od)
+ generic_set_bit(bit, sysconfreg);
+ else
+ generic_clear_bit(bit, sysconfreg);
+}
+
+
+static int sti_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+ struct fdtdec_phandle_args args;
+ const void *blob = gd->fdt_blob;
+ const char *prop_name;
+ int node = dev_of_offset(config);
+ int property_offset, prop_len;
+ int pinconf_node, ret, count;
+ const char *bank_name;
+ u32 cells[MAX_STI_PINCONF_ENTRIES];
+
+ struct sti_pin_desc pin_desc;
+
+ /* go to next node "st,pins" which contains the pins configuration */
+ pinconf_node = fdt_subnode_offset(blob, node, "st,pins");
+
+ /*
+ * parse each pins configuration which looks like :
+ * pin_name = <bank_phandle pin_nb alt dir rt_type rt_delay rt_clk>
+ */
+
+ fdt_for_each_property_offset(property_offset, blob, pinconf_node) {
+ fdt_getprop_by_offset(blob, property_offset, &prop_name,
+ &prop_len);
+
+ /* extract the bank of the pin description */
+ ret = fdtdec_parse_phandle_with_args(blob, pinconf_node,
+ prop_name, "#gpio-cells",
+ 0, 0, &args);
+ if (ret < 0) {
+ error("Can't get the gpio bank phandle: %d\n", ret);
+ return ret;
+ }
+
+ bank_name = fdt_getprop(blob, args.node, "st,bank-name",
+ &count);
+ if (count < 0) {
+ error("Can't find bank-name property %d\n", count);
+ return -EINVAL;
+ }
+
+ pin_desc.bank = trailing_strtoln(bank_name, NULL);
+
+ count = fdtdec_get_int_array_count(blob, pinconf_node,
+ prop_name, cells,
+ ARRAY_SIZE(cells));
+ if (count < 0) {
+ error("Bad pin configuration array %d\n", count);
+ return -EINVAL;
+ }
+
+ if (count > MAX_STI_PINCONF_ENTRIES) {
+ error("Unsupported pinconf array count %d\n", count);
+ return -EINVAL;
+ }
+
+ pin_desc.pin = cells[1];
+ pin_desc.alt = cells[2];
+ pin_desc.dir = cells[3];
+
+ sti_alternate_select(dev, &pin_desc);
+ sti_pin_configure(dev, &pin_desc);
+ };
+
+ return 0;
+}
+
+static int sti_pinctrl_probe(struct udevice *dev)
+{
+ struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
+ struct udevice *syscon;
+ int err;
+
+ /* get corresponding syscon phandle */
+ err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "st,syscfg", &syscon);
+ if (err) {
+ error("unable to find syscon device\n");
+ return err;
+ }
+
+ plat->regmap = syscon_get_regmap(syscon);
+ if (!plat->regmap) {
+ error("unable to find regmap\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id sti_pinctrl_ids[] = {
+ { .compatible = "st,stih407-sbc-pinctrl" },
+ { .compatible = "st,stih407-front-pinctrl" },
+ { .compatible = "st,stih407-rear-pinctrl" },
+ { .compatible = "st,stih407-flash-pinctrl" },
+ { }
+};
+
+const struct pinctrl_ops sti_pinctrl_ops = {
+ .set_state = sti_pinctrl_set_state,
+};
+
+U_BOOT_DRIVER(pinctrl_sti) = {
+ .name = "pinctrl_sti",
+ .id = UCLASS_PINCTRL,
+ .of_match = sti_pinctrl_ids,
+ .ops = &sti_pinctrl_ops,
+ .probe = sti_pinctrl_probe,
+ .platdata_auto_alloc_size = sizeof(struct sti_pinctrl_platdata),
+ .ops = &sti_pinctrl_ops,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b11f3ff..7cb0eaa 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -413,4 +413,12 @@ config PXA_SERIAL
If you have a machine based on a Marvell XScale PXA2xx CPU you
can enable its onboard serial ports by enabling this option.
+config STI_ASC_SERIAL
+ bool "STMicroelectronics on-chip UART"
+ depends on DM_SERIAL && ARCH_STI
+ help
+ Select this to enable Asynchronous Serial Controller available
+ on STiH410 SoC. This is a basic implementation, it supports
+ following baudrate 9600, 19200, 38400, 57600 and 115200.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 8430668..84a22ce 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_FSL_LINFLEXUART) += serial_linflexuart.o
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
+obj-$(CONFIG_STI_ASC_SERIAL) += serial_sti_asc.o
obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o
obj-$(CONFIG_STM32X7_SERIAL) += serial_stm32x7.o
obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o
diff --git a/drivers/serial/serial_sti_asc.c b/drivers/serial/serial_sti_asc.c
new file mode 100644
index 0000000..ce26c94
--- /dev/null
+++ b/drivers/serial/serial_sti_asc.c
@@ -0,0 +1,211 @@
+/*
+ * Support for Serial I/O using STMicroelectronics' on-chip ASC.
+ *
+ * Copyright (c) 2017
+ * Patrice Chotard <patrice.chotard@st.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <serial.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BAUDMODE 0x00001000
+#define RXENABLE 0x00000100
+#define RUN 0x00000080
+#define MODE 0x00000001
+#define MODE_8BIT 0x0001
+#define STOP_1BIT 0x0008
+#define PARITYODD 0x0020
+
+#define STA_TF BIT(9)
+#define STA_RBF BIT(0)
+
+struct sti_asc_uart {
+ u32 baudrate;
+ u32 txbuf;
+ u32 rxbuf;
+ u32 control;
+ u32 inten;
+ u32 status;
+ u32 guardtime;
+ u32 timeout;
+ u32 txreset;
+ u32 rxreset;
+};
+
+struct sti_asc_serial {
+ /* address of registers in physical memory */
+ struct sti_asc_uart *regs;
+};
+
+/* Values for the BAUDRATE Register */
+#define PCLK (200ul * 1000000ul)
+#define BAUDRATE_VAL_M0(bps) (PCLK / (16 * (bps)))
+#define BAUDRATE_VAL_M1(bps) ((bps * (1 << 14)) + (1<<13)) / (PCLK/(1 << 6))
+
+/*
+ * MODE 0
+ * ICCLK
+ * ASCBaudRate = ----------------
+ * baudrate * 16
+ *
+ * MODE 1
+ * baudrate * 16 * 2^16
+ * ASCBaudRate = ------------------------
+ * ICCLK
+ *
+ * NOTE:
+ * Mode 1 should be used for baudrates of 19200, and above, as it
+ * has a lower deviation error than Mode 0 for higher frequencies.
+ * Mode 0 should be used for all baudrates below 19200.
+ */
+
+static int sti_asc_pending(struct udevice *dev, bool input)
+{
+ struct sti_asc_serial *priv = dev_get_priv(dev);
+ struct sti_asc_uart *const uart = priv->regs;
+ unsigned long status;
+
+ status = readl(&uart->status);
+ if (input)
+ return status & STA_RBF;
+ else
+ return status & STA_TF;
+}
+
+static int _sti_asc_serial_setbrg(struct sti_asc_uart *uart, int baudrate)
+{
+ unsigned long val;
+ int t, mode = 1;
+
+ switch (baudrate) {
+ case 9600:
+ t = BAUDRATE_VAL_M0(9600);
+ mode = 0;
+ break;
+ case 19200:
+ t = BAUDRATE_VAL_M1(19200);
+ break;
+ case 38400:
+ t = BAUDRATE_VAL_M1(38400);
+ break;
+ case 57600:
+ t = BAUDRATE_VAL_M1(57600);
+ break;
+ default:
+ debug("ASC: unsupported baud rate: %d, using 115200 instead.\n",
+ baudrate);
+ case 115200:
+ t = BAUDRATE_VAL_M1(115200);
+ break;
+ }
+
+ /* disable the baudrate generator */
+ val = readl(&uart->control);
+ writel(val & ~RUN, &uart->control);
+
+ /* set baud generator reload value */
+ writel(t, &uart->baudrate);
+ /* reset the RX & TX buffers */
+ writel(1, &uart->txreset);
+ writel(1, &uart->rxreset);
+
+ /* set baud generator mode */
+ if (mode)
+ val |= BAUDMODE;
+
+ /* finally, write value and enable ASC */
+ writel(val, &uart->control);
+
+ return 0;
+}
+
+/* called to adjust baud-rate */
+static int sti_asc_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct sti_asc_serial *priv = dev_get_priv(dev);
+ struct sti_asc_uart *const uart = priv->regs;
+
+ return _sti_asc_serial_setbrg(uart, baudrate);
+}
+
+/* blocking function, that returns next char */
+static int sti_asc_serial_getc(struct udevice *dev)
+{
+ struct sti_asc_serial *priv = dev_get_priv(dev);
+ struct sti_asc_uart *const uart = priv->regs;
+
+ /* polling wait: for a char to be read */
+ if (!sti_asc_pending(dev, true))
+ return -EAGAIN;
+
+ return readl(&uart->rxbuf);
+}
+
+/* write write out a single char */
+static int sti_asc_serial_putc(struct udevice *dev, const char c)
+{
+ struct sti_asc_serial *priv = dev_get_priv(dev);
+ struct sti_asc_uart *const uart = priv->regs;
+
+ /* wait till safe to write next char */
+ if (sti_asc_pending(dev, false))
+ return -EAGAIN;
+
+ /* finally, write next char */
+ writel(c, &uart->txbuf);
+
+ return 0;
+}
+
+/* initialize the ASC */
+static int sti_asc_serial_probe(struct udevice *dev)
+{
+ struct sti_asc_serial *priv = dev_get_priv(dev);
+ unsigned long val;
+ fdt_addr_t base;
+
+ base = dev_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = (struct sti_asc_uart *)base;
+ sti_asc_serial_setbrg(dev, gd->baudrate);
+
+ /*
+ * build up the value to be written to CONTROL
+ * set character length, bit stop number, odd parity
+ */
+ val = RXENABLE | RUN | MODE_8BIT | STOP_1BIT | PARITYODD;
+ writel(val, &priv->regs->control);
+
+ return 0;
+}
+
+static const struct dm_serial_ops sti_asc_serial_ops = {
+ .putc = sti_asc_serial_putc,
+ .pending = sti_asc_pending,
+ .getc = sti_asc_serial_getc,
+ .setbrg = sti_asc_serial_setbrg,
+};
+
+static const struct udevice_id sti_serial_of_match[] = {
+ { .compatible = "st,asc" },
+ { }
+};
+
+U_BOOT_DRIVER(serial_sti_asc) = {
+ .name = "serial_sti_asc",
+ .id = UCLASS_SERIAL,
+ .of_match = sti_serial_of_match,
+ .ops = &sti_asc_serial_ops,
+ .probe = sti_asc_serial_probe,
+ .priv_auto_alloc_size = sizeof(struct sti_asc_serial),
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 37638a8..21bcc21 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -13,5 +13,6 @@ obj-$(CONFIG_ROCKCHIP_RK3288) += sysreset_rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3399) += sysreset_rk3399.o
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
obj-$(CONFIG_ARCH_SNAPDRAGON) += sysreset_snapdragon.o
+obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
diff --git a/drivers/sysreset/sysreset_sti.c b/drivers/sysreset/sysreset_sti.c
new file mode 100644
index 0000000..9b58aa8
--- /dev/null
+++ b/drivers/sysreset/sysreset_sti.c
@@ -0,0 +1,82 @@
+/*
+ * (C) Copyright 2017 Patrice Chotard <patrice.chotard@st.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <sysreset.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sti_sysreset_priv {
+ phys_addr_t base;
+};
+
+static int sti_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct sti_sysreset_priv *priv = dev_get_priv(dev);
+
+ generic_clear_bit(0, (void __iomem *)priv->base);
+
+ return -EINPROGRESS;
+}
+
+static int sti_sysreset_probe(struct udevice *dev)
+{
+ struct sti_sysreset_priv *priv = dev_get_priv(dev);
+ struct udevice *syscon;
+ struct regmap *regmap;
+ struct fdtdec_phandle_args syscfg_phandle;
+ int ret;
+
+ /* get corresponding syscon phandle */
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
+ "st,syscfg", NULL, 0, 0,
+ &syscfg_phandle);
+ if (ret < 0) {
+ error("Can't get syscfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SYSCON,
+ syscfg_phandle.node,
+ &syscon);
+ if (ret) {
+ error("%s: uclass_get_device_by_of_offset failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ regmap = syscon_get_regmap(syscon);
+ if (!regmap) {
+ error("unable to get regmap for %s\n", syscon->name);
+ return -ENODEV;
+ }
+
+ priv->base = regmap->base;
+
+ return 0;
+}
+
+static struct sysreset_ops sti_sysreset = {
+ .request = sti_sysreset_request,
+};
+
+static const struct udevice_id sti_sysreset_ids[] = {
+ { .compatible = "st,stih407-restart" },
+ { }
+};
+
+U_BOOT_DRIVER(sysreset_sti) = {
+ .name = "sysreset_sti",
+ .id = UCLASS_SYSRESET,
+ .ops = &sti_sysreset,
+ .probe = sti_sysreset_probe,
+ .of_match = sti_sysreset_ids,
+ .priv_auto_alloc_size = sizeof(struct sti_sysreset_priv),
+};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index cd38a6d..72c1416 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -58,4 +58,11 @@ config AST_TIMER
This is mostly because they all share several registers which
makes it difficult to completely separate them.
+config STI_TIMER
+ bool "STi timer support"
+ depends on TIMER
+ default y if ARCH_STI
+ help
+ Select this to enable a timer for STi devices.
+
endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index a4b1a48..ae94be8 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
obj-$(CONFIG_AST_TIMER) += ast_timer.o
+obj-$(CONFIG_STI_TIMER) += sti-timer.o
diff --git a/drivers/timer/sti-timer.c b/drivers/timer/sti-timer.c
new file mode 100644
index 0000000..e1419c4
--- /dev/null
+++ b/drivers/timer/sti-timer.c
@@ -0,0 +1,78 @@
+/*
+ * (C) Copyright 2017 Patrice Chotard <patrice.chotard@st.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <timer.h>
+
+#include <asm/io.h>
+#include <asm/arch-armv7/globaltimer.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sti_timer_priv {
+ struct globaltimer *global_timer;
+};
+
+static int sti_timer_get_count(struct udevice *dev, u64 *count)
+{
+ struct sti_timer_priv *priv = dev_get_priv(dev);
+ struct globaltimer *global_timer = priv->global_timer;
+ u32 low, high;
+ u64 timer;
+ u32 old = readl(&global_timer->cnt_h);
+
+ while (1) {
+ low = readl(&global_timer->cnt_l);
+ high = readl(&global_timer->cnt_h);
+ if (old == high)
+ break;
+ else
+ old = high;
+ }
+ timer = high;
+ *count = (u64)((timer << 32) | low);
+
+ return 0;
+}
+
+static int sti_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct sti_timer_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+
+ uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+
+ /* get arm global timer base address */
+ addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg");
+ priv->global_timer = (struct globaltimer *)addr;
+
+ /* init timer */
+ writel(0x01, &priv->global_timer->ctl);
+
+ return 0;
+}
+
+static const struct timer_ops sti_timer_ops = {
+ .get_count = sti_timer_get_count,
+};
+
+static const struct udevice_id sti_timer_ids[] = {
+ { .compatible = "arm,cortex-a9-global-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(sti_timer) = {
+ .name = "sti_timer",
+ .id = UCLASS_TIMER,
+ .of_match = sti_timer_ids,
+ .priv_auto_alloc_size = sizeof(struct sti_timer_priv),
+ .probe = sti_timer_probe,
+ .ops = &sti_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};