diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/sti_sdhci.c | 141 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-sti.c | 320 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 8 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/serial_sti_asc.c | 211 | ||||
-rw-r--r-- | drivers/sysreset/Makefile | 1 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_sti.c | 82 | ||||
-rw-r--r-- | drivers/timer/Kconfig | 7 | ||||
-rw-r--r-- | drivers/timer/Makefile | 1 | ||||
-rw-r--r-- | drivers/timer/sti-timer.c | 78 |
14 files changed, 869 insertions, 0 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 01d1dbfb1b..ddef59a3c0 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 8e922db3f1..6a488f1db9 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 0000000000..2a07082036 --- /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 efcb4c0003..0c832e187d 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 512112af64..a2f810156b 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 0000000000..40341b4eeb --- /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 b11f3ff89e..7cb0eaab73 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 8430668bf9..84a22ce14c 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 0000000000..ce26c94710 --- /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 37638a8eea..21bcc21627 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 0000000000..9b58aa8e97 --- /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 cd38a6d4bd..72c14168d6 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 a4b1a486b0..ae94be86c0 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 0000000000..e1419c4976 --- /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, +}; |