diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/aspeed/Makefile | 7 | ||||
-rw-r--r-- | drivers/clk/aspeed/clk_ast2500.c | 265 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier-core.c | 6 | ||||
-rw-r--r-- | drivers/i2c/i2c-uniphier-f.c | 35 | ||||
-rw-r--r-- | drivers/i2c/i2c-uniphier.c | 1 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 96 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 16 | ||||
-rw-r--r-- | drivers/net/designware.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 54 | ||||
-rw-r--r-- | drivers/net/phy/smsc.c | 12 | ||||
-rw-r--r-- | drivers/pci/pci_mvebu.c | 25 | ||||
-rw-r--r-- | drivers/phy/marvell/comphy_a3700.c | 7 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/stm32_qspi.c | 628 | ||||
-rw-r--r-- | drivers/sysreset/Makefile | 1 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_ast.c | 55 | ||||
-rw-r--r-- | drivers/timer/Kconfig | 12 | ||||
-rw-r--r-- | drivers/timer/Makefile | 1 | ||||
-rw-r--r-- | drivers/timer/ast_timer.c | 97 | ||||
-rw-r--r-- | drivers/tpm/Kconfig | 6 |
22 files changed, 1237 insertions, 99 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f55348e8f1..884c21c68b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -17,3 +17,5 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o + +obj-$(CONFIG_ARCH_ASPEED) += aspeed/ diff --git a/drivers/clk/aspeed/Makefile b/drivers/clk/aspeed/Makefile new file mode 100644 index 0000000000..65d1cd6e29 --- /dev/null +++ b/drivers/clk/aspeed/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_ASPEED_AST2500) += clk_ast2500.o diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c new file mode 100644 index 0000000000..af369cc4c8 --- /dev/null +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -0,0 +1,265 @@ +/* + * (C) Copyright 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/scu_ast2500.h> +#include <dm/lists.h> +#include <dt-bindings/clock/ast2500-scu.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * For H-PLL and M-PLL the formula is + * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1) + * M - Numerator + * N - Denumerator + * P - Post Divider + * They have the same layout in their control register. + */ + +/* + * Get the rate of the M-PLL clock from input clock frequency and + * the value of the M-PLL Parameter Register. + */ +static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg) +{ + const ulong num = (mpll_reg >> SCU_MPLL_NUM_SHIFT) & SCU_MPLL_NUM_MASK; + const ulong denum = (mpll_reg >> SCU_MPLL_DENUM_SHIFT) + & SCU_MPLL_DENUM_MASK; + const ulong post_div = (mpll_reg >> SCU_MPLL_POST_SHIFT) + & SCU_MPLL_POST_MASK; + + return (clkin * ((num + 1) / (denum + 1))) / post_div; +} + +/* + * Get the rate of the H-PLL clock from input clock frequency and + * the value of the H-PLL Parameter Register. + */ +static ulong ast2500_get_hpll_rate(ulong clkin, u32 hpll_reg) +{ + const ulong num = (hpll_reg >> SCU_HPLL_NUM_SHIFT) & SCU_HPLL_NUM_MASK; + const ulong denum = (hpll_reg >> SCU_HPLL_DENUM_SHIFT) + & SCU_HPLL_DENUM_MASK; + const ulong post_div = (hpll_reg >> SCU_HPLL_POST_SHIFT) + & SCU_HPLL_POST_MASK; + + return (clkin * ((num + 1) / (denum + 1))) / post_div; +} + +static ulong ast2500_get_clkin(struct ast2500_scu *scu) +{ + return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ + ? 25 * 1000 * 1000 : 24 * 1000 * 1000; +} + +/** + * Get current rate or uart clock + * + * @scu SCU registers + * @uart_index UART index, 1-5 + * + * @return current setting for uart clock rate + */ +static ulong ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_index) +{ + /* + * ast2500 datasheet is very confusing when it comes to UART clocks, + * especially when CLKIN = 25 MHz. The settings are in + * different registers and it is unclear how they interact. + * + * This has only been tested with default settings and CLKIN = 24 MHz. + */ + ulong uart_clkin; + + if (readl(&scu->misc_ctrl2) & + (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT))) + uart_clkin = 192 * 1000 * 1000; + else + uart_clkin = 24 * 1000 * 1000; + + if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13) + uart_clkin /= 13; + + return uart_clkin; +} + +static ulong ast2500_clk_get_rate(struct clk *clk) +{ + struct ast2500_clk_priv *priv = dev_get_priv(clk->dev); + ulong clkin = ast2500_get_clkin(priv->scu); + ulong rate; + + switch (clk->id) { + case PLL_HPLL: + case ARMCLK: + /* + * This ignores dynamic/static slowdown of ARMCLK and may + * be inaccurate. + */ + rate = ast2500_get_hpll_rate(clkin, + readl(&priv->scu->h_pll_param)); + break; + case MCLK_DDR: + rate = ast2500_get_mpll_rate(clkin, + readl(&priv->scu->m_pll_param)); + break; + case PCLK_UART1: + rate = ast2500_get_uart_clk_rate(priv->scu, 1); + break; + case PCLK_UART2: + rate = ast2500_get_uart_clk_rate(priv->scu, 2); + break; + case PCLK_UART3: + rate = ast2500_get_uart_clk_rate(priv->scu, 3); + break; + case PCLK_UART4: + rate = ast2500_get_uart_clk_rate(priv->scu, 4); + break; + case PCLK_UART5: + rate = ast2500_get_uart_clk_rate(priv->scu, 5); + break; + default: + return -ENOENT; + } + + return rate; +} + +static void ast2500_scu_unlock(struct ast2500_scu *scu) +{ + writel(SCU_UNLOCK_VALUE, &scu->protection_key); + while (!readl(&scu->protection_key)) + ; +} + +static void ast2500_scu_lock(struct ast2500_scu *scu) +{ + writel(~SCU_UNLOCK_VALUE, &scu->protection_key); + while (readl(&scu->protection_key)) + ; +} + +static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate) +{ + ulong clkin = ast2500_get_clkin(scu); + u32 mpll_reg; + + /* + * There are not that many combinations of numerator, denumerator + * and post divider, so just brute force the best combination. + * However, to avoid overflow when multiplying, use kHz. + */ + const ulong clkin_khz = clkin / 1000; + const ulong rate_khz = rate / 1000; + ulong best_num = 0; + ulong best_denum = 0; + ulong best_post = 0; + ulong delta = rate; + ulong num, denum, post; + + for (denum = 0; denum <= SCU_MPLL_DENUM_MASK; ++denum) { + for (post = 0; post <= SCU_MPLL_POST_MASK; ++post) { + num = (rate_khz * (post + 1) / clkin_khz) * (denum + 1); + ulong new_rate_khz = (clkin_khz + * ((num + 1) / (denum + 1))) + / (post + 1); + + /* Keep the rate below requested one. */ + if (new_rate_khz > rate_khz) + continue; + + if (new_rate_khz - rate_khz < delta) { + delta = new_rate_khz - rate_khz; + + best_num = num; + best_denum = denum; + best_post = post; + + if (delta == 0) + goto rate_calc_done; + } + } + } + + rate_calc_done: + mpll_reg = readl(&scu->m_pll_param); + mpll_reg &= ~((SCU_MPLL_POST_MASK << SCU_MPLL_POST_SHIFT) + | (SCU_MPLL_NUM_MASK << SCU_MPLL_NUM_SHIFT) + | (SCU_MPLL_DENUM_MASK << SCU_MPLL_DENUM_SHIFT)); + mpll_reg |= (best_post << SCU_MPLL_POST_SHIFT) + | (best_num << SCU_MPLL_NUM_SHIFT) + | (best_denum << SCU_MPLL_DENUM_SHIFT); + + ast2500_scu_unlock(scu); + writel(mpll_reg, &scu->m_pll_param); + ast2500_scu_lock(scu); + + return ast2500_get_mpll_rate(clkin, mpll_reg); +} + +static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate) +{ + struct ast2500_clk_priv *priv = dev_get_priv(clk->dev); + + ulong new_rate; + switch (clk->id) { + case PLL_MPLL: + case MCLK_DDR: + new_rate = ast2500_configure_ddr(priv->scu, rate); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +struct clk_ops ast2500_clk_ops = { + .get_rate = ast2500_clk_get_rate, + .set_rate = ast2500_clk_set_rate, +}; + +static int ast2500_clk_probe(struct udevice *dev) +{ + struct ast2500_clk_priv *priv = dev_get_priv(dev); + + priv->scu = dev_get_addr_ptr(dev); + if (IS_ERR(priv->scu)) + return PTR_ERR(priv->scu); + + return 0; +} + +static int ast2500_clk_bind(struct udevice *dev) +{ + int ret; + + /* The reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); + if (ret) + debug("Warning: No reset driver: ret=%d\n", ret); + + return 0; +} + +static const struct udevice_id ast2500_clk_ids[] = { + { .compatible = "aspeed,ast2500-scu" }, + { } +}; + +U_BOOT_DRIVER(aspeed_ast2500_scu) = { + .name = "aspeed_ast2500_scu", + .id = UCLASS_CLK, + .of_match = ast2500_clk_ids, + .priv_auto_alloc_size = sizeof(struct ast2500_clk_priv), + .ops = &ast2500_clk_ops, + .bind = ast2500_clk_bind, + .probe = ast2500_clk_probe, +}; diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 8ad0242d2a..bcb2d2edb7 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -163,11 +163,11 @@ static const struct udevice_id uniphier_clk_match[] = { .data = (ulong)&uniphier_mio_clk_data, }, { - .compatible = "socionext,uniphier-pro5-mio-clock", + .compatible = "socionext,uniphier-pro5-sd-clock", .data = (ulong)&uniphier_mio_clk_data, }, { - .compatible = "socionext,uniphier-pxs2-mio-clock", + .compatible = "socionext,uniphier-pxs2-sd-clock", .data = (ulong)&uniphier_mio_clk_data, }, { @@ -175,7 +175,7 @@ static const struct udevice_id uniphier_clk_match[] = { .data = (ulong)&uniphier_mio_clk_data, }, { - .compatible = "socionext,uniphier-ld20-mio-clock", + .compatible = "socionext,uniphier-ld20-sd-clock", .data = (ulong)&uniphier_mio_clk_data, }, { /* sentinel */ } diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c index 8bfa916294..9f0df599a0 100644 --- a/drivers/i2c/i2c-uniphier-f.c +++ b/drivers/i2c/i2c-uniphier-f.c @@ -9,10 +9,10 @@ #include <common.h> #include <linux/types.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/sizes.h> #include <linux/errno.h> #include <dm/device.h> -#include <dm/root.h> #include <i2c.h> #include <fdtdec.h> @@ -70,26 +70,14 @@ struct uniphier_fi2c_dev { unsigned long timeout; /* time out (us) */ }; -static int poll_status(u32 __iomem *reg, u32 flag) -{ - int wait = 1000000; /* 1 sec is long enough */ - - while (readl(reg) & flag) { - if (wait-- < 0) - return -EREMOTEIO; - udelay(1); - } - - return 0; -} - static int reset_bus(struct uniphier_fi2c_regs __iomem *regs) { + u32 val; int ret; /* bus forcible reset */ writel(I2C_RST_RST, ®s->rst); - ret = poll_status(®s->rst, I2C_RST_RST); + ret = readl_poll_timeout(®s->rst, val, !(val & I2C_RST_RST), 1); if (ret < 0) debug("error: fail to reset I2C controller\n"); @@ -98,9 +86,10 @@ static int reset_bus(struct uniphier_fi2c_regs __iomem *regs) static int check_device_busy(struct uniphier_fi2c_regs __iomem *regs) { + u32 val; int ret; - ret = poll_status(®s->sr, I2C_SR_DB); + ret = readl_poll_timeout(®s->sr, val, !(val & I2C_SR_DB), 100); if (ret < 0) { debug("error: device busy too long. reset...\n"); ret = reset_bus(regs); @@ -139,15 +128,11 @@ static int wait_for_irq(struct uniphier_fi2c_dev *dev, u32 flags, bool *stop) { u32 irq; - unsigned long wait = dev->timeout; - int ret = -EREMOTEIO; - - do { - udelay(1); - irq = readl(&dev->regs->intr); - } while (!(irq & flags) && wait--); + int ret; - if (wait < 0) { + ret = readl_poll_timeout(&dev->regs->intr, irq, irq & flags, + dev->timeout); + if (ret < 0) { debug("error: time out\n"); return ret; } @@ -173,7 +158,7 @@ static int issue_stop(struct uniphier_fi2c_dev *dev, int old_ret) debug("stop condition\n"); writel(I2C_CR_MST | I2C_CR_STO, &dev->regs->cr); - ret = poll_status(&dev->regs->sr, I2C_SR_DB); + ret = check_device_busy(dev->regs); if (ret < 0) debug("error: device busy after operation\n"); diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c index f391f11e93..73575e9895 100644 --- a/drivers/i2c/i2c-uniphier.c +++ b/drivers/i2c/i2c-uniphier.c @@ -12,7 +12,6 @@ #include <linux/sizes.h> #include <linux/errno.h> #include <dm/device.h> -#include <dm/root.h> #include <i2c.h> #include <fdtdec.h> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 147e52d332..0c07781115 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -10,6 +10,10 @@ config MMC If you want MMC/SD/SDIO support, you should say Y here and also to your specific host controller driver. +config GENERIC_MMC + bool "Generic MMC driver framework" + default MMC + config DM_MMC bool "Enable MMC controllers using Driver Model" depends on DM @@ -47,27 +51,6 @@ config SPL_MMC_TINY operations too, which can remove the need for malloc support in SPL and thus further reduce footprint. -config MSM_SDHCI - bool "Qualcomm SDHCI controller" - depends on DM_MMC && BLK && DM_MMC_OPS - depends on MMC_SDHCI - help - Enables support for SDHCI 2.0 controller present on some Qualcomm - Snapdragon devices. This device is compatible with eMMC v4.5 and - SD 3.0 specifications. Both SD and eMMC devices are supported. - Card-detect gpios are not supported. - -config ATMEL_SDHCI - bool "Atmel SDHCI controller support" - depends on DM_MMC && BLK && DM_MMC_OPS && ARCH_AT91 - depends on MMC_SDHCI - help - This enables support for the Atmel SDHCI controller, which supports - the embedded MultiMedia Card (e.MMC) Specification V4.51, the SD - Memory Card Specification V3.0, and the SDIO V3.0 specification. - It is compliant with the SD Host Controller Standard V3.0 - specification. - config MMC_DAVINCI bool "TI DAVINCI Multimedia Card Interface support" depends on ARCH_DAVINCI @@ -154,27 +137,6 @@ config SH_SDHI help Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform -config PIC32_SDHCI - bool "Microchip PIC32 on-chip SDHCI support" - depends on DM_MMC && MACH_PIC32 - depends on MMC_SDHCI - help - Support for Microchip PIC32 SDHCI controller. - -config ZYNQ_SDHCI - bool "Arasan SDHCI controller support" - depends on DM_MMC && OF_CONTROL && BLK && DM_MMC_OPS - depends on MMC_SDHCI - help - Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform - -config ROCKCHIP_SDHCI - bool "Arasan SDHCI controller for Rockchip support" - depends on DM_MMC && BLK && DM_MMC_OPS - depends on MMC_SDHCI - help - Support for Arasan SDHCI host controller on Rockchip ARM SoCs platform - config MMC_UNIPHIER bool "UniPhier SD/MMC Host Controller support" depends on ARCH_UNIPHIER @@ -183,9 +145,10 @@ config MMC_UNIPHIER help This selects support for the SD/MMC Host Controller on UniPhier SoCs. -config SANDBOX_MMC +config MMC_SANDBOX bool "Sandbox MMC support" - depends on MMC && SANDBOX + depends on SANDBOX + depends on BLK && DM_MMC_OPS && OF_CONTROL help This select a dummy sandbox MMC driver. At present this does nothing other than allow sandbox to be build with MMC support. This @@ -217,6 +180,18 @@ config MMC_SDHCI_SDMA This enables support for the SDMA (Single Operation DMA) defined in the SD Host Controller Standard Specification Version 1.00 . +config MMC_SDHCI_ATMEL + bool "Atmel SDHCI controller support" + depends on ARCH_AT91 + depends on DM_MMC && BLK && DM_MMC_OPS && ARCH_AT91 + depends on MMC_SDHCI + help + This enables support for the Atmel SDHCI controller, which supports + the embedded MultiMedia Card (e.MMC) Specification V4.51, the SD + Memory Card Specification V3.0, and the SDIO V3.0 specification. + It is compliant with the SD Host Controller Standard V3.0 + specification. + config MMC_SDHCI_BCM2835 tristate "SDHCI support for the BCM2835 SD/MMC Controller" depends on ARCH_BCM283X @@ -252,6 +227,16 @@ config MMC_SDHCI_KONA If you have a controller with this interface, say Y here. +config MMC_SDHCI_MSM + bool "Qualcomm SDHCI controller" + depends on BLK && DM_MMC_OPS + depends on MMC_SDHCI + help + Enables support for SDHCI 2.0 controller present on some Qualcomm + Snapdragon devices. This device is compatible with eMMC v4.5 and + SD 3.0 specifications. Both SD and eMMC devices are supported. + Card-detect gpios are not supported. + config MMC_SDHCI_MV bool "SDHCI support on Marvell platform" depends on ARCH_MVEBU @@ -264,6 +249,21 @@ config MMC_SDHCI_MV If unsure, say N. +config MMC_SDHCI_PIC32 + bool "Microchip PIC32 on-chip SDHCI support" + depends on DM_MMC && MACH_PIC32 + depends on MMC_SDHCI + help + Support for Microchip PIC32 SDHCI controller. + +config MMC_SDHCI_ROCKCHIP + bool "Arasan SDHCI controller for Rockchip support" + depends on ARCH_ROCKCHIP + depends on DM_MMC && BLK && DM_MMC_OPS + depends on MMC_SDHCI + help + Support for Arasan SDHCI host controller on Rockchip ARM SoCs platform + config MMC_SDHCI_S5P bool "SDHCI support on Samsung S5P SoC" depends on MMC_SDHCI @@ -308,6 +308,14 @@ config MMC_SDHCI_TEGRA If unsure, say N. +config MMC_SDHCI_ZYNQ + bool "Arasan SDHCI controller support" + depends on ARCH_ZYNQ || ARCH_ZYNQMP + depends on DM_MMC && OF_CONTROL && BLK && DM_MMC_OPS + depends on MMC_SDHCI + help + Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform + config MMC_SUNXI bool "Allwinner sunxi SD/MMC Host Controller support" depends on ARCH_SUNXI && !UART0_PORT_F diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6af7f79ff8..e78bd0d41d 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_GENERIC_MMC) += mmc_legacy.o endif obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o -obj-$(CONFIG_ATMEL_SDHCI) += atmel_sdhci.o obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o @@ -40,15 +39,9 @@ obj-$(CONFIG_X86) += pci_mmc.o obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o obj-$(CONFIG_S3C_SDI) += s3c_sdi.o -ifdef CONFIG_BLK -ifdef CONFIG_GENERIC_MMC -obj-$(CONFIG_SANDBOX) += sandbox_mmc.o -endif -endif +obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o -obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o -obj-$(CONFIG_ROCKCHIP_SDHCI) += rockchip_sdhci.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o @@ -56,19 +49,22 @@ obj-$(CONFIG_SPL_SAVEENV) += mmc_write.o else obj-$(CONFIG_GENERIC_MMC) += mmc_write.o endif -obj-$(CONFIG_PIC32_SDHCI) += pic32_sdhci.o -obj-$(CONFIG_MSM_SDHCI) += msm_sdhci.o # SDHCI obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o +obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o +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_TEGRA) += tegra_mmc.o obj-$(CONFIG_MMC_SDHCI_XENON) += xenon_sdhci.o +obj-$(CONFIG_MMC_SDHCI_ZYNQ) += zynq_sdhci.o obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o diff --git a/drivers/net/designware.c b/drivers/net/designware.c index f242fc6b3f..e207bc63b8 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -763,6 +763,7 @@ static const struct udevice_id designware_eth_ids[] = { { .compatible = "allwinner,sun7i-a20-gmac" }, { .compatible = "altr,socfpga-stmmac" }, { .compatible = "amlogic,meson6-dwmac" }, + { .compatible = "st,stm32-dwmac" }, { } }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4eeb0f6ede..c3058a40b2 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -480,6 +480,49 @@ static int m88e1310_config(struct phy_device *phydev) return genphy_config_aneg(phydev); } +static int m88e1680_config(struct phy_device *phydev) +{ + /* + * As per Marvell Release Notes - Alaska V 88E1680 Rev A2 + * Errata Section 4.1 + */ + u16 reg; + int res; + + /* Matrix LED mode (not neede if single LED mode is used */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0004); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 27); + reg |= (1 << 5); + phy_write(phydev, MDIO_DEVAD_NONE, 27, reg); + + /* QSGMII TX amplitude change */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00fd); + phy_write(phydev, MDIO_DEVAD_NONE, 8, 0x0b53); + phy_write(phydev, MDIO_DEVAD_NONE, 7, 0x200d); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + + /* EEE initialization */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff); + phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb030); + phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x215c); + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fc); + phy_write(phydev, MDIO_DEVAD_NONE, 24, 0x888c); + phy_write(phydev, MDIO_DEVAD_NONE, 25, 0x888c); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140); + + res = genphy_config_aneg(phydev); + if (res < 0) + return res; + + /* soft reset */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + reg |= BMCR_RESET; + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg); + + return 0; +} + static struct phy_driver M88E1011S_driver = { .name = "Marvell 88E1011S", .uid = 0x1410c60, @@ -580,6 +623,16 @@ static struct phy_driver M88E1310_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1680_driver = { + .name = "Marvell 88E1680", + .uid = 0x1410ed0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1680_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { phy_register(&M88E1310_driver); @@ -592,6 +645,7 @@ int phy_marvell_init(void) phy_register(&M88E1011S_driver); phy_register(&M88E1510_driver); phy_register(&M88E1518_driver); + phy_register(&M88E1680_driver); return 0; } diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 313fcdfdc5..41ffbe9d0e 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -82,12 +82,24 @@ static struct phy_driver lan8740_driver = { .startup = &genphy_startup, .shutdown = &genphy_shutdown, }; + +static struct phy_driver lan8742_driver = { + .name = "SMSC LAN8742", + .uid = 0x0007c130, + .mask = 0xffff0, + .features = PHY_BASIC_FEATURES, + .config = &genphy_config_aneg, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + int phy_smsc_init(void) { phy_register(&lan8710_driver); phy_register(&lan911x_driver); phy_register(&lan8700_driver); phy_register(&lan8740_driver); + phy_register(&lan8742_driver); return 0; } diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 0f449703de..da0aa29865 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -91,25 +91,26 @@ static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE; #if defined(CONFIG_ARMADA_38X) #define PCIE_BASE(if) \ ((if) == 0 ? \ - MVEBU_REG_PCIE_BASE + 0x40000 : \ - MVEBU_REG_PCIE_BASE + 0x4000 * (if)) + MVEBU_REG_PCIE0_BASE : \ + (MVEBU_REG_PCIE_BASE + 0x4000 * (if - 1))) /* * On A38x MV6820 these PEX ports are supported: * 0 - Port 0.0 - * 1 - Port 0.1 - * 2 - Port 0.2 + * 1 - Port 1.0 + * 2 - Port 2.0 + * 3 - Port 3.0 */ -#define MAX_PEX 3 +#define MAX_PEX 4 static struct mvebu_pcie pcie_bus[MAX_PEX]; static void mvebu_get_port_lane(struct mvebu_pcie *pcie, int pex_idx, int *mem_target, int *mem_attr) { - u8 port[] = { 0, 1, 2 }; - u8 lane[] = { 0, 0, 0 }; - u8 target[] = { 8, 4, 4 }; - u8 attr[] = { 0xe8, 0xe8, 0xd8 }; + u8 port[] = { 0, 1, 2, 3 }; + u8 lane[] = { 0, 0, 0, 0 }; + u8 target[] = { 8, 4, 4, 4 }; + u8 attr[] = { 0xe8, 0xe8, 0xd8, 0xb8 }; pcie->port = port[pex_idx]; pcie->lane = lane[pex_idx]; @@ -351,9 +352,9 @@ void pci_init_board(void) mvebu_get_port_lane(pcie, i, &mem_target, &mem_attr); /* Don't read at all from pci registers if port power is down */ - if (pcie->lane == 0 && SELECT(soc_ctrl, pcie->port) == 0) { - i += 3; - debug("%s: skipping port %d\n", __func__, pcie->port); + if (SELECT(soc_ctrl, pcie->port) == 0) { + if (pcie->lane == 0) + debug("%s: skipping port %d\n", __func__, pcie->port); continue; } diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c index faa62f90ae..5afd23c052 100644 --- a/drivers/phy/marvell/comphy_a3700.c +++ b/drivers/phy/marvell/comphy_a3700.c @@ -884,11 +884,10 @@ void comphy_dedicated_phys_init(void) } node = fdt_node_offset_by_compatible(blob, -1, - "marvell,armada-3700-sdio"); + "marvell,armada-8k-sdhci"); if (node <= 0) { - debug("No SDIO node in DT, looking for MMC one\n"); - node = fdt_node_offset_by_compatible(blob, -1, - "marvell,xenon-sdhci"); + node = fdt_node_offset_by_compatible( + blob, -1, "marvell,armada-3700-sdhci"); } if (node > 0) { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0f51b3a21b..f3f7dbe089 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -124,6 +124,14 @@ config SANDBOX_SPI }; }; +config STM32_QSPI + bool "STM32F7 QSPI driver" + depends on STM32F7 + help + Enable the STM32F7 Quad-SPI (QSPI) driver. This driver can be + used to access the SPI NOR flash chips on platforms embedding + this ST IP core. + config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 896b093765..fa9a1d2496 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o 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_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c new file mode 100644 index 0000000000..123a1f368d --- /dev/null +++ b/drivers/spi/stm32_qspi.c @@ -0,0 +1,628 @@ +/* + * (C) Copyright 2016 + * + * Michael Kurz, <michi.kurz@gmail.com> + * + * STM32 QSPI driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <spi_flash.h> +#include <asm/io.h> +#include <dm.h> +#include <errno.h> +#include <asm/arch/stm32.h> +#include <asm/arch/stm32_defs.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct stm32_qspi_regs { + u32 cr; /* 0x00 */ + u32 dcr; /* 0x04 */ + u32 sr; /* 0x08 */ + u32 fcr; /* 0x0C */ + u32 dlr; /* 0x10 */ + u32 ccr; /* 0x14 */ + u32 ar; /* 0x18 */ + u32 abr; /* 0x1C */ + u32 dr; /* 0x20 */ + u32 psmkr; /* 0x24 */ + u32 psmar; /* 0x28 */ + u32 pir; /* 0x2C */ + u32 lptr; /* 0x30 */ +}; + +/* + * QUADSPI control register + */ +#define STM32_QSPI_CR_EN BIT(0) +#define STM32_QSPI_CR_ABORT BIT(1) +#define STM32_QSPI_CR_DMAEN BIT(2) +#define STM32_QSPI_CR_TCEN BIT(3) +#define STM32_QSPI_CR_SSHIFT BIT(4) +#define STM32_QSPI_CR_DFM BIT(6) +#define STM32_QSPI_CR_FSEL BIT(7) +#define STM32_QSPI_CR_FTHRES_MASK GENMASK(4, 0) +#define STM32_QSPI_CR_FTHRES_SHIFT (8) +#define STM32_QSPI_CR_TEIE BIT(16) +#define STM32_QSPI_CR_TCIE BIT(17) +#define STM32_QSPI_CR_FTIE BIT(18) +#define STM32_QSPI_CR_SMIE BIT(19) +#define STM32_QSPI_CR_TOIE BIT(20) +#define STM32_QSPI_CR_APMS BIT(22) +#define STM32_QSPI_CR_PMM BIT(23) +#define STM32_QSPI_CR_PRESCALER_MASK GENMASK(7, 0) +#define STM32_QSPI_CR_PRESCALER_SHIFT (24) + +/* + * QUADSPI device configuration register + */ +#define STM32_QSPI_DCR_CKMODE BIT(0) +#define STM32_QSPI_DCR_CSHT_MASK GENMASK(2, 0) +#define STM32_QSPI_DCR_CSHT_SHIFT (8) +#define STM32_QSPI_DCR_FSIZE_MASK GENMASK(4, 0) +#define STM32_QSPI_DCR_FSIZE_SHIFT (16) + +/* + * QUADSPI status register + */ +#define STM32_QSPI_SR_TEF BIT(0) +#define STM32_QSPI_SR_TCF BIT(1) +#define STM32_QSPI_SR_FTF BIT(2) +#define STM32_QSPI_SR_SMF BIT(3) +#define STM32_QSPI_SR_TOF BIT(4) +#define STM32_QSPI_SR_BUSY BIT(5) +#define STM32_QSPI_SR_FLEVEL_MASK GENMASK(5, 0) +#define STM32_QSPI_SR_FLEVEL_SHIFT (8) + +/* + * QUADSPI flag clear register + */ +#define STM32_QSPI_FCR_CTEF BIT(0) +#define STM32_QSPI_FCR_CTCF BIT(1) +#define STM32_QSPI_FCR_CSMF BIT(3) +#define STM32_QSPI_FCR_CTOF BIT(4) + +/* + * QUADSPI communication configuration register + */ +#define STM32_QSPI_CCR_DDRM BIT(31) +#define STM32_QSPI_CCR_DHHC BIT(30) +#define STM32_QSPI_CCR_SIOO BIT(28) +#define STM32_QSPI_CCR_FMODE_SHIFT (26) +#define STM32_QSPI_CCR_DMODE_SHIFT (24) +#define STM32_QSPI_CCR_DCYC_SHIFT (18) +#define STM32_QSPI_CCR_DCYC_MASK GENMASK(4, 0) +#define STM32_QSPI_CCR_ABSIZE_SHIFT (16) +#define STM32_QSPI_CCR_ABMODE_SHIFT (14) +#define STM32_QSPI_CCR_ADSIZE_SHIFT (12) +#define STM32_QSPI_CCR_ADMODE_SHIFT (10) +#define STM32_QSPI_CCR_IMODE_SHIFT (8) +#define STM32_QSPI_CCR_INSTRUCTION_MASK GENMASK(7, 0) + +enum STM32_QSPI_CCR_IMODE { + STM32_QSPI_CCR_IMODE_NONE = 0, + STM32_QSPI_CCR_IMODE_ONE_LINE = 1, + STM32_QSPI_CCR_IMODE_TWO_LINE = 2, + STM32_QSPI_CCR_IMODE_FOUR_LINE = 3, +}; + +enum STM32_QSPI_CCR_ADMODE { + STM32_QSPI_CCR_ADMODE_NONE = 0, + STM32_QSPI_CCR_ADMODE_ONE_LINE = 1, + STM32_QSPI_CCR_ADMODE_TWO_LINE = 2, + STM32_QSPI_CCR_ADMODE_FOUR_LINE = 3, +}; + +enum STM32_QSPI_CCR_ADSIZE { + STM32_QSPI_CCR_ADSIZE_8BIT = 0, + STM32_QSPI_CCR_ADSIZE_16BIT = 1, + STM32_QSPI_CCR_ADSIZE_24BIT = 2, + STM32_QSPI_CCR_ADSIZE_32BIT = 3, +}; + +enum STM32_QSPI_CCR_ABMODE { + STM32_QSPI_CCR_ABMODE_NONE = 0, + STM32_QSPI_CCR_ABMODE_ONE_LINE = 1, + STM32_QSPI_CCR_ABMODE_TWO_LINE = 2, + STM32_QSPI_CCR_ABMODE_FOUR_LINE = 3, +}; + +enum STM32_QSPI_CCR_ABSIZE { + STM32_QSPI_CCR_ABSIZE_8BIT = 0, + STM32_QSPI_CCR_ABSIZE_16BIT = 1, + STM32_QSPI_CCR_ABSIZE_24BIT = 2, + STM32_QSPI_CCR_ABSIZE_32BIT = 3, +}; + +enum STM32_QSPI_CCR_DMODE { + STM32_QSPI_CCR_DMODE_NONE = 0, + STM32_QSPI_CCR_DMODE_ONE_LINE = 1, + STM32_QSPI_CCR_DMODE_TWO_LINE = 2, + STM32_QSPI_CCR_DMODE_FOUR_LINE = 3, +}; + +enum STM32_QSPI_CCR_FMODE { + STM32_QSPI_CCR_IND_WRITE = 0, + STM32_QSPI_CCR_IND_READ = 1, + STM32_QSPI_CCR_AUTO_POLL = 2, + STM32_QSPI_CCR_MEM_MAP = 3, +}; + +/* default SCK frequency, unit: HZ */ +#define STM32_QSPI_DEFAULT_SCK_FREQ 108000000 + +struct stm32_qspi_platdata { + u32 base; + u32 memory_map; + u32 max_hz; +}; + +struct stm32_qspi_priv { + struct stm32_qspi_regs *regs; + u32 max_hz; + u32 mode; + + u32 command; + u32 address; + u32 dummycycles; +#define CMD_HAS_ADR BIT(24) +#define CMD_HAS_DUMMY BIT(25) +#define CMD_HAS_DATA BIT(26) +}; + +static void _stm32_qspi_disable(struct stm32_qspi_priv *priv) +{ + clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); +} + +static void _stm32_qspi_enable(struct stm32_qspi_priv *priv) +{ + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); +} + +static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) +{ + while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY) + ; +} + +static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv) +{ + while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_TCF)) + ; +} + +static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) +{ + while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_FTF)) + ; +} + +static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size) +{ + u32 fsize = fls(size) - 1; + clrsetbits_le32(&priv->regs->dcr, + STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT, + fsize << STM32_QSPI_DCR_FSIZE_SHIFT); +} + +static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv) +{ + unsigned int ccr_reg = 0; + u8 imode, admode, dmode; + u32 mode = priv->mode; + u32 cmd = (priv->command & STM32_QSPI_CCR_INSTRUCTION_MASK); + + imode = STM32_QSPI_CCR_IMODE_ONE_LINE; + admode = STM32_QSPI_CCR_ADMODE_ONE_LINE; + + if (mode & SPI_RX_QUAD) { + dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE; + if (mode & SPI_TX_QUAD) { + imode = STM32_QSPI_CCR_IMODE_FOUR_LINE; + admode = STM32_QSPI_CCR_ADMODE_FOUR_LINE; + } + } else if (mode & SPI_RX_DUAL) { + dmode = STM32_QSPI_CCR_DMODE_TWO_LINE; + if (mode & SPI_TX_DUAL) { + imode = STM32_QSPI_CCR_IMODE_TWO_LINE; + admode = STM32_QSPI_CCR_ADMODE_TWO_LINE; + } + } else { + dmode = STM32_QSPI_CCR_DMODE_ONE_LINE; + } + + if (priv->command & CMD_HAS_DATA) + ccr_reg |= (dmode << STM32_QSPI_CCR_DMODE_SHIFT); + + if (priv->command & CMD_HAS_DUMMY) + ccr_reg |= ((priv->dummycycles & STM32_QSPI_CCR_DCYC_MASK) + << STM32_QSPI_CCR_DCYC_SHIFT); + + if (priv->command & CMD_HAS_ADR) { + ccr_reg |= (STM32_QSPI_CCR_ADSIZE_24BIT + << STM32_QSPI_CCR_ADSIZE_SHIFT); + ccr_reg |= (admode << STM32_QSPI_CCR_ADMODE_SHIFT); + } + ccr_reg |= (imode << STM32_QSPI_CCR_IMODE_SHIFT); + ccr_reg |= cmd; + return ccr_reg; +} + +static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv, + struct spi_flash *flash) +{ + priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA + | CMD_HAS_DUMMY; + priv->dummycycles = flash->dummy_byte * 8; + + unsigned int ccr_reg = _stm32_qspi_gen_ccr(priv); + ccr_reg |= (STM32_QSPI_CCR_MEM_MAP << STM32_QSPI_CCR_FMODE_SHIFT); + + _stm32_qspi_wait_for_not_busy(priv); + + writel(ccr_reg, &priv->regs->ccr); + + priv->dummycycles = 0; +} + +static void _stm32_qspi_disable_mmap(struct stm32_qspi_priv *priv) +{ + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); +} + +static void _stm32_qspi_set_xfer_length(struct stm32_qspi_priv *priv, + u32 length) +{ + writel(length - 1, &priv->regs->dlr); +} + +static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg) +{ + writel(cr_reg, &priv->regs->ccr); + + if (priv->command & CMD_HAS_ADR) + writel(priv->address, &priv->regs->ar); +} + +static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, + struct spi_flash *flash, unsigned int bitlen, + const u8 *dout, u8 *din, unsigned long flags) +{ + unsigned int words = bitlen / 8; + + if (flags & SPI_XFER_MMAP) { + _stm32_qspi_enable_mmap(priv, flash); + return 0; + } else if (flags & SPI_XFER_MMAP_END) { + _stm32_qspi_disable_mmap(priv); + return 0; + } + + if (bitlen == 0) + return -1; + + if (bitlen % 8) { + debug("spi_xfer: Non byte aligned SPI transfer\n"); + return -1; + } + + if (dout && din) { + debug("spi_xfer: QSPI cannot have data in and data out set\n"); + return -1; + } + + if (!dout && (flags & SPI_XFER_BEGIN)) { + debug("spi_xfer: QSPI transfer must begin with command\n"); + return -1; + } + + if (dout) { + if (flags & SPI_XFER_BEGIN) { + /* data is command */ + priv->command = dout[0] | CMD_HAS_DATA; + if (words >= 4) { + /* address is here too */ + priv->address = (dout[1] << 16) | + (dout[2] << 8) | dout[3]; + priv->command |= CMD_HAS_ADR; + } + + if (words > 4) { + /* rest is dummy bytes */ + priv->dummycycles = (words - 4) * 8; + priv->command |= CMD_HAS_DUMMY; + } + + if (flags & SPI_XFER_END) { + /* command without data */ + priv->command &= ~(CMD_HAS_DATA); + } + } + + if (flags & SPI_XFER_END) { + u32 ccr_reg = _stm32_qspi_gen_ccr(priv); + ccr_reg |= STM32_QSPI_CCR_IND_WRITE + << STM32_QSPI_CCR_FMODE_SHIFT; + + _stm32_qspi_wait_for_not_busy(priv); + + if (priv->command & CMD_HAS_DATA) + _stm32_qspi_set_xfer_length(priv, words); + + _stm32_qspi_start_xfer(priv, ccr_reg); + + debug("%s: write: ccr:0x%08x adr:0x%08x\n", + __func__, priv->regs->ccr, priv->regs->ar); + + if (priv->command & CMD_HAS_DATA) { + _stm32_qspi_wait_for_ftf(priv); + + debug("%s: words:%d data:", __func__, words); + + int i = 0; + while (words > i) { + writeb(dout[i], &priv->regs->dr); + debug("%02x ", dout[i]); + i++; + } + debug("\n"); + + _stm32_qspi_wait_for_complete(priv); + } else { + _stm32_qspi_wait_for_not_busy(priv); + } + } + } else if (din) { + u32 ccr_reg = _stm32_qspi_gen_ccr(priv); + ccr_reg |= STM32_QSPI_CCR_IND_READ + << STM32_QSPI_CCR_FMODE_SHIFT; + + _stm32_qspi_wait_for_not_busy(priv); + + _stm32_qspi_set_xfer_length(priv, words); + + _stm32_qspi_start_xfer(priv, ccr_reg); + + debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__, + priv->regs->ccr, priv->regs->ar, priv->regs->dlr); + + debug("%s: data:", __func__); + + int i = 0; + while (words > i) { + din[i] = readb(&priv->regs->dr); + debug("%02x ", din[i]); + i++; + } + debug("\n"); + } + + return 0; +} + +static int stm32_qspi_ofdata_to_platdata(struct udevice *bus) +{ + struct fdt_resource res_regs, res_mem; + struct stm32_qspi_platdata *plat = bus->platdata; + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + int ret; + + ret = fdt_get_named_resource(blob, node, "reg", "reg-names", + "QuadSPI", &res_regs); + if (ret) { + debug("Error: can't get regs base addresses(ret = %d)!\n", ret); + return -ENOMEM; + } + ret = fdt_get_named_resource(blob, node, "reg", "reg-names", + "QuadSPI-memory", &res_mem); + if (ret) { + debug("Error: can't get mmap base address(ret = %d)!\n", ret); + return -ENOMEM; + } + + plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", + STM32_QSPI_DEFAULT_SCK_FREQ); + + plat->base = res_regs.start; + plat->memory_map = res_mem.start; + + debug("%s: regs=<0x%x> mapped=<0x%x>, max-frequency=%d\n", + __func__, + plat->base, + plat->memory_map, + plat->max_hz + ); + + return 0; +} + +static int stm32_qspi_probe(struct udevice *bus) +{ + struct stm32_qspi_platdata *plat = dev_get_platdata(bus); + struct stm32_qspi_priv *priv = dev_get_priv(bus); + struct dm_spi_bus *dm_spi_bus; + + dm_spi_bus = bus->uclass_priv; + + dm_spi_bus->max_hz = plat->max_hz; + + priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base; + + priv->max_hz = plat->max_hz; + + clock_setup(QSPI_CLOCK_CFG); + + setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT); + + return 0; +} + +static int stm32_qspi_remove(struct udevice *bus) +{ + return 0; +} + +static int stm32_qspi_claim_bus(struct udevice *dev) +{ + struct stm32_qspi_priv *priv; + struct udevice *bus; + struct spi_flash *flash; + + bus = dev->parent; + priv = dev_get_priv(bus); + flash = dev_get_uclass_priv(dev); + + _stm32_qspi_set_flash_size(priv, flash->size); + + _stm32_qspi_enable(priv); + + return 0; +} + +static int stm32_qspi_release_bus(struct udevice *dev) +{ + struct stm32_qspi_priv *priv; + struct udevice *bus; + + bus = dev->parent; + priv = dev_get_priv(bus); + + _stm32_qspi_disable(priv); + + return 0; +} + +static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct stm32_qspi_priv *priv; + struct udevice *bus; + struct spi_flash *flash; + + bus = dev->parent; + priv = dev_get_priv(bus); + flash = dev_get_uclass_priv(dev); + + return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout, + (u8 *)din, flags); +} + +static int stm32_qspi_set_speed(struct udevice *bus, uint speed) +{ + struct stm32_qspi_platdata *plat = bus->platdata; + struct stm32_qspi_priv *priv = dev_get_priv(bus); + + if (speed > plat->max_hz) + speed = plat->max_hz; + + u32 qspi_clk = clock_get(CLOCK_AHB); + u32 prescaler = 255; + if (speed > 0) { + prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; + if (prescaler > 255) + prescaler = 255; + else if (prescaler < 0) + prescaler = 0; + } + + u32 csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); + csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK; + + _stm32_qspi_wait_for_not_busy(priv); + + clrsetbits_le32(&priv->regs->cr, + STM32_QSPI_CR_PRESCALER_MASK << + STM32_QSPI_CR_PRESCALER_SHIFT, + prescaler << STM32_QSPI_CR_PRESCALER_SHIFT); + + + clrsetbits_le32(&priv->regs->dcr, + STM32_QSPI_DCR_CSHT_MASK << STM32_QSPI_DCR_CSHT_SHIFT, + csht << STM32_QSPI_DCR_CSHT_SHIFT); + + debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, + (qspi_clk / (prescaler + 1))); + + return 0; +} + +static int stm32_qspi_set_mode(struct udevice *bus, uint mode) +{ + struct stm32_qspi_priv *priv = dev_get_priv(bus); + + _stm32_qspi_wait_for_not_busy(priv); + + if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) + setbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); + else if (!(mode & SPI_CPHA) && !(mode & SPI_CPOL)) + clrbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); + else + return -ENODEV; + + if (mode & SPI_CS_HIGH) + return -ENODEV; + + if (mode & SPI_RX_QUAD) + priv->mode |= SPI_RX_QUAD; + else if (mode & SPI_RX_DUAL) + priv->mode |= SPI_RX_DUAL; + else + priv->mode &= ~(SPI_RX_QUAD | SPI_RX_DUAL); + + if (mode & SPI_TX_QUAD) + priv->mode |= SPI_TX_QUAD; + else if (mode & SPI_TX_DUAL) + priv->mode |= SPI_TX_DUAL; + else + priv->mode &= ~(SPI_TX_QUAD | SPI_TX_DUAL); + + debug("%s: regs=%p, mode=%d rx: ", __func__, priv->regs, mode); + + if (mode & SPI_RX_QUAD) + debug("quad, tx: "); + else if (mode & SPI_RX_DUAL) + debug("dual, tx: "); + else + debug("single, tx: "); + + if (mode & SPI_TX_QUAD) + debug("quad\n"); + else if (mode & SPI_TX_DUAL) + debug("dual\n"); + else + debug("single\n"); + + return 0; +} + +static const struct dm_spi_ops stm32_qspi_ops = { + .claim_bus = stm32_qspi_claim_bus, + .release_bus = stm32_qspi_release_bus, + .xfer = stm32_qspi_xfer, + .set_speed = stm32_qspi_set_speed, + .set_mode = stm32_qspi_set_mode, +}; + +static const struct udevice_id stm32_qspi_ids[] = { + { .compatible = "st,stm32-qspi" }, + { } +}; + +U_BOOT_DRIVER(stm32_qspi) = { + .name = "stm32_qspi", + .id = UCLASS_SPI, + .of_match = stm32_qspi_ids, + .ops = &stm32_qspi_ops, + .ofdata_to_platdata = stm32_qspi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct stm32_qspi_platdata), + .priv_auto_alloc_size = sizeof(struct stm32_qspi_priv), + .probe = stm32_qspi_probe, + .remove = stm32_qspi_remove, +}; diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index fa75cc52de..37638a8eea 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_ROCKCHIP_RK3399) += sysreset_rk3399.o obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o obj-$(CONFIG_ARCH_SNAPDRAGON) += sysreset_snapdragon.o obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o +obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o diff --git a/drivers/sysreset/sysreset_ast.c b/drivers/sysreset/sysreset_ast.c new file mode 100644 index 0000000000..a0ab12851d --- /dev/null +++ b/drivers/sysreset/sysreset_ast.c @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <asm/io.h> +#include <asm/arch/wdt.h> +#include <linux/err.h> + +/* Number of Watchdog Timer ticks before reset */ +#define AST_WDT_RESET_TIMEOUT 10 +#define AST_WDT_FOR_RESET 0 + +static int ast_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct ast_wdt *wdt = ast_get_wdt(AST_WDT_FOR_RESET); + u32 reset_mode = 0; + + if (IS_ERR(wdt)) + return PTR_ERR(wdt); + + switch (type) { + case SYSRESET_WARM: + reset_mode = WDT_CTRL_RESET_CPU; + break; + case SYSRESET_COLD: + reset_mode = WDT_CTRL_RESET_CHIP; + break; + default: + return -EPROTONOSUPPORT; + } + + /* Clear reset mode bits */ + clrsetbits_le32(&wdt->ctrl, + (WDT_CTRL_RESET_MODE_MASK << WDT_CTRL_RESET_MODE_SHIFT), + (reset_mode << WDT_CTRL_RESET_MODE_SHIFT)); + wdt_start(wdt, AST_WDT_RESET_TIMEOUT); + + return -EINPROGRESS; +} + +static struct sysreset_ops ast_sysreset = { + .request = ast_sysreset_request, +}; + +U_BOOT_DRIVER(sysreset_ast) = { + .name = "ast_sysreset", + .id = UCLASS_SYSRESET, + .ops = &ast_sysreset, +}; diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index cb18f12fc9..cd38a6d4bd 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -46,4 +46,16 @@ config OMAP_TIMER help Select this to enable an timer for Omap devices. +config AST_TIMER + bool "Aspeed ast2400/ast2500 timer support" + depends on TIMER + default y if ARCH_ASPEED + help + Select this to enable timer for Aspeed ast2400/ast2500 devices. + This is a simple sys timer driver, it is compatible with lib/time.c, + but does not support any interrupts. Even though SoC has 8 hardware + counters, they are all treated as a single device by this driver. + This is mostly because they all share several registers which + makes it difficult to completely separate them. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index f351fbb4e0..a4b1a486b0 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o 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 diff --git a/drivers/timer/ast_timer.c b/drivers/timer/ast_timer.c new file mode 100644 index 0000000000..d7c5460cd3 --- /dev/null +++ b/drivers/timer/ast_timer.c @@ -0,0 +1,97 @@ +/* + * Copyright 2016 Google Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <timer.h> +#include <asm/io.h> +#include <asm/arch/timer.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define AST_TICK_TIMER 1 +#define AST_TMC_RELOAD_VAL 0xffffffff + +struct ast_timer_priv { + struct ast_timer *regs; + struct ast_timer_counter *tmc; +}; + +static struct ast_timer_counter *ast_get_timer_counter(struct ast_timer *timer, + int n) +{ + if (n > 3) + return &timer->timers2[n - 4]; + else + return &timer->timers1[n - 1]; +} + +static int ast_timer_probe(struct udevice *dev) +{ + struct ast_timer_priv *priv = dev_get_priv(dev); + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + writel(AST_TMC_RELOAD_VAL, &priv->tmc->reload_val); + + /* + * Stop the timer. This will also load reload_val into + * the status register. + */ + clrbits_le32(&priv->regs->ctrl1, + AST_TMC_EN << AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER)); + /* Start the timer from the fixed 1MHz clock. */ + setbits_le32(&priv->regs->ctrl1, + (AST_TMC_EN | AST_TMC_1MHZ) << + AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER)); + + uc_priv->clock_rate = AST_TMC_RATE; + + return 0; +} + +static int ast_timer_get_count(struct udevice *dev, u64 *count) +{ + struct ast_timer_priv *priv = dev_get_priv(dev); + + *count = AST_TMC_RELOAD_VAL - readl(&priv->tmc->status); + + return 0; +} + +static int ast_timer_ofdata_to_platdata(struct udevice *dev) +{ + struct ast_timer_priv *priv = dev_get_priv(dev); + + priv->regs = dev_get_addr_ptr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + priv->tmc = ast_get_timer_counter(priv->regs, AST_TICK_TIMER); + + return 0; +} + +static const struct timer_ops ast_timer_ops = { + .get_count = ast_timer_get_count, +}; + +static const struct udevice_id ast_timer_ids[] = { + { .compatible = "aspeed,ast2500-timer" }, + { .compatible = "aspeed,ast2400-timer" }, + { } +}; + +U_BOOT_DRIVER(ast_timer) = { + .name = "ast_timer", + .id = UCLASS_TIMER, + .of_match = ast_timer_ids, + .probe = ast_timer_probe, + .priv_auto_alloc_size = sizeof(struct ast_timer_priv), + .ofdata_to_platdata = ast_timer_ofdata_to_platdata, + .ops = &ast_timer_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 7ab34ce863..3490ee0c3b 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -82,4 +82,10 @@ config TPM_ST33ZP24_SPI to the device using the standard TPM Interface Specification (TIS) protocol +config TPM_FLUSH_RESOURCES + bool "Enable TPM resource flushing support" + depends on TPM + help + Enable support to flush specific resources (e.g. keys) from the TPM. + The functionality is available via the 'tpm' command as well. endmenu |