summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/ata/dwc_ahci.c23
-rw-r--r--drivers/bootcount/Kconfig1
-rw-r--r--drivers/clk/Kconfig8
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/at91/Kconfig8
-rw-r--r--drivers/clk/at91/Makefile3
-rw-r--r--drivers/clk/at91/clk-plladiv.c88
-rw-r--r--drivers/clk/at91/clk-system.c26
-rw-r--r--drivers/clk/at91/clk-usb.c146
-rw-r--r--drivers/clk/clk-uclass.c59
-rw-r--r--drivers/clk/clk_sandbox_test.c29
-rw-r--r--drivers/clk/clk_stm32f.c404
-rw-r--r--drivers/clk/clk_stm32h7.c109
-rw-r--r--drivers/clk/clk_stm32mp1.c1777
-rw-r--r--drivers/clk/clk_zynq.c2
-rw-r--r--drivers/clk/clk_zynqmp.c76
-rw-r--r--drivers/clk/renesas/r8a7790-cpg-mssr.c10
-rw-r--r--drivers/clk/rockchip/clk_rk3036.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3188.c4
-rw-r--r--drivers/clk/rockchip/clk_rk322x.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3288.c2
-rw-r--r--drivers/clk/rockchip/clk_rk3328.c2
-rw-r--r--drivers/clk/rockchip/clk_rv1108.c2
-rw-r--r--drivers/core/fdtaddr.c17
-rw-r--r--drivers/core/ofnode.c5
-rw-r--r--drivers/core/root.c16
-rw-r--r--drivers/core/uclass.c26
-rw-r--r--drivers/cpu/bmips_cpu.c51
-rw-r--r--drivers/fpga/fpga.c21
-rw-r--r--drivers/fpga/zynqmppl.c28
-rw-r--r--drivers/fpga/zynqpl.c16
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/gpio-uclass.c2
-rw-r--r--drivers/gpio/omap_gpio.c1
-rw-r--r--drivers/gpio/stm32f7_gpio.c15
-rw-r--r--drivers/gpio/sunxi_gpio.c3
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/fsl_i2c.c13
-rw-r--r--drivers/i2c/i2c-uclass.c118
-rw-r--r--drivers/i2c/ihs_i2c.c45
-rw-r--r--drivers/i2c/imx_lpi2c.c10
-rw-r--r--drivers/i2c/soft_i2c.c3
-rw-r--r--drivers/i2c/stm32f7_i2c.c4
-rw-r--r--drivers/input/Makefile4
-rw-r--r--drivers/input/keyboard.c87
-rw-r--r--drivers/input/pc_keyb.c251
-rw-r--r--drivers/input/ps2mult.c461
-rw-r--r--drivers/input/ps2ser.c147
-rw-r--r--drivers/mmc/Kconfig35
-rw-r--r--drivers/mmc/Makefile4
-rw-r--r--drivers/mmc/bcm2835_sdhci.c2
-rw-r--r--drivers/mmc/bcm2835_sdhost.c3
-rw-r--r--drivers/mmc/ftsdc010_mci.c219
-rw-r--r--drivers/mmc/ftsdc010_mci.h15
-rw-r--r--drivers/mmc/nds32_mmc.c136
-rw-r--r--drivers/mmc/pci_mmc.c5
-rw-r--r--drivers/mmc/renesas-sdhi.c368
-rw-r--r--drivers/mmc/rockchip_sdhci.c8
-rw-r--r--drivers/mmc/stm32_sdmmc2.c10
-rw-r--r--drivers/mmc/sunxi_mmc.c10
-rw-r--r--drivers/mmc/tmio-common.c787
-rw-r--r--drivers/mmc/tmio-common.h151
-rw-r--r--drivers/mmc/uniphier-sd.c850
-rw-r--r--drivers/mtd/Kconfig7
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/nand/Kconfig26
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/arasan_nfc.c7
-rw-r--r--drivers/mtd/nand/nand_ecc.c16
-rw-r--r--drivers/mtd/nand/ndfc.c200
-rw-r--r--drivers/mtd/nand/sunxi_nand.c8
-rw-r--r--drivers/mtd/nand/sunxi_nand_spl.c236
-rw-r--r--drivers/mtd/renesas_rpc_hf.c398
-rw-r--r--drivers/mtd/spi/Kconfig13
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/spi_flash.c2
-rw-r--r--drivers/mtd/spi/sunxi_spi_spl.c312
-rw-r--r--drivers/mtd/stm32_flash.c2
-rw-r--r--drivers/mtd/ubi/Kconfig7
-rw-r--r--drivers/net/Kconfig30
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/cpsw-common.c1
-rw-r--r--drivers/net/cpsw.c2
-rw-r--r--drivers/net/enc28j60.c959
-rw-r--r--drivers/net/enc28j60.h238
-rw-r--r--drivers/net/fec_mxc.c56
-rw-r--r--drivers/net/fsl_mcdmafec.c1
-rw-r--r--drivers/net/macb.c2
-rw-r--r--drivers/net/mcffec.c1
-rw-r--r--drivers/net/mpc8xx_fec.c2
-rw-r--r--drivers/net/mvneta.c10
-rw-r--r--drivers/net/mvpp2.c4
-rw-r--r--drivers/net/ne2000_base.c1
-rw-r--r--drivers/net/pfe_eth/Kconfig12
-rw-r--r--drivers/net/pfe_eth/Makefile12
-rw-r--r--drivers/net/pfe_eth/pfe_cmd.c497
-rw-r--r--drivers/net/pfe_eth/pfe_driver.c643
-rw-r--r--drivers/net/pfe_eth/pfe_eth.c297
-rw-r--r--drivers/net/pfe_eth/pfe_firmware.c230
-rw-r--r--drivers/net/pfe_eth/pfe_hw.c999
-rw-r--r--drivers/net/pfe_eth/pfe_mdio.c291
-rw-r--r--drivers/net/phy/Kconfig25
-rw-r--r--drivers/net/phy/aquantia.c1
-rw-r--r--drivers/net/phy/cortina.c59
-rw-r--r--drivers/net/phy/realtek.c34
-rw-r--r--drivers/net/phy/xilinx_phy.c2
-rw-r--r--drivers/net/sh_eth.c4
-rw-r--r--drivers/net/sun8i_emac.c91
-rw-r--r--drivers/net/xilinx_axi_emac.c33
-rw-r--r--drivers/net/zynq_gem.c12
-rw-r--r--drivers/pci/Kconfig10
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/pci-aardvark.c690
-rw-r--r--drivers/pci/pci-uclass.c8
-rw-r--r--drivers/pci/pcie_dw_mvebu.c91
-rw-r--r--drivers/phy/Kconfig33
-rw-r--r--drivers/phy/Makefile5
-rw-r--r--drivers/phy/bcm6318-usbh-phy.c144
-rw-r--r--drivers/phy/bcm6348-usbh-phy.c94
-rw-r--r--drivers/phy/bcm6358-usbh-phy.c94
-rw-r--r--drivers/phy/bcm6368-usbh-phy.c196
-rw-r--r--drivers/phy/meson-gxl-usb2.c238
-rw-r--r--drivers/phy/meson-gxl-usb3.c201
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-37xx.c52
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c19
-rw-r--r--drivers/pinctrl/pinctrl_stm32.c9
-rw-r--r--drivers/pinctrl/rockchip/pinctrl_rk3036.c410
-rw-r--r--drivers/pinctrl/rockchip/pinctrl_rk3188.c380
-rw-r--r--drivers/pinctrl/rockchip/pinctrl_rk3399.c61
-rw-r--r--drivers/power/Kconfig5
-rw-r--r--drivers/power/pmic/Kconfig8
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/stpmu1.c62
-rw-r--r--drivers/power/regulator/pbias_regulator.c6
-rw-r--r--drivers/pwm/rk_pwm.c2
-rw-r--r--drivers/ram/Kconfig2
-rw-r--r--drivers/ram/Makefile1
-rw-r--r--drivers/ram/rockchip/sdram_rk3399.c1
-rw-r--r--drivers/ram/stm32mp1/Kconfig12
-rw-r--r--drivers/ram/stm32mp1/Makefile8
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.c496
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.h210
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr_regs.h365
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ram.c197
-rw-r--r--drivers/reset/Kconfig10
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-meson.c90
-rw-r--r--drivers/reset/reset-uclass.c60
-rw-r--r--drivers/reset/sandbox-reset-test.c29
-rw-r--r--drivers/reset/sandbox-reset.c2
-rw-r--r--drivers/reset/stm32-reset.c36
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/ds1307.c33
-rw-r--r--drivers/rtc/ds1374.c15
-rw-r--r--drivers/rtc/isl1208.c141
-rw-r--r--drivers/rtc/mx27rtc.c6
-rw-r--r--drivers/rtc/rs5c372.c24
-rw-r--r--drivers/rtc/rx8025.c18
-rw-r--r--drivers/serial/Kconfig56
-rw-r--r--drivers/serial/Makefile20
-rw-r--r--drivers/serial/serial.c64
-rw-r--r--drivers/serial/serial_meson.c1
-rw-r--r--drivers/serial/serial_mpc8xx.c2
-rw-r--r--drivers/serial/serial_sh.c2
-rw-r--r--drivers/spi/Kconfig26
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atcspi200_spi.c87
-rw-r--r--drivers/spi/atmel_spi.c14
-rw-r--r--drivers/spi/designware_spi.c130
-rw-r--r--drivers/spi/mpc8xx_spi.c2
-rw-r--r--drivers/spi/omap3_spi.c31
-rw-r--r--drivers/spi/renesas_rpc_spi.c465
-rw-r--r--drivers/spi/sh_qspi.c119
-rw-r--r--drivers/spi/stm32_qspi.c1
-rw-r--r--drivers/sysreset/sysreset_syscon.c8
-rw-r--r--drivers/timer/Kconfig7
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/stm32_timer.c138
-rw-r--r--drivers/usb/eth/Kconfig2
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/ether.c1
-rw-r--r--drivers/usb/gadget/f_rockusb.c1
-rw-r--r--drivers/usb/host/Kconfig19
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/dwc2.c62
-rw-r--r--drivers/usb/host/dwc3-of-simple.c109
-rw-r--r--drivers/usb/host/ehci-generic.c98
-rw-r--r--drivers/usb/host/ehci-ppc4xx.c35
-rw-r--r--drivers/usb/host/ohci-generic.c95
-rw-r--r--drivers/usb/host/xhci-dwc3.c113
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/cfb_console.c2
-rw-r--r--drivers/video/da8xx-fb.c5
-rw-r--r--drivers/video/exynos/exynos_dp.c12
-rw-r--r--drivers/video/pwm_backlight.c24
-rw-r--r--drivers/video/rockchip/rk3288_mipi.c2
-rw-r--r--drivers/video/rockchip/rk3399_mipi.c2
-rw-r--r--drivers/video/stb_truetype.h2
-rw-r--r--drivers/video/stm32/stm32_ltdc.c117
-rw-r--r--drivers/video/sunxi/sunxi_display.c8
-rw-r--r--drivers/video/vidconsole-uclass.c88
-rw-r--r--drivers/video/video-uclass.c38
-rw-r--r--drivers/watchdog/Kconfig22
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/cdns_wdt.c276
-rw-r--r--drivers/watchdog/mpc8xx_wdt.c21
-rw-r--r--drivers/watchdog/omap_wdt.c21
208 files changed, 14467 insertions, 5003 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 2673428cb6..6846d181aa 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/
obj-$(CONFIG_ALTERA_SDRAM) += ddr/altera/
obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/
obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/
+obj-$(CONFIG_SPL_RESET_SUPPORT) += reset/
obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/
obj-$(CONFIG_SPL_ONENAND_SUPPORT) += mtd/onenand/
obj-$(CONFIG_SPL_UBI) += mtd/ubispl/
diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c
index 029b7784f6..6c7371e3ed 100644
--- a/drivers/ata/dwc_ahci.c
+++ b/drivers/ata/dwc_ahci.c
@@ -25,17 +25,18 @@ struct dwc_ahci_priv {
void *wrapper_base;
};
+static int dwc_ahci_bind(struct udevice *dev)
+{
+ struct udevice *scsi_dev;
+
+ return ahci_bind_scsi(dev, &scsi_dev);
+}
+
static int dwc_ahci_ofdata_to_platdata(struct udevice *dev)
{
struct dwc_ahci_priv *priv = dev_get_priv(dev);
- struct scsi_platdata *plat = dev_get_uclass_platdata(dev);
fdt_addr_t addr;
- plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
- "max-id", CONFIG_SYS_SCSI_MAX_SCSI_ID);
- plat->max_lun = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
- "max-lun", CONFIG_SYS_SCSI_MAX_LUN);
-
priv->base = map_physmem(devfdt_get_addr(dev), sizeof(void *),
MAP_NOCACHE);
@@ -81,11 +82,7 @@ static int dwc_ahci_probe(struct udevice *dev)
writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG);
}
- ret = ahci_init_dm(dev, priv->base);
- if (ret)
- return ret;
-
- return ahci_start_ports_dm(dev);
+ return ahci_probe_scsi(dev, (ulong)priv->base);
}
static const struct udevice_id dwc_ahci_ids[] = {
@@ -95,11 +92,11 @@ static const struct udevice_id dwc_ahci_ids[] = {
U_BOOT_DRIVER(dwc_ahci) = {
.name = "dwc_ahci",
- .id = UCLASS_SCSI,
+ .id = UCLASS_AHCI,
.of_match = dwc_ahci_ids,
+ .bind = dwc_ahci_bind,
.ofdata_to_platdata = dwc_ahci_ofdata_to_platdata,
.ops = &scsi_ops,
.probe = dwc_ahci_probe,
.priv_auto_alloc_size = sizeof(struct dwc_ahci_priv),
- .flags = DM_FLAG_ALLOC_PRIV_DMA,
};
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 73972b7f9c..d335ed14b9 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -34,6 +34,7 @@ config BOOTCOUNT_EXT
config BOOTCOUNT_AM33XX
bool "Boot counter in AM33XX RTC IP block"
depends on AM33XX || SOC_DA8XX
+ select SPL_AM33XX_ENABLE_RTC32K_OSC if AM33XX
help
A bootcount driver for the RTC IP block found on many TI platforms.
This requires the RTC clocks, etc, to be enabled prior to use and
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index cdfa052c16..c382e8865f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -75,6 +75,14 @@ config CLK_ZYNQMP
This clock driver adds support for clock realted settings for
ZynqMP platform.
+config CLK_STM32MP1
+ bool "Enable RCC clock driver for STM32MP1"
+ depends on ARCH_STM32MP && CLK
+ default y
+ help
+ Enable the STM32 clock (RCC) driver. Enable support for
+ manipulating STM32MP1's on-SoC clocks.
+
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/exynos/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index dab106ab7f..e05c607223 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_CLK_EXYNOS) += exynos/
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
obj-$(CONFIG_CLK_RENESAS) += renesas/
obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
+obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o
obj-$(CONFIG_CLK_ZYNQMP) += clk_zynqmp.o
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig
index fd56f200b9..8d482a2752 100644
--- a/drivers/clk/at91/Kconfig
+++ b/drivers/clk/at91/Kconfig
@@ -27,6 +27,14 @@ config AT91_UTMI
fast crystal oscillator to meet the frequency accuracy
required by USB.
+config AT91_USB_CLK
+ bool "Support USB OHCI Input Clock"
+ depends on CLK_AT91
+ help
+ This option is used to enable the USB Input Clock, from
+ the device tree, configure the USBS bit (PLLA or UTMI PLL)
+ and USBDIV field of the PMC_USB register.
+
config AT91_H32MX
bool "Support H32MX 32-bit Matrix Clock"
depends on CLK_AT91
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index fbe3cb6581..8c197ff949 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,9 +3,10 @@
#
obj-y += pmc.o sckc.o
-obj-y += clk-slow.o clk-main.o clk-plla.o clk-master.o
+obj-y += clk-slow.o clk-main.o clk-plla.o clk-plladiv.o clk-master.o
obj-y += clk-system.o clk-peripheral.o
obj-$(CONFIG_AT91_UTMI) += clk-utmi.o
+obj-$(CONFIG_AT91_USB_CLK) += clk-usb.o
obj-$(CONFIG_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generated.o
diff --git a/drivers/clk/at91/clk-plladiv.c b/drivers/clk/at91/clk-plladiv.c
new file mode 100644
index 0000000000..0599d2893b
--- /dev/null
+++ b/drivers/clk/at91/clk-plladiv.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 Microhip / Atmel Corporation
+ * Wenyou.Yang <wenyou.yang@microchip.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/io.h>
+#include <mach/at91_pmc.h>
+#include "pmc.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int at91_plladiv_clk_enable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong at91_plladiv_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &source);
+ if (ret)
+ return -EINVAL;
+
+ clk_rate = clk_get_rate(&source);
+ if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2)
+ clk_rate /= 2;
+
+ return clk_rate;
+}
+
+static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ ulong parent_rate;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &source);
+ if (ret)
+ return -EINVAL;
+
+ parent_rate = clk_get_rate(&source);
+ if ((parent_rate != rate) && ((parent_rate) / 2 != rate))
+ return -EINVAL;
+
+ if (parent_rate != rate) {
+ writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2),
+ &pmc->mckr);
+ }
+
+ return 0;
+}
+
+static struct clk_ops at91_plladiv_clk_ops = {
+ .enable = at91_plladiv_clk_enable,
+ .get_rate = at91_plladiv_clk_get_rate,
+ .set_rate = at91_plladiv_clk_set_rate,
+};
+
+static int at91_plladiv_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id at91_plladiv_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-plldiv" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_plladiv_clk) = {
+ .name = "at91-plladiv-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_plladiv_clk_match,
+ .probe = at91_plladiv_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &at91_plladiv_clk_ops,
+};
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 24b271aa18..81fe47a9d7 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -44,6 +44,30 @@ static inline int is_pck(int id)
return (id >= 8) && (id <= 15);
}
+static ulong system_clk_get_rate(struct clk *clk)
+{
+ struct clk clk_dev;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (ret)
+ return -EINVAL;
+
+ return clk_get_rate(&clk_dev);
+}
+
+static ulong system_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk clk_dev;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (ret)
+ return -EINVAL;
+
+ return clk_set_rate(&clk_dev, rate);
+}
+
static int system_clk_enable(struct clk *clk)
{
struct pmc_platdata *plat = dev_get_platdata(clk->dev);
@@ -73,6 +97,8 @@ static int system_clk_enable(struct clk *clk)
static struct clk_ops system_clk_ops = {
.of_xlate = at91_clk_of_xlate,
+ .get_rate = system_clk_get_rate,
+ .set_rate = system_clk_set_rate,
.enable = system_clk_enable,
};
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
new file mode 100644
index 0000000000..36622c09dc
--- /dev/null
+++ b/drivers/clk/at91/clk-usb.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 Microhip / Atmel Corporation
+ * Wenyou.Yang <wenyou.yang@microchip.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/io.h>
+#include <mach/at91_pmc.h>
+#include "pmc.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define AT91_USB_CLK_SOURCE_MAX 2
+#define AT91_USB_CLK_MAX_DIV 15
+
+struct at91_usb_clk_priv {
+ u32 num_clksource;
+};
+
+static ulong at91_usb_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ u32 tmp, usbdiv;
+ u8 source_index;
+ int ret;
+
+ tmp = readl(&pmc->pcr);
+ source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) &
+ AT91_PMC_USB_USBS_MASK;
+ usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK;
+
+ ret = clk_get_by_index(clk->dev, source_index, &source);
+ if (ret)
+ return 0;
+
+ return clk_get_rate(&source) / (usbdiv + 1);
+}
+
+static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev);
+ struct clk source, best_source;
+ ulong tmp_rate, best_rate = rate, source_rate;
+ int tmp_diff, best_diff = -1;
+ u32 div, best_div = 0;
+ u8 best_source_index = 0;
+ u8 i;
+ u32 tmp;
+ int ret;
+
+ for (i = 0; i < priv->num_clksource; i++) {
+ ret = clk_get_by_index(clk->dev, i, &source);
+ if (ret)
+ return ret;
+
+ source_rate = clk_get_rate(&source);
+ if (IS_ERR_VALUE(source_rate))
+ return source_rate;
+
+ for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) {
+ tmp_rate = DIV_ROUND_CLOSEST(source_rate, div);
+ tmp_diff = abs(rate - tmp_rate);
+
+ if (best_diff < 0 || best_diff > tmp_diff) {
+ best_rate = tmp_rate;
+ best_diff = tmp_diff;
+
+ best_div = div - 1;
+ best_source = source;
+ best_source_index = i;
+ }
+
+ if (!best_diff || tmp_rate < rate)
+ break;
+ }
+
+ if (!best_diff)
+ break;
+ }
+
+ debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n",
+ best_source.dev->name, best_rate, best_div);
+
+ ret = clk_enable(&best_source);
+ if (ret)
+ return ret;
+
+ tmp = AT91_PMC_USB_USBS_(best_source_index) |
+ AT91_PMC_USB_DIV_(best_div);
+ writel(tmp, &pmc->usb);
+
+ return 0;
+}
+
+static struct clk_ops at91_usb_clk_ops = {
+ .get_rate = at91_usb_clk_get_rate,
+ .set_rate = at91_usb_clk_set_rate,
+};
+
+static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct at91_usb_clk_priv *priv = dev_get_priv(dev);
+ u32 cells[AT91_USB_CLK_SOURCE_MAX];
+ u32 num_clksource;
+
+ num_clksource = fdtdec_get_int_array_count(gd->fdt_blob,
+ dev_of_offset(dev),
+ "clocks", cells,
+ AT91_USB_CLK_SOURCE_MAX);
+
+ if (!num_clksource)
+ return -1;
+
+ priv->num_clksource = num_clksource;
+
+ return 0;
+}
+
+static int at91_usb_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id at91_usb_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-usb" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_usb_clk) = {
+ .name = "at91-usb-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_usb_clk_match,
+ .probe = at91_usb_clk_probe,
+ .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &at91_usb_clk_ops,
+};
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index ad763795d9..6e99b3b15d 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -104,6 +104,39 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
return clk_get_by_indexed_prop(dev, "clocks", index, clk);
}
+int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
+{
+ int i, ret, err, count;
+
+ bulk->count = 0;
+
+ count = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
+ if (!count)
+ return 0;
+
+ bulk->clks = devm_kcalloc(dev, count, sizeof(struct clk), GFP_KERNEL);
+ if (!bulk->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ ret = clk_get_by_index(dev, i, &bulk->clks[i]);
+ if (ret < 0)
+ goto bulk_get_err;
+
+ ++bulk->count;
+ }
+
+ return 0;
+
+bulk_get_err:
+ err = clk_release_all(bulk->clks, bulk->count);
+ if (err)
+ debug("%s: could release all clocks for %p\n",
+ __func__, dev);
+
+ return ret;
+}
+
static int clk_set_default_parents(struct udevice *dev)
{
struct clk clk, parent_clk;
@@ -336,6 +369,19 @@ int clk_enable(struct clk *clk)
return ops->enable(clk);
}
+int clk_enable_bulk(struct clk_bulk *bulk)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = clk_enable(&bulk->clks[i]);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
int clk_disable(struct clk *clk)
{
const struct clk_ops *ops = clk_dev_ops(clk->dev);
@@ -348,6 +394,19 @@ int clk_disable(struct clk *clk)
return ops->disable(clk);
}
+int clk_disable_bulk(struct clk_bulk *bulk)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = clk_disable(&bulk->clks[i]);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
UCLASS_DRIVER(clk) = {
.id = UCLASS_CLK,
.name = "clk",
diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c
index 999100de9d..d0898815b3 100644
--- a/drivers/clk/clk_sandbox_test.c
+++ b/drivers/clk/clk_sandbox_test.c
@@ -11,6 +11,7 @@
struct sandbox_clk_test {
struct clk clks[SANDBOX_CLK_TEST_ID_COUNT];
+ struct clk_bulk bulk;
};
static const char * const sandbox_clk_test_names[] = {
@@ -34,6 +35,13 @@ int sandbox_clk_test_get(struct udevice *dev)
return 0;
}
+int sandbox_clk_test_get_bulk(struct udevice *dev)
+{
+ struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+ return clk_get_bulk(dev, &sbct->bulk);
+}
+
ulong sandbox_clk_test_get_rate(struct udevice *dev, int id)
{
struct sandbox_clk_test *sbct = dev_get_priv(dev);
@@ -64,6 +72,13 @@ int sandbox_clk_test_enable(struct udevice *dev, int id)
return clk_enable(&sbct->clks[id]);
}
+int sandbox_clk_test_enable_bulk(struct udevice *dev)
+{
+ struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+ return clk_enable_bulk(&sbct->bulk);
+}
+
int sandbox_clk_test_disable(struct udevice *dev, int id)
{
struct sandbox_clk_test *sbct = dev_get_priv(dev);
@@ -74,6 +89,13 @@ int sandbox_clk_test_disable(struct udevice *dev, int id)
return clk_disable(&sbct->clks[id]);
}
+int sandbox_clk_test_disable_bulk(struct udevice *dev)
+{
+ struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+ return clk_disable_bulk(&sbct->bulk);
+}
+
int sandbox_clk_test_free(struct udevice *dev)
{
struct sandbox_clk_test *sbct = dev_get_priv(dev);
@@ -88,6 +110,13 @@ int sandbox_clk_test_free(struct udevice *dev)
return 0;
}
+int sandbox_clk_test_release_bulk(struct udevice *dev)
+{
+ struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+ return clk_release_bulk(&sbct->bulk);
+}
+
static const struct udevice_id sandbox_clk_test_ids[] = {
{ .compatible = "sandbox,clk-test" },
{ }
diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c
index 926b249ff3..d8eab1a88d 100644
--- a/drivers/clk/clk_stm32f.c
+++ b/drivers/clk/clk_stm32f.c
@@ -55,18 +55,27 @@
#define RCC_CFGR_PPRE1_SHIFT 10
#define RCC_CFGR_PPRE2_SHIFT 13
-#define RCC_PLLCFGR_PLLSAIN_MASK GENMASK(14, 6)
-#define RCC_PLLCFGR_PLLSAIP_MASK GENMASK(17, 16)
+#define RCC_PLLSAICFGR_PLLSAIN_MASK GENMASK(14, 6)
+#define RCC_PLLSAICFGR_PLLSAIP_MASK GENMASK(17, 16)
+#define RCC_PLLSAICFGR_PLLSAIQ_MASK GENMASK(27, 24)
+#define RCC_PLLSAICFGR_PLLSAIR_MASK GENMASK(30, 28)
#define RCC_PLLSAICFGR_PLLSAIN_SHIFT 6
#define RCC_PLLSAICFGR_PLLSAIP_SHIFT 16
+#define RCC_PLLSAICFGR_PLLSAIQ_SHIFT 24
+#define RCC_PLLSAICFGR_PLLSAIR_SHIFT 28
#define RCC_PLLSAICFGR_PLLSAIP_4 BIT(16)
#define RCC_PLLSAICFGR_PLLSAIQ_4 BIT(26)
-#define RCC_PLLSAICFGR_PLLSAIR_2 BIT(29)
+#define RCC_PLLSAICFGR_PLLSAIR_3 BIT(29) | BIT(28)
+#define RCC_DCKCFGRX_TIMPRE BIT(24)
#define RCC_DCKCFGRX_CK48MSEL BIT(27)
#define RCC_DCKCFGRX_SDMMC1SEL BIT(28)
#define RCC_DCKCFGR2_SDMMC2SEL BIT(29)
+#define RCC_DCKCFGR_PLLSAIDIVR_SHIFT 16
+#define RCC_DCKCFGR_PLLSAIDIVR_MASK GENMASK(17, 16)
+#define RCC_DCKCFGR_PLLSAIDIVR_2 0
+
/*
* RCC AHB1ENR specific definitions
*/
@@ -86,8 +95,10 @@
#define RCC_APB2ENR_SYSCFGEN BIT(14)
#define RCC_APB2ENR_SAI1EN BIT(22)
-enum periph_clock {
- TIMER2_CLOCK_CFG,
+enum pllsai_div {
+ PLLSAIP,
+ PLLSAIQ,
+ PLLSAIR,
};
static const struct stm32_clk_info stm32f4_clk_info = {
@@ -125,13 +136,17 @@ struct stm32_clk {
unsigned long hse_rate;
};
+#ifdef CONFIG_VIDEO_STM32
+static const u8 plldivr_table[] = { 0, 0, 2, 3, 4, 5, 6, 7 };
+#endif
+static const u8 pllsaidivr_table[] = { 2, 4, 8, 16 };
+
static int configure_clocks(struct udevice *dev)
{
struct stm32_clk *priv = dev_get_priv(dev);
struct stm32_rcc_regs *regs = priv->base;
struct stm32_pwr_regs *pwr = priv->pwr_regs;
struct pll_psc *sys_pll_psc = &priv->info.sys_pll_psc;
- u32 pllsaicfgr = 0;
/* Reset RCC configuration */
setbits_le32(&regs->cr, RCC_CR_HSION);
@@ -163,20 +178,10 @@ static int configure_clocks(struct udevice *dev)
clrsetbits_le32(&regs->pllcfgr, RCC_PLLCFGR_PLLQ_MASK,
sys_pll_psc->pll_q << RCC_PLLCFGR_PLLQ_SHIFT);
- /* Configure the SAI PLL to get a 48 MHz source */
- pllsaicfgr = RCC_PLLSAICFGR_PLLSAIR_2 | RCC_PLLSAICFGR_PLLSAIQ_4 |
- RCC_PLLSAICFGR_PLLSAIP_4;
- pllsaicfgr |= 192 << RCC_PLLSAICFGR_PLLSAIN_SHIFT;
- writel(pllsaicfgr, &regs->pllsaicfgr);
-
- /* Enable the main PLL */
- setbits_le32(&regs->cr, RCC_CR_PLLON);
- while (!(readl(&regs->cr) & RCC_CR_PLLRDY))
- ;
-
+ /* configure SDMMC clock */
if (priv->info.v2) { /*stm32f7 case */
- /* select PLLSAI as 48MHz clock source */
- setbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_CK48MSEL);
+ /* select PLLQ as 48MHz clock source */
+ clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_CK48MSEL);
/* select 48MHz as SDMMC1 clock source */
clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGRX_SDMMC1SEL);
@@ -184,18 +189,36 @@ static int configure_clocks(struct udevice *dev)
/* select 48MHz as SDMMC2 clock source */
clrbits_le32(&regs->dckcfgr2, RCC_DCKCFGR2_SDMMC2SEL);
} else { /* stm32f4 case */
- /* select PLLSAI as 48MHz clock source */
- setbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_CK48MSEL);
+ /* select PLLQ as 48MHz clock source */
+ clrbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_CK48MSEL);
/* select 48MHz as SDMMC1 clock source */
clrbits_le32(&regs->dckcfgr, RCC_DCKCFGRX_SDMMC1SEL);
}
- /* Enable the SAI PLL */
+#ifdef CONFIG_VIDEO_STM32
+ /*
+ * Configure the SAI PLL to generate LTDC pixel clock
+ */
+ clrsetbits_le32(&regs->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIR_MASK,
+ RCC_PLLSAICFGR_PLLSAIR_3);
+ clrsetbits_le32(&regs->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIN_MASK,
+ 195 << RCC_PLLSAICFGR_PLLSAIN_SHIFT);
+
+ clrsetbits_le32(&regs->dckcfgr, RCC_DCKCFGR_PLLSAIDIVR_MASK,
+ RCC_DCKCFGR_PLLSAIDIVR_2 << RCC_DCKCFGR_PLLSAIDIVR_SHIFT);
+#endif
+ /* Enable the main PLL */
+ setbits_le32(&regs->cr, RCC_CR_PLLON);
+ while (!(readl(&regs->cr) & RCC_CR_PLLRDY))
+ ;
+
+#ifdef CONFIG_VIDEO_STM32
+/* Enable the SAI PLL */
setbits_le32(&regs->cr, RCC_CR_PLLSAION);
while (!(readl(&regs->cr) & RCC_CR_PLLSAIRDY))
;
-
+#endif
setbits_le32(&regs->apb1enr, RCC_APB1ENR_PWREN);
if (priv->info.has_overdrive) {
@@ -221,8 +244,6 @@ static int configure_clocks(struct udevice *dev)
while ((readl(&regs->cfgr) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_PLL)
;
- /* gate the SAI clock, needed for MMC 1&2 clocks */
- setbits_le32(&regs->apb2enr, RCC_APB2ENR_SAI1EN);
#ifdef CONFIG_ETH_DESIGNWARE
/* gate the SYSCFG clock, needed to set RMII ethernet interface */
@@ -232,49 +253,145 @@ static int configure_clocks(struct udevice *dev)
return 0;
}
-static unsigned long stm32_clk_pll48clk_rate(struct stm32_clk *priv,
- u32 sysclk)
+static bool stm32_clk_get_ck48msel(struct stm32_clk *priv)
{
struct stm32_rcc_regs *regs = priv->base;
- u16 pllq, pllm, pllsain, pllsaip;
- bool pllsai;
-
- pllq = (readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLQ_MASK)
- >> RCC_PLLCFGR_PLLQ_SHIFT;
if (priv->info.v2) /*stm32f7 case */
- pllsai = readl(&regs->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL;
+ return readl(&regs->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL;
else
- pllsai = readl(&regs->dckcfgr) & RCC_DCKCFGRX_CK48MSEL;
- if (pllsai) {
- /* PLL48CLK is selected from PLLSAI, get PLLSAI value */
- pllm = (readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
- pllsain = ((readl(&regs->pllsaicfgr) & RCC_PLLCFGR_PLLSAIN_MASK)
- >> RCC_PLLSAICFGR_PLLSAIN_SHIFT);
- pllsaip = ((((readl(&regs->pllsaicfgr) & RCC_PLLCFGR_PLLSAIP_MASK)
- >> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1);
- return ((priv->hse_rate / pllm) * pllsain) / pllsaip;
+ return readl(&regs->dckcfgr) & RCC_DCKCFGRX_CK48MSEL;
+}
+
+static unsigned long stm32_clk_get_pllsai_vco_rate(struct stm32_clk *priv)
+{
+ struct stm32_rcc_regs *regs = priv->base;
+ u16 pllm, pllsain;
+
+ pllm = (readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
+ pllsain = ((readl(&regs->pllsaicfgr) & RCC_PLLSAICFGR_PLLSAIN_MASK)
+ >> RCC_PLLSAICFGR_PLLSAIN_SHIFT);
+
+ return ((priv->hse_rate / pllm) * pllsain);
+}
+
+static unsigned long stm32_clk_get_pllsai_rate(struct stm32_clk *priv,
+ enum pllsai_div output)
+{
+ struct stm32_rcc_regs *regs = priv->base;
+ u16 pll_div_output;
+
+ switch (output) {
+ case PLLSAIP:
+ pll_div_output = ((((readl(&regs->pllsaicfgr)
+ & RCC_PLLSAICFGR_PLLSAIP_MASK)
+ >> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1);
+ break;
+ case PLLSAIQ:
+ pll_div_output = (readl(&regs->pllsaicfgr)
+ & RCC_PLLSAICFGR_PLLSAIQ_MASK)
+ >> RCC_PLLSAICFGR_PLLSAIQ_SHIFT;
+ break;
+ case PLLSAIR:
+ pll_div_output = (readl(&regs->pllsaicfgr)
+ & RCC_PLLSAICFGR_PLLSAIR_MASK)
+ >> RCC_PLLSAICFGR_PLLSAIR_SHIFT;
+ break;
+ default:
+ pr_err("incorrect PLLSAI output %d\n", output);
+ return -EINVAL;
}
- /* PLL48CLK is selected from PLLQ */
- return sysclk / pllq;
+
+ return (stm32_clk_get_pllsai_vco_rate(priv) / pll_div_output);
}
-static unsigned long stm32_clk_get_rate(struct clk *clk)
+static bool stm32_get_timpre(struct stm32_clk *priv)
{
- struct stm32_clk *priv = dev_get_priv(clk->dev);
struct stm32_rcc_regs *regs = priv->base;
- u32 sysclk = 0;
- u32 shift = 0;
- u16 pllm, plln, pllp;
+ u32 val;
+
+ if (priv->info.v2) /*stm32f7 case */
+ val = readl(&regs->dckcfgr2);
+ else
+ val = readl(&regs->dckcfgr);
+ /* get timer prescaler */
+ return !!(val & RCC_DCKCFGRX_TIMPRE);
+}
+
+static u32 stm32_get_hclk_rate(struct stm32_rcc_regs *regs, u32 sysclk)
+{
+ u8 shift;
/* Prescaler table lookups for clock computation */
u8 ahb_psc_table[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
};
+
+ shift = ahb_psc_table[(
+ (readl(&regs->cfgr) & RCC_CFGR_AHB_PSC_MASK)
+ >> RCC_CFGR_HPRE_SHIFT)];
+
+ return sysclk >> shift;
+};
+
+static u8 stm32_get_apb_shift(struct stm32_rcc_regs *regs, enum apb apb)
+{
+ /* Prescaler table lookups for clock computation */
u8 apb_psc_table[8] = {
0, 0, 0, 0, 1, 2, 3, 4
};
+ if (apb == APB1)
+ return apb_psc_table[(
+ (readl(&regs->cfgr) & RCC_CFGR_APB1_PSC_MASK)
+ >> RCC_CFGR_PPRE1_SHIFT)];
+ else /* APB2 */
+ return apb_psc_table[(
+ (readl(&regs->cfgr) & RCC_CFGR_APB2_PSC_MASK)
+ >> RCC_CFGR_PPRE2_SHIFT)];
+};
+
+static u32 stm32_get_timer_rate(struct stm32_clk *priv, u32 sysclk,
+ enum apb apb)
+{
+ struct stm32_rcc_regs *regs = priv->base;
+ u8 shift = stm32_get_apb_shift(regs, apb);
+
+ if (stm32_get_timpre(priv))
+ /*
+ * if APB prescaler is configured to a
+ * division factor of 1, 2 or 4
+ */
+ switch (shift) {
+ case 0:
+ case 1:
+ case 2:
+ return stm32_get_hclk_rate(regs, sysclk);
+ default:
+ return (sysclk >> shift) * 4;
+ }
+ else
+ /*
+ * if APB prescaler is configured to a
+ * division factor of 1
+ */
+ if (shift == 0)
+ return sysclk;
+ else
+ return (sysclk >> shift) * 2;
+};
+
+static ulong stm32_clk_get_rate(struct clk *clk)
+{
+ struct stm32_clk *priv = dev_get_priv(clk->dev);
+ struct stm32_rcc_regs *regs = priv->base;
+ u32 sysclk = 0;
+ u32 vco;
+ u32 sdmmcxsel_bit;
+ u32 saidivr;
+ u32 pllsai_rate;
+ u16 pllm, plln, pllp, pllq;
+
if ((readl(&regs->cfgr) & RCC_CFGR_SWS_MASK) ==
RCC_CFGR_SWS_PLL) {
pllm = (readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
@@ -282,7 +399,10 @@ static unsigned long stm32_clk_get_rate(struct clk *clk)
>> RCC_PLLCFGR_PLLN_SHIFT);
pllp = ((((readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLP_MASK)
>> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1);
- sysclk = ((priv->hse_rate / pllm) * plln) / pllp;
+ pllq = ((readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLQ_MASK)
+ >> RCC_PLLCFGR_PLLQ_SHIFT);
+ vco = (priv->hse_rate / pllm) * plln;
+ sysclk = vco / pllp;
} else {
return -EINVAL;
}
@@ -293,44 +413,72 @@ static unsigned long stm32_clk_get_rate(struct clk *clk)
* AHB1, AHB2 and AHB3
*/
case STM32F7_AHB1_CLOCK(GPIOA) ... STM32F7_AHB3_CLOCK(QSPI):
- shift = ahb_psc_table[(
- (readl(&regs->cfgr) & RCC_CFGR_AHB_PSC_MASK)
- >> RCC_CFGR_HPRE_SHIFT)];
- return sysclk >>= shift;
+ return stm32_get_hclk_rate(regs, sysclk);
/* APB1 CLOCK */
case STM32F7_APB1_CLOCK(TIM2) ... STM32F7_APB1_CLOCK(UART8):
- shift = apb_psc_table[(
- (readl(&regs->cfgr) & RCC_CFGR_APB1_PSC_MASK)
- >> RCC_CFGR_PPRE1_SHIFT)];
- return sysclk >>= shift;
+ /* For timer clock, an additionnal prescaler is used*/
+ switch (clk->id) {
+ case STM32F7_APB1_CLOCK(TIM2):
+ case STM32F7_APB1_CLOCK(TIM3):
+ case STM32F7_APB1_CLOCK(TIM4):
+ case STM32F7_APB1_CLOCK(TIM5):
+ case STM32F7_APB1_CLOCK(TIM6):
+ case STM32F7_APB1_CLOCK(TIM7):
+ case STM32F7_APB1_CLOCK(TIM12):
+ case STM32F7_APB1_CLOCK(TIM13):
+ case STM32F7_APB1_CLOCK(TIM14):
+ return stm32_get_timer_rate(priv, sysclk, APB1);
+ }
+ return (sysclk >> stm32_get_apb_shift(regs, APB1));
+
/* APB2 CLOCK */
- case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC):
+ case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(DSI):
+ switch (clk->id) {
/*
* particular case for SDMMC1 and SDMMC2 :
* 48Mhz source clock can be from main PLL or from
- * SAI PLL
+ * PLLSAIP
*/
- switch (clk->id) {
case STM32F7_APB2_CLOCK(SDMMC1):
- if (readl(&regs->dckcfgr2) & RCC_DCKCFGRX_SDMMC1SEL)
- /* System clock is selected as SDMMC1 clock */
- return sysclk;
- else
- return stm32_clk_pll48clk_rate(priv, sysclk);
- break;
case STM32F7_APB2_CLOCK(SDMMC2):
- if (readl(&regs->dckcfgr2) & RCC_DCKCFGR2_SDMMC2SEL)
- /* System clock is selected as SDMMC2 clock */
+ if (clk->id == STM32F7_APB2_CLOCK(SDMMC1))
+ sdmmcxsel_bit = RCC_DCKCFGRX_SDMMC1SEL;
+ else
+ sdmmcxsel_bit = RCC_DCKCFGR2_SDMMC2SEL;
+
+ if (readl(&regs->dckcfgr2) & sdmmcxsel_bit)
+ /* System clock is selected as SDMMC1 clock */
return sysclk;
+ /*
+ * 48 MHz can be generated by either PLLSAIP
+ * or by PLLQ depending of CK48MSEL bit of RCC_DCKCFGR
+ */
+ if (stm32_clk_get_ck48msel(priv))
+ return stm32_clk_get_pllsai_rate(priv, PLLSAIP);
else
- return stm32_clk_pll48clk_rate(priv, sysclk);
+ return (vco / pllq);
break;
+
+ /* For timer clock, an additionnal prescaler is used*/
+ case STM32F7_APB2_CLOCK(TIM1):
+ case STM32F7_APB2_CLOCK(TIM8):
+ case STM32F7_APB2_CLOCK(TIM9):
+ case STM32F7_APB2_CLOCK(TIM10):
+ case STM32F7_APB2_CLOCK(TIM11):
+ return stm32_get_timer_rate(priv, sysclk, APB2);
+ break;
+
+ /* particular case for LTDC clock */
+ case STM32F7_APB2_CLOCK(LTDC):
+ saidivr = readl(&regs->dckcfgr);
+ saidivr = (saidivr & RCC_DCKCFGR_PLLSAIDIVR_MASK)
+ >> RCC_DCKCFGR_PLLSAIDIVR_SHIFT;
+ pllsai_rate = stm32_clk_get_pllsai_rate(priv, PLLSAIR);
+
+ return pllsai_rate / pllsaidivr_table[saidivr];
}
+ return (sysclk >> stm32_get_apb_shift(regs, APB2));
- shift = apb_psc_table[(
- (readl(&regs->cfgr) & RCC_CFGR_APB2_PSC_MASK)
- >> RCC_CFGR_PPRE2_SHIFT)];
- return sysclk >>= shift;
default:
pr_err("clock index %ld out of range\n", clk->id);
return -EINVAL;
@@ -339,7 +487,104 @@ static unsigned long stm32_clk_get_rate(struct clk *clk)
static ulong stm32_set_rate(struct clk *clk, ulong rate)
{
+#ifdef CONFIG_VIDEO_STM32
+ struct stm32_clk *priv = dev_get_priv(clk->dev);
+ struct stm32_rcc_regs *regs = priv->base;
+ u32 pllsair_rate, pllsai_vco_rate, current_rate;
+ u32 best_div, best_diff, diff;
+ u16 div;
+ u8 best_plldivr, best_pllsaidivr;
+ u8 i, j;
+ bool found = false;
+
+ /* Only set_rate for LTDC clock is implemented */
+ if (clk->id != STM32F7_APB2_CLOCK(LTDC)) {
+ pr_err("set_rate not implemented for clock index %ld\n",
+ clk->id);
+ return 0;
+ }
+
+ if (rate == stm32_clk_get_rate(clk))
+ /* already set to requested rate */
+ return rate;
+
+ /* get the current PLLSAIR output freq */
+ pllsair_rate = stm32_clk_get_pllsai_rate(priv, PLLSAIR);
+ best_div = pllsair_rate / rate;
+
+ /* look into pllsaidivr_table if this divider is available*/
+ for (i = 0 ; i < sizeof(pllsaidivr_table); i++)
+ if (best_div == pllsaidivr_table[i]) {
+ /* set pll_saidivr with found value */
+ clrsetbits_le32(&regs->dckcfgr,
+ RCC_DCKCFGR_PLLSAIDIVR_MASK,
+ pllsaidivr_table[i]);
+ return rate;
+ }
+
+ /*
+ * As no pllsaidivr value is suitable to obtain requested freq,
+ * test all combination of pllsaidivr * pllsair and find the one
+ * which give freq closest to requested rate.
+ */
+
+ pllsai_vco_rate = stm32_clk_get_pllsai_vco_rate(priv);
+ best_diff = ULONG_MAX;
+ best_pllsaidivr = 0;
+ best_plldivr = 0;
+ /*
+ * start at index 2 of plldivr_table as divider value at index 0
+ * and 1 are 0)
+ */
+ for (i = 2; i < sizeof(plldivr_table); i++) {
+ for (j = 0; j < sizeof(pllsaidivr_table); j++) {
+ div = plldivr_table[i] * pllsaidivr_table[j];
+ current_rate = pllsai_vco_rate / div;
+ /* perfect combination is found ? */
+ if (current_rate == rate) {
+ best_pllsaidivr = j;
+ best_plldivr = i;
+ found = true;
+ break;
+ }
+
+ diff = (current_rate > rate) ?
+ current_rate - rate : rate - current_rate;
+
+ /* found a better combination ? */
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_pllsaidivr = j;
+ best_plldivr = i;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ /* Disable the SAI PLL */
+ clrbits_le32(&regs->cr, RCC_CR_PLLSAION);
+
+ /* set pll_saidivr with found value */
+ clrsetbits_le32(&regs->dckcfgr, RCC_DCKCFGR_PLLSAIDIVR_MASK,
+ best_pllsaidivr << RCC_DCKCFGR_PLLSAIDIVR_SHIFT);
+
+ /* set pllsair with found value */
+ clrsetbits_le32(&regs->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIR_MASK,
+ plldivr_table[best_plldivr]
+ << RCC_PLLSAICFGR_PLLSAIR_SHIFT);
+
+ /* Enable the SAI PLL */
+ setbits_le32(&regs->cr, RCC_CR_PLLSAION);
+ while (!(readl(&regs->cr) & RCC_CR_PLLSAIRDY))
+ ;
+
+ div = plldivr_table[best_plldivr] * pllsaidivr_table[best_pllsaidivr];
+ return pllsai_vco_rate / div;
+#else
return 0;
+#endif
}
static int stm32_clk_enable(struct clk *clk)
@@ -356,17 +601,6 @@ static int stm32_clk_enable(struct clk *clk)
return 0;
}
-void clock_setup(int peripheral)
-{
- switch (peripheral) {
- case TIMER2_CLOCK_CFG:
- setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_TIM2EN);
- break;
- default:
- break;
- }
-}
-
static int stm32_clk_probe(struct udevice *dev)
{
struct ofnode_phandle_args args;
diff --git a/drivers/clk/clk_stm32h7.c b/drivers/clk/clk_stm32h7.c
index c9594d405a..9ee2e2e999 100644
--- a/drivers/clk/clk_stm32h7.c
+++ b/drivers/clk/clk_stm32h7.c
@@ -35,6 +35,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define RCC_CFGR_SW_CSI 1
#define RCC_CFGR_SW_HSE 2
#define RCC_CFGR_SW_PLL1 3
+#define RCC_CFGR_TIMPRE BIT(15)
#define RCC_PLLCKSELR_PLLSRC_HSI 0
#define RCC_PLLCKSELR_PLLSRC_CSI 1
@@ -339,6 +340,11 @@ struct pll_psc sys_pll_psc = {
.divr = 2,
};
+enum apb {
+ APB1,
+ APB2,
+};
+
int configure_clocks(struct udevice *dev)
{
struct stm32_clk *priv = dev_get_priv(dev);
@@ -562,13 +568,74 @@ static u32 stm32_get_PLL1_rate(struct stm32_rcc_regs *regs,
return -EINVAL;
}
+static u32 stm32_get_apb_psc(struct stm32_rcc_regs *regs, enum apb apb)
+{
+ u16 prescaler_table[8] = {2, 4, 8, 16, 64, 128, 256, 512};
+ u32 d2cfgr = readl(&regs->d2cfgr);
+
+ if (apb == APB1) {
+ if (d2cfgr & RCC_D2CFGR_D2PPRE1_DIVIDED)
+ /* get D2 domain APB1 prescaler */
+ return prescaler_table[
+ ((d2cfgr & RCC_D2CFGR_D2PPRE1_DIVIDER)
+ >> RCC_D2CFGR_D2PPRE1_SHIFT)];
+ } else { /* APB2 */
+ if (d2cfgr & RCC_D2CFGR_D2PPRE2_DIVIDED)
+ /* get D2 domain APB2 prescaler */
+ return prescaler_table[
+ ((d2cfgr & RCC_D2CFGR_D2PPRE2_DIVIDER)
+ >> RCC_D2CFGR_D2PPRE2_SHIFT)];
+ }
+
+ return 1;
+};
+
+static u32 stm32_get_timer_rate(struct stm32_clk *priv, u32 sysclk,
+ enum apb apb)
+{
+ struct stm32_rcc_regs *regs = priv->rcc_base;
+u32 psc = stm32_get_apb_psc(regs, apb);
+
+ if (readl(&regs->cfgr) & RCC_CFGR_TIMPRE)
+ /*
+ * if APB prescaler is configured to a
+ * division factor of 1, 2 or 4
+ */
+ switch (psc) {
+ case 1:
+ case 2:
+ case 4:
+ return sysclk;
+ case 8:
+ return sysclk / 2;
+ case 16:
+ return sysclk / 4;
+ default:
+ pr_err("unexpected prescaler value (%d)\n", psc);
+ return 0;
+ }
+ else
+ switch (psc) {
+ case 1:
+ return sysclk;
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ return sysclk / psc;
+ default:
+ pr_err("unexpected prescaler value (%d)\n", psc);
+ return 0;
+ }
+};
+
static ulong stm32_clk_get_rate(struct clk *clk)
{
struct stm32_clk *priv = dev_get_priv(clk->dev);
struct stm32_rcc_regs *regs = priv->rcc_base;
ulong sysclk = 0;
u32 gate_offset;
- u32 d1cfgr;
+ u32 d1cfgr, d3cfgr;
/* prescaler table lookups for clock computation */
u16 prescaler_table[8] = {2, 4, 8, 16, 64, 128, 256, 512};
u8 source, idx;
@@ -645,9 +712,10 @@ static ulong stm32_clk_get_rate(struct clk *clk)
break;
case RCC_APB4ENR:
- if (d1cfgr & RCC_D3CFGR_D3PPRE_DIVIDED) {
+ d3cfgr = readl(&regs->d3cfgr);
+ if (d3cfgr & RCC_D3CFGR_D3PPRE_DIVIDED) {
/* get D3 domain APB4 prescaler */
- idx = (d1cfgr & RCC_D3CFGR_D3PPRE_DIVIDER) >>
+ idx = (d3cfgr & RCC_D3CFGR_D3PPRE_DIVIDER) >>
RCC_D3CFGR_D3PPRE_SHIFT;
sysclk = sysclk / prescaler_table[idx];
}
@@ -660,31 +728,42 @@ static ulong stm32_clk_get_rate(struct clk *clk)
case RCC_APB1LENR:
case RCC_APB1HENR:
- if (d1cfgr & RCC_D2CFGR_D2PPRE1_DIVIDED) {
- /* get D2 domain APB1 prescaler */
- idx = (d1cfgr & RCC_D2CFGR_D2PPRE1_DIVIDER) >>
- RCC_D2CFGR_D2PPRE1_SHIFT;
- sysclk = sysclk / prescaler_table[idx];
+ /* special case for GPT timers */
+ switch (clk->id) {
+ case TIM14_CK:
+ case TIM13_CK:
+ case TIM12_CK:
+ case TIM7_CK:
+ case TIM6_CK:
+ case TIM5_CK:
+ case TIM4_CK:
+ case TIM3_CK:
+ case TIM2_CK:
+ return stm32_get_timer_rate(priv, sysclk, APB1);
}
debug("%s system clock: freq after APB1 prescaler = %ld\n",
__func__, sysclk);
- return sysclk;
+ return (sysclk / stm32_get_apb_psc(regs, APB1));
break;
case RCC_APB2ENR:
- if (d1cfgr & RCC_D2CFGR_D2PPRE2_DIVIDED) {
- /* get D2 domain APB1 prescaler */
- idx = (d1cfgr & RCC_D2CFGR_D2PPRE2_DIVIDER) >>
- RCC_D2CFGR_D2PPRE2_SHIFT;
- sysclk = sysclk / prescaler_table[idx];
+ /* special case for timers */
+ switch (clk->id) {
+ case TIM17_CK:
+ case TIM16_CK:
+ case TIM15_CK:
+ case TIM8_CK:
+ case TIM1_CK:
+ return stm32_get_timer_rate(priv, sysclk, APB2);
}
debug("%s system clock: freq after APB2 prescaler = %ld\n",
__func__, sysclk);
- return sysclk;
+ return (sysclk / stm32_get_apb_psc(regs, APB2));
+
break;
default:
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
new file mode 100644
index 0000000000..c67aa44473
--- /dev/null
+++ b/drivers/clk/clk_stm32mp1.c
@@ -0,0 +1,1777 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <regmap.h>
+#include <spl.h>
+#include <syscon.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+
+#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
+/* activate clock tree initialization in the driver */
+#define STM32MP1_CLOCK_TREE_INIT
+#endif
+
+#define MAX_HSI_HZ 64000000
+
+/* TIMEOUT */
+#define TIMEOUT_200MS 200000
+#define TIMEOUT_1S 1000000
+
+/* STGEN registers */
+#define STGENC_CNTCR 0x00
+#define STGENC_CNTSR 0x04
+#define STGENC_CNTCVL 0x08
+#define STGENC_CNTCVU 0x0C
+#define STGENC_CNTFID0 0x20
+
+#define STGENC_CNTCR_EN BIT(0)
+
+/* RCC registers */
+#define RCC_OCENSETR 0x0C
+#define RCC_OCENCLRR 0x10
+#define RCC_HSICFGR 0x18
+#define RCC_MPCKSELR 0x20
+#define RCC_ASSCKSELR 0x24
+#define RCC_RCK12SELR 0x28
+#define RCC_MPCKDIVR 0x2C
+#define RCC_AXIDIVR 0x30
+#define RCC_APB4DIVR 0x3C
+#define RCC_APB5DIVR 0x40
+#define RCC_RTCDIVR 0x44
+#define RCC_MSSCKSELR 0x48
+#define RCC_PLL1CR 0x80
+#define RCC_PLL1CFGR1 0x84
+#define RCC_PLL1CFGR2 0x88
+#define RCC_PLL1FRACR 0x8C
+#define RCC_PLL1CSGR 0x90
+#define RCC_PLL2CR 0x94
+#define RCC_PLL2CFGR1 0x98
+#define RCC_PLL2CFGR2 0x9C
+#define RCC_PLL2FRACR 0xA0
+#define RCC_PLL2CSGR 0xA4
+#define RCC_I2C46CKSELR 0xC0
+#define RCC_CPERCKSELR 0xD0
+#define RCC_STGENCKSELR 0xD4
+#define RCC_DDRITFCR 0xD8
+#define RCC_BDCR 0x140
+#define RCC_RDLSICR 0x144
+#define RCC_MP_APB4ENSETR 0x200
+#define RCC_MP_APB5ENSETR 0x208
+#define RCC_MP_AHB5ENSETR 0x210
+#define RCC_MP_AHB6ENSETR 0x218
+#define RCC_OCRDYR 0x808
+#define RCC_DBGCFGR 0x80C
+#define RCC_RCK3SELR 0x820
+#define RCC_RCK4SELR 0x824
+#define RCC_MCUDIVR 0x830
+#define RCC_APB1DIVR 0x834
+#define RCC_APB2DIVR 0x838
+#define RCC_APB3DIVR 0x83C
+#define RCC_PLL3CR 0x880
+#define RCC_PLL3CFGR1 0x884
+#define RCC_PLL3CFGR2 0x888
+#define RCC_PLL3FRACR 0x88C
+#define RCC_PLL3CSGR 0x890
+#define RCC_PLL4CR 0x894
+#define RCC_PLL4CFGR1 0x898
+#define RCC_PLL4CFGR2 0x89C
+#define RCC_PLL4FRACR 0x8A0
+#define RCC_PLL4CSGR 0x8A4
+#define RCC_I2C12CKSELR 0x8C0
+#define RCC_I2C35CKSELR 0x8C4
+#define RCC_UART6CKSELR 0x8E4
+#define RCC_UART24CKSELR 0x8E8
+#define RCC_UART35CKSELR 0x8EC
+#define RCC_UART78CKSELR 0x8F0
+#define RCC_SDMMC12CKSELR 0x8F4
+#define RCC_SDMMC3CKSELR 0x8F8
+#define RCC_ETHCKSELR 0x8FC
+#define RCC_QSPICKSELR 0x900
+#define RCC_FMCCKSELR 0x904
+#define RCC_USBCKSELR 0x91C
+#define RCC_MP_APB1ENSETR 0xA00
+#define RCC_MP_APB2ENSETR 0XA08
+#define RCC_MP_AHB2ENSETR 0xA18
+#define RCC_MP_AHB4ENSETR 0xA28
+
+/* used for most of SELR register */
+#define RCC_SELR_SRC_MASK GENMASK(2, 0)
+#define RCC_SELR_SRCRDY BIT(31)
+
+/* Values of RCC_MPCKSELR register */
+#define RCC_MPCKSELR_HSI 0
+#define RCC_MPCKSELR_HSE 1
+#define RCC_MPCKSELR_PLL 2
+#define RCC_MPCKSELR_PLL_MPUDIV 3
+
+/* Values of RCC_ASSCKSELR register */
+#define RCC_ASSCKSELR_HSI 0
+#define RCC_ASSCKSELR_HSE 1
+#define RCC_ASSCKSELR_PLL 2
+
+/* Values of RCC_MSSCKSELR register */
+#define RCC_MSSCKSELR_HSI 0
+#define RCC_MSSCKSELR_HSE 1
+#define RCC_MSSCKSELR_CSI 2
+#define RCC_MSSCKSELR_PLL 3
+
+/* Values of RCC_CPERCKSELR register */
+#define RCC_CPERCKSELR_HSI 0
+#define RCC_CPERCKSELR_CSI 1
+#define RCC_CPERCKSELR_HSE 2
+
+/* used for most of DIVR register : max div for RTC */
+#define RCC_DIVR_DIV_MASK GENMASK(5, 0)
+#define RCC_DIVR_DIVRDY BIT(31)
+
+/* Masks for specific DIVR registers */
+#define RCC_APBXDIV_MASK GENMASK(2, 0)
+#define RCC_MPUDIV_MASK GENMASK(2, 0)
+#define RCC_AXIDIV_MASK GENMASK(2, 0)
+#define RCC_MCUDIV_MASK GENMASK(3, 0)
+
+/* offset between RCC_MP_xxxENSETR and RCC_MP_xxxENCLRR registers */
+#define RCC_MP_ENCLRR_OFFSET 4
+
+/* Fields of RCC_BDCR register */
+#define RCC_BDCR_LSEON BIT(0)
+#define RCC_BDCR_LSEBYP BIT(1)
+#define RCC_BDCR_LSERDY BIT(2)
+#define RCC_BDCR_LSEDRV_MASK GENMASK(5, 4)
+#define RCC_BDCR_LSEDRV_SHIFT 4
+#define RCC_BDCR_LSECSSON BIT(8)
+#define RCC_BDCR_RTCCKEN BIT(20)
+#define RCC_BDCR_RTCSRC_MASK GENMASK(17, 16)
+#define RCC_BDCR_RTCSRC_SHIFT 16
+
+/* Fields of RCC_RDLSICR register */
+#define RCC_RDLSICR_LSION BIT(0)
+#define RCC_RDLSICR_LSIRDY BIT(1)
+
+/* used for ALL PLLNCR registers */
+#define RCC_PLLNCR_PLLON BIT(0)
+#define RCC_PLLNCR_PLLRDY BIT(1)
+#define RCC_PLLNCR_DIVPEN BIT(4)
+#define RCC_PLLNCR_DIVQEN BIT(5)
+#define RCC_PLLNCR_DIVREN BIT(6)
+#define RCC_PLLNCR_DIVEN_SHIFT 4
+
+/* used for ALL PLLNCFGR1 registers */
+#define RCC_PLLNCFGR1_DIVM_SHIFT 16
+#define RCC_PLLNCFGR1_DIVM_MASK GENMASK(21, 16)
+#define RCC_PLLNCFGR1_DIVN_SHIFT 0
+#define RCC_PLLNCFGR1_DIVN_MASK GENMASK(8, 0)
+/* only for PLL3 and PLL4 */
+#define RCC_PLLNCFGR1_IFRGE_SHIFT 24
+#define RCC_PLLNCFGR1_IFRGE_MASK GENMASK(25, 24)
+
+/* used for ALL PLLNCFGR2 registers */
+#define RCC_PLLNCFGR2_DIVX_MASK GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVP_SHIFT 0
+#define RCC_PLLNCFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVQ_SHIFT 8
+#define RCC_PLLNCFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLLNCFGR2_DIVR_SHIFT 16
+#define RCC_PLLNCFGR2_DIVR_MASK GENMASK(22, 16)
+
+/* used for ALL PLLNFRACR registers */
+#define RCC_PLLNFRACR_FRACV_SHIFT 3
+#define RCC_PLLNFRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLLNFRACR_FRACLE BIT(16)
+
+/* used for ALL PLLNCSGR registers */
+#define RCC_PLLNCSGR_INC_STEP_SHIFT 16
+#define RCC_PLLNCSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLLNCSGR_MOD_PER_SHIFT 0
+#define RCC_PLLNCSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLLNCSGR_SSCG_MODE_SHIFT 15
+#define RCC_PLLNCSGR_SSCG_MODE_MASK BIT(15)
+
+/* used for RCC_OCENSETR and RCC_OCENCLRR registers */
+#define RCC_OCENR_HSION BIT(0)
+#define RCC_OCENR_CSION BIT(4)
+#define RCC_OCENR_HSEON BIT(8)
+#define RCC_OCENR_HSEBYP BIT(10)
+#define RCC_OCENR_HSECSSON BIT(11)
+
+/* Fields of RCC_OCRDYR register */
+#define RCC_OCRDYR_HSIRDY BIT(0)
+#define RCC_OCRDYR_HSIDIVRDY BIT(2)
+#define RCC_OCRDYR_CSIRDY BIT(4)
+#define RCC_OCRDYR_HSERDY BIT(8)
+
+/* Fields of DDRITFCR register */
+#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20)
+#define RCC_DDRITFCR_DDRCKMOD_SHIFT 20
+#define RCC_DDRITFCR_DDRCKMOD_SSR 0
+
+/* Fields of RCC_HSICFGR register */
+#define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0)
+
+/* used for MCO related operations */
+#define RCC_MCOCFG_MCOON BIT(12)
+#define RCC_MCOCFG_MCODIV_MASK GENMASK(7, 4)
+#define RCC_MCOCFG_MCODIV_SHIFT 4
+#define RCC_MCOCFG_MCOSRC_MASK GENMASK(2, 0)
+
+enum stm32mp1_parent_id {
+/*
+ * _HSI, _HSE, _CSI, _LSI, _LSE should not be moved
+ * they are used as index in osc[] as entry point
+ */
+ _HSI,
+ _HSE,
+ _CSI,
+ _LSI,
+ _LSE,
+ _I2S_CKIN,
+ _USB_PHY_48,
+ NB_OSC,
+
+/* other parent source */
+ _HSI_KER = NB_OSC,
+ _HSE_KER,
+ _HSE_KER_DIV2,
+ _CSI_KER,
+ _PLL1_P,
+ _PLL1_Q,
+ _PLL1_R,
+ _PLL2_P,
+ _PLL2_Q,
+ _PLL2_R,
+ _PLL3_P,
+ _PLL3_Q,
+ _PLL3_R,
+ _PLL4_P,
+ _PLL4_Q,
+ _PLL4_R,
+ _ACLK,
+ _PCLK1,
+ _PCLK2,
+ _PCLK3,
+ _PCLK4,
+ _PCLK5,
+ _HCLK6,
+ _HCLK2,
+ _CK_PER,
+ _CK_MPU,
+ _CK_MCU,
+ _PARENT_NB,
+ _UNKNOWN_ID = 0xff,
+};
+
+enum stm32mp1_parent_sel {
+ _I2C12_SEL,
+ _I2C35_SEL,
+ _I2C46_SEL,
+ _UART6_SEL,
+ _UART24_SEL,
+ _UART35_SEL,
+ _UART78_SEL,
+ _SDMMC12_SEL,
+ _SDMMC3_SEL,
+ _ETH_SEL,
+ _QSPI_SEL,
+ _FMC_SEL,
+ _USBPHY_SEL,
+ _USBO_SEL,
+ _STGEN_SEL,
+ _PARENT_SEL_NB,
+ _UNKNOWN_SEL = 0xff,
+};
+
+enum stm32mp1_pll_id {
+ _PLL1,
+ _PLL2,
+ _PLL3,
+ _PLL4,
+ _PLL_NB
+};
+
+enum stm32mp1_div_id {
+ _DIV_P,
+ _DIV_Q,
+ _DIV_R,
+ _DIV_NB,
+};
+
+enum stm32mp1_clksrc_id {
+ CLKSRC_MPU,
+ CLKSRC_AXI,
+ CLKSRC_MCU,
+ CLKSRC_PLL12,
+ CLKSRC_PLL3,
+ CLKSRC_PLL4,
+ CLKSRC_RTC,
+ CLKSRC_MCO1,
+ CLKSRC_MCO2,
+ CLKSRC_NB
+};
+
+enum stm32mp1_clkdiv_id {
+ CLKDIV_MPU,
+ CLKDIV_AXI,
+ CLKDIV_MCU,
+ CLKDIV_APB1,
+ CLKDIV_APB2,
+ CLKDIV_APB3,
+ CLKDIV_APB4,
+ CLKDIV_APB5,
+ CLKDIV_RTC,
+ CLKDIV_MCO1,
+ CLKDIV_MCO2,
+ CLKDIV_NB
+};
+
+enum stm32mp1_pllcfg {
+ PLLCFG_M,
+ PLLCFG_N,
+ PLLCFG_P,
+ PLLCFG_Q,
+ PLLCFG_R,
+ PLLCFG_O,
+ PLLCFG_NB
+};
+
+enum stm32mp1_pllcsg {
+ PLLCSG_MOD_PER,
+ PLLCSG_INC_STEP,
+ PLLCSG_SSCG_MODE,
+ PLLCSG_NB
+};
+
+enum stm32mp1_plltype {
+ PLL_800,
+ PLL_1600,
+ PLL_TYPE_NB
+};
+
+struct stm32mp1_pll {
+ u8 refclk_min;
+ u8 refclk_max;
+ u8 divn_max;
+};
+
+struct stm32mp1_clk_gate {
+ u16 offset;
+ u8 bit;
+ u8 index;
+ u8 set_clr;
+ u8 sel;
+ u8 fixed;
+};
+
+struct stm32mp1_clk_sel {
+ u16 offset;
+ u8 src;
+ u8 msk;
+ u8 nb_parent;
+ const u8 *parent;
+};
+
+#define REFCLK_SIZE 4
+struct stm32mp1_clk_pll {
+ enum stm32mp1_plltype plltype;
+ u16 rckxselr;
+ u16 pllxcfgr1;
+ u16 pllxcfgr2;
+ u16 pllxfracr;
+ u16 pllxcr;
+ u16 pllxcsgr;
+ u8 refclk[REFCLK_SIZE];
+};
+
+struct stm32mp1_clk_data {
+ const struct stm32mp1_clk_gate *gate;
+ const struct stm32mp1_clk_sel *sel;
+ const struct stm32mp1_clk_pll *pll;
+ const int nb_gate;
+};
+
+struct stm32mp1_clk_priv {
+ fdt_addr_t base;
+ const struct stm32mp1_clk_data *data;
+ ulong osc[NB_OSC];
+ struct udevice *osc_dev[NB_OSC];
+};
+
+#define STM32MP1_CLK(off, b, idx, s) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 0, \
+ .sel = (s), \
+ .fixed = _UNKNOWN_ID, \
+ }
+
+#define STM32MP1_CLK_F(off, b, idx, f) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 0, \
+ .sel = _UNKNOWN_SEL, \
+ .fixed = (f), \
+ }
+
+#define STM32MP1_CLK_SET_CLR(off, b, idx, s) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 1, \
+ .sel = (s), \
+ .fixed = _UNKNOWN_ID, \
+ }
+
+#define STM32MP1_CLK_SET_CLR_F(off, b, idx, f) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 1, \
+ .sel = _UNKNOWN_SEL, \
+ .fixed = (f), \
+ }
+
+#define STM32MP1_CLK_PARENT(idx, off, s, m, p) \
+ [(idx)] = { \
+ .offset = (off), \
+ .src = (s), \
+ .msk = (m), \
+ .parent = (p), \
+ .nb_parent = ARRAY_SIZE((p)) \
+ }
+
+#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3, off4, off5, off6,\
+ p1, p2, p3, p4) \
+ [(idx)] = { \
+ .plltype = (type), \
+ .rckxselr = (off1), \
+ .pllxcfgr1 = (off2), \
+ .pllxcfgr2 = (off3), \
+ .pllxfracr = (off4), \
+ .pllxcr = (off5), \
+ .pllxcsgr = (off6), \
+ .refclk[0] = (p1), \
+ .refclk[1] = (p2), \
+ .refclk[2] = (p3), \
+ .refclk[3] = (p4), \
+ }
+
+static const u8 stm32mp1_clks[][2] = {
+ {CK_PER, _CK_PER},
+ {CK_MPU, _CK_MPU},
+ {CK_AXI, _ACLK},
+ {CK_MCU, _CK_MCU},
+ {CK_HSE, _HSE},
+ {CK_CSI, _CSI},
+ {CK_LSI, _LSI},
+ {CK_LSE, _LSE},
+ {CK_HSI, _HSI},
+ {CK_HSE_DIV2, _HSE_KER_DIV2},
+};
+
+static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
+ STM32MP1_CLK(RCC_DDRITFCR, 0, DDRC1, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 1, DDRC1LP, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 2, DDRC2, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 3, DDRC2LP, _UNKNOWN_SEL),
+ STM32MP1_CLK_F(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
+ STM32MP1_CLK(RCC_DDRITFCR, 5, DDRPHYCLP, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 6, DDRCAPB, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 7, DDRCAPBLP, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 8, AXIDCG, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL),
+ STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL),
+
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 8, ETHTX, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 9, ETHRX, _UNKNOWN_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 10, ETHMAC_K, _ETH_SEL),
+ STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
+
+ STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
+};
+
+static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
+static const u8 i2c35_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
+static const u8 i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER};
+static const u8 uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER,
+ _HSE_KER};
+static const u8 uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
+ _HSE_KER};
+static const u8 uart35_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
+ _HSE_KER};
+static const u8 uart78_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
+ _HSE_KER};
+static const u8 sdmmc12_parents[] = {_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER};
+static const u8 sdmmc3_parents[] = {_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER};
+static const u8 eth_parents[] = {_PLL4_P, _PLL3_Q};
+static const u8 qspi_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER};
+static const u8 fmc_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER};
+static const u8 usbphy_parents[] = {_HSE_KER, _PLL4_R, _HSE_KER_DIV2};
+static const u8 usbo_parents[] = {_PLL4_R, _USB_PHY_48};
+static const u8 stgen_parents[] = {_HSI_KER, _HSE_KER};
+
+static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
+ STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents),
+ STM32MP1_CLK_PARENT(_I2C35_SEL, RCC_I2C35CKSELR, 0, 0x7, i2c35_parents),
+ STM32MP1_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents),
+ STM32MP1_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents),
+ STM32MP1_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7,
+ uart24_parents),
+ STM32MP1_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7,
+ uart35_parents),
+ STM32MP1_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7,
+ uart78_parents),
+ STM32MP1_CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7,
+ sdmmc12_parents),
+ STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7,
+ sdmmc3_parents),
+ STM32MP1_CLK_PARENT(_ETH_SEL, RCC_ETHCKSELR, 0, 0x3, eth_parents),
+ STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents),
+ STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents),
+ STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents),
+ STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
+ STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents),
+};
+
+#ifdef STM32MP1_CLOCK_TREE_INIT
+/* define characteristic of PLL according type */
+#define DIVN_MIN 24
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+ [PLL_800] = {
+ .refclk_min = 4,
+ .refclk_max = 16,
+ .divn_max = 99,
+ },
+ [PLL_1600] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ .divn_max = 199,
+ },
+};
+#endif /* STM32MP1_CLOCK_TREE_INIT */
+
+static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
+ STM32MP1_CLK_PLL(_PLL1, PLL_1600,
+ RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
+ RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
+ _HSI, _HSE, _UNKNOWN_ID, _UNKNOWN_ID),
+ STM32MP1_CLK_PLL(_PLL2, PLL_1600,
+ RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
+ RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
+ _HSI, _HSE, _UNKNOWN_ID, _UNKNOWN_ID),
+ STM32MP1_CLK_PLL(_PLL3, PLL_800,
+ RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
+ RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
+ _HSI, _HSE, _CSI, _UNKNOWN_ID),
+ STM32MP1_CLK_PLL(_PLL4, PLL_800,
+ RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
+ RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
+ _HSI, _HSE, _CSI, _I2S_CKIN),
+};
+
+/* Prescaler table lookups for clock computation */
+/* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
+static const u8 stm32mp1_mcu_div[16] = {
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
+};
+
+/* div = /1 /2 /4 /8 /16 : same divider for pmu and apbx*/
+#define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
+#define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
+static const u8 stm32mp1_mpu_apbx_div[8] = {
+ 0, 1, 2, 3, 4, 4, 4, 4
+};
+
+/* div = /1 /2 /3 /4 */
+static const u8 stm32mp1_axi_div[8] = {
+ 1, 2, 3, 4, 4, 4, 4, 4
+};
+
+#ifdef DEBUG
+static const char * const stm32mp1_clk_parent_name[_PARENT_NB] = {
+ [_HSI] = "HSI",
+ [_HSE] = "HSE",
+ [_CSI] = "CSI",
+ [_LSI] = "LSI",
+ [_LSE] = "LSE",
+ [_I2S_CKIN] = "I2S_CKIN",
+ [_HSI_KER] = "HSI_KER",
+ [_HSE_KER] = "HSE_KER",
+ [_HSE_KER_DIV2] = "HSE_KER_DIV2",
+ [_CSI_KER] = "CSI_KER",
+ [_PLL1_P] = "PLL1_P",
+ [_PLL1_Q] = "PLL1_Q",
+ [_PLL1_R] = "PLL1_R",
+ [_PLL2_P] = "PLL2_P",
+ [_PLL2_Q] = "PLL2_Q",
+ [_PLL2_R] = "PLL2_R",
+ [_PLL3_P] = "PLL3_P",
+ [_PLL3_Q] = "PLL3_Q",
+ [_PLL3_R] = "PLL3_R",
+ [_PLL4_P] = "PLL4_P",
+ [_PLL4_Q] = "PLL4_Q",
+ [_PLL4_R] = "PLL4_R",
+ [_ACLK] = "ACLK",
+ [_PCLK1] = "PCLK1",
+ [_PCLK2] = "PCLK2",
+ [_PCLK3] = "PCLK3",
+ [_PCLK4] = "PCLK4",
+ [_PCLK5] = "PCLK5",
+ [_HCLK6] = "KCLK6",
+ [_HCLK2] = "HCLK2",
+ [_CK_PER] = "CK_PER",
+ [_CK_MPU] = "CK_MPU",
+ [_CK_MCU] = "CK_MCU",
+ [_USB_PHY_48] = "USB_PHY_48"
+};
+
+static const char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = {
+ [_I2C12_SEL] = "I2C12",
+ [_I2C35_SEL] = "I2C35",
+ [_I2C46_SEL] = "I2C46",
+ [_UART6_SEL] = "UART6",
+ [_UART24_SEL] = "UART24",
+ [_UART35_SEL] = "UART35",
+ [_UART78_SEL] = "UART78",
+ [_SDMMC12_SEL] = "SDMMC12",
+ [_SDMMC3_SEL] = "SDMMC3",
+ [_ETH_SEL] = "ETH",
+ [_QSPI_SEL] = "QSPI",
+ [_FMC_SEL] = "FMC",
+ [_USBPHY_SEL] = "USBPHY",
+ [_USBO_SEL] = "USBO",
+ [_STGEN_SEL] = "STGEN"
+};
+#endif
+
+static const struct stm32mp1_clk_data stm32mp1_data = {
+ .gate = stm32mp1_clk_gate,
+ .sel = stm32mp1_clk_sel,
+ .pll = stm32mp1_clk_pll,
+ .nb_gate = ARRAY_SIZE(stm32mp1_clk_gate),
+};
+
+static ulong stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, int idx)
+{
+ if (idx >= NB_OSC) {
+ debug("%s: clk id %d not found\n", __func__, idx);
+ return 0;
+ }
+
+ debug("%s: clk id %d = %x : %ld kHz\n", __func__, idx,
+ (u32)priv->osc[idx], priv->osc[idx] / 1000);
+
+ return priv->osc[idx];
+}
+
+static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id)
+{
+ const struct stm32mp1_clk_gate *gate = priv->data->gate;
+ int i, nb_clks = priv->data->nb_gate;
+
+ for (i = 0; i < nb_clks; i++) {
+ if (gate[i].index == id)
+ break;
+ }
+
+ if (i == nb_clks) {
+ printf("%s: clk id %d not found\n", __func__, (u32)id);
+ return -EINVAL;
+ }
+
+ return i;
+}
+
+static int stm32mp1_clk_get_sel(struct stm32mp1_clk_priv *priv,
+ int i)
+{
+ const struct stm32mp1_clk_gate *gate = priv->data->gate;
+
+ if (gate[i].sel > _PARENT_SEL_NB) {
+ printf("%s: parents for clk id %d not found\n",
+ __func__, i);
+ return -EINVAL;
+ }
+
+ return gate[i].sel;
+}
+
+static int stm32mp1_clk_get_fixed_parent(struct stm32mp1_clk_priv *priv,
+ int i)
+{
+ const struct stm32mp1_clk_gate *gate = priv->data->gate;
+
+ if (gate[i].fixed == _UNKNOWN_ID)
+ return -ENOENT;
+
+ return gate[i].fixed;
+}
+
+static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv,
+ unsigned long id)
+{
+ const struct stm32mp1_clk_sel *sel = priv->data->sel;
+ int i;
+ int s, p;
+
+ for (i = 0; i < ARRAY_SIZE(stm32mp1_clks); i++)
+ if (stm32mp1_clks[i][0] == id)
+ return stm32mp1_clks[i][1];
+
+ i = stm32mp1_clk_get_id(priv, id);
+ if (i < 0)
+ return i;
+
+ p = stm32mp1_clk_get_fixed_parent(priv, i);
+ if (p >= 0 && p < _PARENT_NB)
+ return p;
+
+ s = stm32mp1_clk_get_sel(priv, i);
+ if (s < 0)
+ return s;
+
+ p = (readl(priv->base + sel[s].offset) >> sel[s].src) & sel[s].msk;
+
+ if (p < sel[s].nb_parent) {
+#ifdef DEBUG
+ debug("%s: %s clock is the parent %s of clk id %d\n", __func__,
+ stm32mp1_clk_parent_name[sel[s].parent[p]],
+ stm32mp1_clk_parent_sel_name[s],
+ (u32)id);
+#endif
+ return sel[s].parent[p];
+ }
+
+ pr_err("%s: no parents defined for clk id %d\n",
+ __func__, (u32)id);
+
+ return -EINVAL;
+}
+
+static ulong stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv,
+ int pll_id, int div_id)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ int divm, divn, divy, src;
+ ulong refclk, dfout;
+ u32 selr, cfgr1, cfgr2, fracr;
+ const u8 shift[_DIV_NB] = {
+ [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
+ [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
+ [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT };
+
+ debug("%s(%d, %d)\n", __func__, pll_id, div_id);
+ if (div_id > _DIV_NB)
+ return 0;
+
+ selr = readl(priv->base + pll[pll_id].rckxselr);
+ cfgr1 = readl(priv->base + pll[pll_id].pllxcfgr1);
+ cfgr2 = readl(priv->base + pll[pll_id].pllxcfgr2);
+ fracr = readl(priv->base + pll[pll_id].pllxfracr);
+
+ debug("PLL%d : selr=%x cfgr1=%x cfgr2=%x fracr=%x\n",
+ pll_id, selr, cfgr1, cfgr2, fracr);
+
+ divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
+ divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
+ divy = (cfgr2 >> shift[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
+
+ debug(" DIVN=%d DIVM=%d DIVY=%d\n", divn, divm, divy);
+
+ src = selr & RCC_SELR_SRC_MASK;
+ refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]);
+
+ debug(" refclk = %d kHz\n", (u32)(refclk / 1000));
+
+ /*
+ * For: PLL1 & PLL2 => VCO is * 2 but ck_pll_y is also / 2
+ * So same final result than PLL2 et 4
+ * with FRACV :
+ * Fck_pll_y = Fck_ref * ((DIVN + 1) + FRACV / 2^13)
+ * / (DIVM + 1) * (DIVy + 1)
+ * without FRACV
+ * Fck_pll_y = Fck_ref * ((DIVN + 1) / (DIVM + 1) *(DIVy + 1)
+ */
+ if (fracr & RCC_PLLNFRACR_FRACLE) {
+ u32 fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK)
+ >> RCC_PLLNFRACR_FRACV_SHIFT;
+ dfout = (ulong)lldiv((unsigned long long)refclk *
+ (((divn + 1) << 13) + fracv),
+ ((unsigned long long)(divm + 1) *
+ (divy + 1)) << 13);
+ } else {
+ dfout = (ulong)(refclk * (divn + 1) / (divm + 1) * (divy + 1));
+ }
+ debug(" => dfout = %d kHz\n", (u32)(dfout / 1000));
+
+ return dfout;
+}
+
+static ulong stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
+{
+ u32 reg;
+ ulong clock = 0;
+
+ switch (p) {
+ case _CK_MPU:
+ /* MPU sub system */
+ reg = readl(priv->base + RCC_MPCKSELR);
+ switch (reg & RCC_SELR_SRC_MASK) {
+ case RCC_MPCKSELR_HSI:
+ clock = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case RCC_MPCKSELR_HSE:
+ clock = stm32mp1_clk_get_fixed(priv, _HSE);
+ break;
+ case RCC_MPCKSELR_PLL:
+ case RCC_MPCKSELR_PLL_MPUDIV:
+ clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
+ if (p == RCC_MPCKSELR_PLL_MPUDIV) {
+ reg = readl(priv->base + RCC_MPCKDIVR);
+ clock /= stm32mp1_mpu_div[reg &
+ RCC_MPUDIV_MASK];
+ }
+ break;
+ }
+ break;
+ /* AXI sub system */
+ case _ACLK:
+ case _HCLK2:
+ case _HCLK6:
+ case _PCLK4:
+ case _PCLK5:
+ reg = readl(priv->base + RCC_ASSCKSELR);
+ switch (reg & RCC_SELR_SRC_MASK) {
+ case RCC_ASSCKSELR_HSI:
+ clock = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case RCC_ASSCKSELR_HSE:
+ clock = stm32mp1_clk_get_fixed(priv, _HSE);
+ break;
+ case RCC_ASSCKSELR_PLL:
+ clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P);
+ break;
+ }
+
+ /* System clock divider */
+ reg = readl(priv->base + RCC_AXIDIVR);
+ clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
+
+ switch (p) {
+ case _PCLK4:
+ reg = readl(priv->base + RCC_APB4DIVR);
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+ break;
+ case _PCLK5:
+ reg = readl(priv->base + RCC_APB5DIVR);
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+ break;
+ default:
+ break;
+ }
+ break;
+ /* MCU sub system */
+ case _CK_MCU:
+ case _PCLK1:
+ case _PCLK2:
+ case _PCLK3:
+ reg = readl(priv->base + RCC_MSSCKSELR);
+ switch (reg & RCC_SELR_SRC_MASK) {
+ case RCC_MSSCKSELR_HSI:
+ clock = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case RCC_MSSCKSELR_HSE:
+ clock = stm32mp1_clk_get_fixed(priv, _HSE);
+ break;
+ case RCC_MSSCKSELR_CSI:
+ clock = stm32mp1_clk_get_fixed(priv, _CSI);
+ break;
+ case RCC_MSSCKSELR_PLL:
+ clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_P);
+ break;
+ }
+
+ /* MCU clock divider */
+ reg = readl(priv->base + RCC_MCUDIVR);
+ clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
+
+ switch (p) {
+ case _PCLK1:
+ reg = readl(priv->base + RCC_APB1DIVR);
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+ break;
+ case _PCLK2:
+ reg = readl(priv->base + RCC_APB2DIVR);
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+ break;
+ case _PCLK3:
+ reg = readl(priv->base + RCC_APB3DIVR);
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+ break;
+ case _CK_MCU:
+ default:
+ break;
+ }
+ break;
+ case _CK_PER:
+ reg = readl(priv->base + RCC_CPERCKSELR);
+ switch (reg & RCC_SELR_SRC_MASK) {
+ case RCC_CPERCKSELR_HSI:
+ clock = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case RCC_CPERCKSELR_HSE:
+ clock = stm32mp1_clk_get_fixed(priv, _HSE);
+ break;
+ case RCC_CPERCKSELR_CSI:
+ clock = stm32mp1_clk_get_fixed(priv, _CSI);
+ break;
+ }
+ break;
+ case _HSI:
+ case _HSI_KER:
+ clock = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case _CSI:
+ case _CSI_KER:
+ clock = stm32mp1_clk_get_fixed(priv, _CSI);
+ break;
+ case _HSE:
+ case _HSE_KER:
+ case _HSE_KER_DIV2:
+ clock = stm32mp1_clk_get_fixed(priv, _HSE);
+ if (p == _HSE_KER_DIV2)
+ clock >>= 1;
+ break;
+ case _LSI:
+ clock = stm32mp1_clk_get_fixed(priv, _LSI);
+ break;
+ case _LSE:
+ clock = stm32mp1_clk_get_fixed(priv, _LSE);
+ break;
+ /* PLL */
+ case _PLL1_P:
+ case _PLL1_Q:
+ case _PLL1_R:
+ clock = stm32mp1_read_pll_freq(priv, _PLL1, p - _PLL1_P);
+ break;
+ case _PLL2_P:
+ case _PLL2_Q:
+ case _PLL2_R:
+ clock = stm32mp1_read_pll_freq(priv, _PLL2, p - _PLL2_P);
+ break;
+ case _PLL3_P:
+ case _PLL3_Q:
+ case _PLL3_R:
+ clock = stm32mp1_read_pll_freq(priv, _PLL3, p - _PLL3_P);
+ break;
+ case _PLL4_P:
+ case _PLL4_Q:
+ case _PLL4_R:
+ clock = stm32mp1_read_pll_freq(priv, _PLL4, p - _PLL4_P);
+ break;
+ /* other */
+ case _USB_PHY_48:
+ clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48);
+ break;
+
+ default:
+ break;
+ }
+
+ debug("%s(%d) clock = %lx : %ld kHz\n",
+ __func__, p, clock, clock / 1000);
+
+ return clock;
+}
+
+static int stm32mp1_clk_enable(struct clk *clk)
+{
+ struct stm32mp1_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct stm32mp1_clk_gate *gate = priv->data->gate;
+ int i = stm32mp1_clk_get_id(priv, clk->id);
+
+ if (i < 0)
+ return i;
+
+ if (gate[i].set_clr)
+ writel(BIT(gate[i].bit), priv->base + gate[i].offset);
+ else
+ setbits_le32(priv->base + gate[i].offset, BIT(gate[i].bit));
+
+ debug("%s: id clock %d has been enabled\n", __func__, (u32)clk->id);
+
+ return 0;
+}
+
+static int stm32mp1_clk_disable(struct clk *clk)
+{
+ struct stm32mp1_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct stm32mp1_clk_gate *gate = priv->data->gate;
+ int i = stm32mp1_clk_get_id(priv, clk->id);
+
+ if (i < 0)
+ return i;
+
+ if (gate[i].set_clr)
+ writel(BIT(gate[i].bit),
+ priv->base + gate[i].offset
+ + RCC_MP_ENCLRR_OFFSET);
+ else
+ clrbits_le32(priv->base + gate[i].offset, BIT(gate[i].bit));
+
+ debug("%s: id clock %d has been disabled\n", __func__, (u32)clk->id);
+
+ return 0;
+}
+
+static ulong stm32mp1_clk_get_rate(struct clk *clk)
+{
+ struct stm32mp1_clk_priv *priv = dev_get_priv(clk->dev);
+ int p = stm32mp1_clk_get_parent(priv, clk->id);
+ ulong rate;
+
+ if (p < 0)
+ return 0;
+
+ rate = stm32mp1_clk_get(priv, p);
+
+#ifdef DEBUG
+ debug("%s: computed rate for id clock %d is %d (parent is %s)\n",
+ __func__, (u32)clk->id, (u32)rate, stm32mp1_clk_parent_name[p]);
+#endif
+ return rate;
+}
+
+#ifdef STM32MP1_CLOCK_TREE_INIT
+static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset,
+ u32 mask_on)
+{
+ u32 address = rcc + offset;
+
+ if (enable)
+ setbits_le32(address, mask_on);
+ else
+ clrbits_le32(address, mask_on);
+}
+
+static void stm32mp1_hs_ocs_set(int enable, fdt_addr_t rcc, u32 mask_on)
+{
+ if (enable)
+ setbits_le32(rcc + RCC_OCENSETR, mask_on);
+ else
+ setbits_le32(rcc + RCC_OCENCLRR, mask_on);
+}
+
+static int stm32mp1_osc_wait(int enable, fdt_addr_t rcc, u32 offset,
+ u32 mask_rdy)
+{
+ u32 mask_test = 0;
+ u32 address = rcc + offset;
+ u32 val;
+ int ret;
+
+ if (enable)
+ mask_test = mask_rdy;
+
+ ret = readl_poll_timeout(address, val,
+ (val & mask_rdy) == mask_test,
+ TIMEOUT_1S);
+
+ if (ret)
+ pr_err("OSC %x @ %x timeout for enable=%d : 0x%x\n",
+ mask_rdy, address, enable, readl(address));
+
+ return ret;
+}
+
+static void stm32mp1_lse_enable(fdt_addr_t rcc, int bypass, int lsedrv)
+{
+ u32 value;
+
+ if (bypass)
+ setbits_le32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP);
+
+ /*
+ * warning: not recommended to switch directly from "high drive"
+ * to "medium low drive", and vice-versa.
+ */
+ value = (readl(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK)
+ >> RCC_BDCR_LSEDRV_SHIFT;
+
+ while (value != lsedrv) {
+ if (value > lsedrv)
+ value--;
+ else
+ value++;
+
+ clrsetbits_le32(rcc + RCC_BDCR,
+ RCC_BDCR_LSEDRV_MASK,
+ value << RCC_BDCR_LSEDRV_SHIFT);
+ }
+
+ stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON);
+}
+
+static void stm32mp1_lse_wait(fdt_addr_t rcc)
+{
+ stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY);
+}
+
+static void stm32mp1_lsi_set(fdt_addr_t rcc, int enable)
+{
+ stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION);
+ stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY);
+}
+
+static void stm32mp1_hse_enable(fdt_addr_t rcc, int bypass, int css)
+{
+ if (bypass)
+ setbits_le32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP);
+
+ stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON);
+ stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY);
+
+ if (css)
+ setbits_le32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON);
+}
+
+static void stm32mp1_csi_set(fdt_addr_t rcc, int enable)
+{
+ stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION);
+ stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY);
+}
+
+static void stm32mp1_hsi_set(fdt_addr_t rcc, int enable)
+{
+ stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION);
+ stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY);
+}
+
+static int stm32mp1_set_hsidiv(fdt_addr_t rcc, u8 hsidiv)
+{
+ u32 address = rcc + RCC_OCRDYR;
+ u32 val;
+ int ret;
+
+ clrsetbits_le32(rcc + RCC_HSICFGR,
+ RCC_HSICFGR_HSIDIV_MASK,
+ RCC_HSICFGR_HSIDIV_MASK & hsidiv);
+
+ ret = readl_poll_timeout(address, val,
+ val & RCC_OCRDYR_HSIDIVRDY,
+ TIMEOUT_200MS);
+ if (ret)
+ pr_err("HSIDIV failed @ 0x%x: 0x%x\n",
+ address, readl(address));
+
+ return ret;
+}
+
+static int stm32mp1_hsidiv(fdt_addr_t rcc, ulong hsifreq)
+{
+ u8 hsidiv;
+ u32 hsidivfreq = MAX_HSI_HZ;
+
+ for (hsidiv = 0; hsidiv < 4; hsidiv++,
+ hsidivfreq = hsidivfreq / 2)
+ if (hsidivfreq == hsifreq)
+ break;
+
+ if (hsidiv == 4) {
+ pr_err("clk-hsi frequency invalid");
+ return -1;
+ }
+
+ if (hsidiv > 0)
+ return stm32mp1_set_hsidiv(rcc, hsidiv);
+
+ return 0;
+}
+
+static void pll_start(struct stm32mp1_clk_priv *priv, int pll_id)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+
+ writel(RCC_PLLNCR_PLLON, priv->base + pll[pll_id].pllxcr);
+}
+
+static int pll_output(struct stm32mp1_clk_priv *priv, int pll_id, int output)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ u32 pllxcr = priv->base + pll[pll_id].pllxcr;
+ u32 val;
+ int ret;
+
+ ret = readl_poll_timeout(pllxcr, val, val & RCC_PLLNCR_PLLRDY,
+ TIMEOUT_200MS);
+
+ if (ret) {
+ pr_err("PLL%d start failed @ 0x%x: 0x%x\n",
+ pll_id, pllxcr, readl(pllxcr));
+ return ret;
+ }
+
+ /* start the requested output */
+ setbits_le32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
+
+ return 0;
+}
+
+static int pll_stop(struct stm32mp1_clk_priv *priv, int pll_id)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ u32 pllxcr = priv->base + pll[pll_id].pllxcr;
+ u32 val;
+
+ /* stop all output */
+ clrbits_le32(pllxcr,
+ RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ /* stop PLL */
+ clrbits_le32(pllxcr, RCC_PLLNCR_PLLON);
+
+ /* wait PLL stopped */
+ return readl_poll_timeout(pllxcr, val, (val & RCC_PLLNCR_PLLRDY) == 0,
+ TIMEOUT_200MS);
+}
+
+static void pll_config_output(struct stm32mp1_clk_priv *priv,
+ int pll_id, u32 *pllcfg)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ fdt_addr_t rcc = priv->base;
+ u32 value;
+
+ value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT)
+ & RCC_PLLNCFGR2_DIVP_MASK;
+ value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT)
+ & RCC_PLLNCFGR2_DIVQ_MASK;
+ value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT)
+ & RCC_PLLNCFGR2_DIVR_MASK;
+ writel(value, rcc + pll[pll_id].pllxcfgr2);
+}
+
+static int pll_config(struct stm32mp1_clk_priv *priv, int pll_id,
+ u32 *pllcfg, u32 fracv)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ fdt_addr_t rcc = priv->base;
+ enum stm32mp1_plltype type = pll[pll_id].plltype;
+ int src;
+ ulong refclk;
+ u8 ifrge = 0;
+ u32 value;
+
+ src = readl(priv->base + pll[pll_id].rckxselr) & RCC_SELR_SRC_MASK;
+
+ refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]) /
+ (pllcfg[PLLCFG_M] + 1);
+
+ if (refclk < (stm32mp1_pll[type].refclk_min * 1000000) ||
+ refclk > (stm32mp1_pll[type].refclk_max * 1000000)) {
+ debug("invalid refclk = %x\n", (u32)refclk);
+ return -EINVAL;
+ }
+ if (type == PLL_800 && refclk >= 8000000)
+ ifrge = 1;
+
+ value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT)
+ & RCC_PLLNCFGR1_DIVN_MASK;
+ value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT)
+ & RCC_PLLNCFGR1_DIVM_MASK;
+ value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT)
+ & RCC_PLLNCFGR1_IFRGE_MASK;
+ writel(value, rcc + pll[pll_id].pllxcfgr1);
+
+ /* fractional configuration: load sigma-delta modulator (SDM) */
+
+ /* Write into FRACV the new fractional value , and FRACLE to 0 */
+ writel(fracv << RCC_PLLNFRACR_FRACV_SHIFT,
+ rcc + pll[pll_id].pllxfracr);
+
+ /* Write FRACLE to 1 : FRACV value is loaded into the SDM */
+ setbits_le32(rcc + pll[pll_id].pllxfracr,
+ RCC_PLLNFRACR_FRACLE);
+
+ pll_config_output(priv, pll_id, pllcfg);
+
+ return 0;
+}
+
+static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg)
+{
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ u32 pllxcsg;
+
+ pllxcsg = ((csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
+ RCC_PLLNCSGR_MOD_PER_MASK) |
+ ((csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
+ RCC_PLLNCSGR_INC_STEP_MASK) |
+ ((csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
+ RCC_PLLNCSGR_SSCG_MODE_MASK);
+
+ writel(pllxcsg, priv->base + pll[pll_id].pllxcsgr);
+}
+
+static int set_clksrc(struct stm32mp1_clk_priv *priv, unsigned int clksrc)
+{
+ u32 address = priv->base + (clksrc >> 4);
+ u32 val;
+ int ret;
+
+ clrsetbits_le32(address, RCC_SELR_SRC_MASK, clksrc & RCC_SELR_SRC_MASK);
+ ret = readl_poll_timeout(address, val, val & RCC_SELR_SRCRDY,
+ TIMEOUT_200MS);
+ if (ret)
+ pr_err("CLKSRC %x start failed @ 0x%x: 0x%x\n",
+ clksrc, address, readl(address));
+
+ return ret;
+}
+
+static void stgen_config(struct stm32mp1_clk_priv *priv)
+{
+ int p;
+ u32 stgenc, cntfid0;
+ ulong rate;
+
+ stgenc = (u32)syscon_get_first_range(STM32MP_SYSCON_STGEN);
+
+ cntfid0 = readl(stgenc + STGENC_CNTFID0);
+ p = stm32mp1_clk_get_parent(priv, STGEN_K);
+ rate = stm32mp1_clk_get(priv, p);
+
+ if (cntfid0 != rate) {
+ pr_debug("System Generic Counter (STGEN) update\n");
+ clrbits_le32(stgenc + STGENC_CNTCR, STGENC_CNTCR_EN);
+ writel(0x0, stgenc + STGENC_CNTCVL);
+ writel(0x0, stgenc + STGENC_CNTCVU);
+ writel(rate, stgenc + STGENC_CNTFID0);
+ setbits_le32(stgenc + STGENC_CNTCR, STGENC_CNTCR_EN);
+
+ __asm__ volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (rate));
+
+ /* need to update gd->arch.timer_rate_hz with new frequency */
+ timer_init();
+ pr_debug("gd->arch.timer_rate_hz = %x\n",
+ (u32)gd->arch.timer_rate_hz);
+ pr_debug("Tick = %x\n", (u32)(get_ticks()));
+ }
+}
+
+static int set_clkdiv(unsigned int clkdiv, u32 address)
+{
+ u32 val;
+ int ret;
+
+ clrsetbits_le32(address, RCC_DIVR_DIV_MASK, clkdiv & RCC_DIVR_DIV_MASK);
+ ret = readl_poll_timeout(address, val, val & RCC_DIVR_DIVRDY,
+ TIMEOUT_200MS);
+ if (ret)
+ pr_err("CLKDIV %x start failed @ 0x%x: 0x%x\n",
+ clkdiv, address, readl(address));
+
+ return ret;
+}
+
+static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv,
+ u32 clksrc, u32 clkdiv)
+{
+ u32 address = priv->base + (clksrc >> 4);
+
+ /*
+ * binding clksrc : bit15-4 offset
+ * bit3: disable
+ * bit2-0: MCOSEL[2:0]
+ */
+ if (clksrc & 0x8) {
+ clrbits_le32(address, RCC_MCOCFG_MCOON);
+ } else {
+ clrsetbits_le32(address,
+ RCC_MCOCFG_MCOSRC_MASK,
+ clksrc & RCC_MCOCFG_MCOSRC_MASK);
+ clrsetbits_le32(address,
+ RCC_MCOCFG_MCODIV_MASK,
+ clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
+ setbits_le32(address, RCC_MCOCFG_MCOON);
+ }
+}
+
+static void set_rtcsrc(struct stm32mp1_clk_priv *priv,
+ unsigned int clksrc,
+ int lse_css)
+{
+ u32 address = priv->base + RCC_BDCR;
+
+ if (readl(address) & RCC_BDCR_RTCCKEN)
+ goto skip_rtc;
+
+ if (clksrc == CLK_RTC_DISABLED)
+ goto skip_rtc;
+
+ clrsetbits_le32(address,
+ RCC_BDCR_RTCSRC_MASK,
+ clksrc << RCC_BDCR_RTCSRC_SHIFT);
+
+ setbits_le32(address, RCC_BDCR_RTCCKEN);
+
+skip_rtc:
+ if (lse_css)
+ setbits_le32(address, RCC_BDCR_LSECSSON);
+}
+
+static void pkcs_config(struct stm32mp1_clk_priv *priv, u32 pkcs)
+{
+ u32 address = priv->base + ((pkcs >> 4) & 0xFFF);
+ u32 value = pkcs & 0xF;
+ u32 mask = 0xF;
+
+ if (pkcs & BIT(31)) {
+ mask <<= 4;
+ value <<= 4;
+ }
+ clrsetbits_le32(address, mask, value);
+}
+
+static int stm32mp1_clktree(struct udevice *dev)
+{
+ struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
+ fdt_addr_t rcc = priv->base;
+ unsigned int clksrc[CLKSRC_NB];
+ unsigned int clkdiv[CLKDIV_NB];
+ unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
+ ofnode plloff[_PLL_NB];
+ int ret;
+ int i, len;
+ int lse_css = 0;
+ const u32 *pkcs_cell;
+
+ /* check mandatory field */
+ ret = dev_read_u32_array(dev, "st,clksrc", clksrc, CLKSRC_NB);
+ if (ret < 0) {
+ debug("field st,clksrc invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = dev_read_u32_array(dev, "st,clkdiv", clkdiv, CLKDIV_NB);
+ if (ret < 0) {
+ debug("field st,clkdiv invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* check mandatory field in each pll */
+ for (i = 0; i < _PLL_NB; i++) {
+ char name[12];
+
+ sprintf(name, "st,pll@%d", i);
+ plloff[i] = dev_read_subnode(dev, name);
+ if (!ofnode_valid(plloff[i]))
+ continue;
+ ret = ofnode_read_u32_array(plloff[i], "cfg",
+ pllcfg[i], PLLCFG_NB);
+ if (ret < 0) {
+ debug("field cfg invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+ }
+
+ debug("configuration MCO\n");
+ stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
+ stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
+
+ debug("switch ON osillator\n");
+ /*
+ * switch ON oscillator found in device-tree,
+ * HSI already ON after bootrom
+ */
+ if (priv->osc[_LSI])
+ stm32mp1_lsi_set(rcc, 1);
+
+ if (priv->osc[_LSE]) {
+ int bypass;
+ int lsedrv;
+ struct udevice *dev = priv->osc_dev[_LSE];
+
+ bypass = dev_read_bool(dev, "st,bypass");
+ lse_css = dev_read_bool(dev, "st,css");
+ lsedrv = dev_read_u32_default(dev, "st,drive",
+ LSEDRV_MEDIUM_HIGH);
+
+ stm32mp1_lse_enable(rcc, bypass, lsedrv);
+ }
+
+ if (priv->osc[_HSE]) {
+ int bypass, css;
+ struct udevice *dev = priv->osc_dev[_HSE];
+
+ bypass = dev_read_bool(dev, "st,bypass");
+ css = dev_read_bool(dev, "st,css");
+
+ stm32mp1_hse_enable(rcc, bypass, css);
+ }
+ /* CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
+ * => switch on CSI even if node is not present in device tree
+ */
+ stm32mp1_csi_set(rcc, 1);
+
+ /* come back to HSI */
+ debug("come back to HSI\n");
+ set_clksrc(priv, CLK_MPU_HSI);
+ set_clksrc(priv, CLK_AXI_HSI);
+ set_clksrc(priv, CLK_MCU_HSI);
+
+ debug("pll stop\n");
+ for (i = 0; i < _PLL_NB; i++)
+ pll_stop(priv, i);
+
+ /* configure HSIDIV */
+ debug("configure HSIDIV\n");
+ if (priv->osc[_HSI]) {
+ stm32mp1_hsidiv(rcc, priv->osc[_HSI]);
+ stgen_config(priv);
+ }
+
+ /* select DIV */
+ debug("select DIV\n");
+ /* no ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
+ writel(clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK, rcc + RCC_MPCKDIVR);
+ set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR);
+ set_clkdiv(clkdiv[CLKDIV_MCU], rcc + RCC_MCUDIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR);
+
+ /* no ready bit for RTC */
+ writel(clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK, rcc + RCC_RTCDIVR);
+
+ /* configure PLLs source */
+ debug("configure PLLs source\n");
+ set_clksrc(priv, clksrc[CLKSRC_PLL12]);
+ set_clksrc(priv, clksrc[CLKSRC_PLL3]);
+ set_clksrc(priv, clksrc[CLKSRC_PLL4]);
+
+ /* configure and start PLLs */
+ debug("configure PLLs\n");
+ for (i = 0; i < _PLL_NB; i++) {
+ u32 fracv;
+ u32 csg[PLLCSG_NB];
+
+ debug("configure PLL %d @ %d\n", i,
+ ofnode_to_offset(plloff[i]));
+ if (!ofnode_valid(plloff[i]))
+ continue;
+
+ fracv = ofnode_read_u32_default(plloff[i], "frac", 0);
+ pll_config(priv, i, pllcfg[i], fracv);
+ ret = ofnode_read_u32_array(plloff[i], "csg", csg, PLLCSG_NB);
+ if (!ret) {
+ pll_csg(priv, i, csg);
+ } else if (ret != -FDT_ERR_NOTFOUND) {
+ debug("invalid csg node for pll@%d res=%d\n", i, ret);
+ return ret;
+ }
+ pll_start(priv, i);
+ }
+
+ /* wait and start PLLs ouptut when ready */
+ for (i = 0; i < _PLL_NB; i++) {
+ if (!ofnode_valid(plloff[i]))
+ continue;
+ debug("output PLL %d\n", i);
+ pll_output(priv, i, pllcfg[i][PLLCFG_O]);
+ }
+
+ /* wait LSE ready before to use it */
+ if (priv->osc[_LSE])
+ stm32mp1_lse_wait(rcc);
+
+ /* configure with expected clock source */
+ debug("CLKSRC\n");
+ set_clksrc(priv, clksrc[CLKSRC_MPU]);
+ set_clksrc(priv, clksrc[CLKSRC_AXI]);
+ set_clksrc(priv, clksrc[CLKSRC_MCU]);
+ set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css);
+
+ /* configure PKCK */
+ debug("PKCK\n");
+ pkcs_cell = dev_read_prop(dev, "st,pkcs", &len);
+ if (pkcs_cell) {
+ bool ckper_disabled = false;
+
+ for (i = 0; i < len / sizeof(u32); i++) {
+ u32 pkcs = (u32)fdt32_to_cpu(pkcs_cell[i]);
+
+ if (pkcs == CLK_CKPER_DISABLED) {
+ ckper_disabled = true;
+ continue;
+ }
+ pkcs_config(priv, pkcs);
+ }
+ /* CKPER is source for some peripheral clock
+ * (FMC-NAND / QPSI-NOR) and switching source is allowed
+ * only if previous clock is still ON
+ * => deactivated CKPER only after switching clock
+ */
+ if (ckper_disabled)
+ pkcs_config(priv, CLK_CKPER_DISABLED);
+ }
+
+ /* STGEN clock source can change with CLK_STGEN_XXX */
+ stgen_config(priv);
+
+ debug("oscillator off\n");
+ /* switch OFF HSI if not found in device-tree */
+ if (!priv->osc[_HSI])
+ stm32mp1_hsi_set(rcc, 0);
+
+ /* Software Self-Refresh mode (SSR) during DDR initilialization */
+ clrsetbits_le32(priv->base + RCC_DDRITFCR,
+ RCC_DDRITFCR_DDRCKMOD_MASK,
+ RCC_DDRITFCR_DDRCKMOD_SSR <<
+ RCC_DDRITFCR_DDRCKMOD_SHIFT);
+
+ return 0;
+}
+#endif /* STM32MP1_CLOCK_TREE_INIT */
+
+static void stm32mp1_osc_clk_init(const char *name,
+ struct stm32mp1_clk_priv *priv,
+ int index)
+{
+ struct clk clk;
+ struct udevice *dev = NULL;
+
+ priv->osc[index] = 0;
+ clk.id = 0;
+ if (!uclass_get_device_by_name(UCLASS_CLK, name, &dev)) {
+ if (clk_request(dev, &clk))
+ pr_err("%s request", name);
+ else
+ priv->osc[index] = clk_get_rate(&clk);
+ }
+ priv->osc_dev[index] = dev;
+}
+
+static void stm32mp1_osc_init(struct udevice *dev)
+{
+ struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
+ int i;
+ const char *name[NB_OSC] = {
+ [_LSI] = "clk-lsi",
+ [_LSE] = "clk-lse",
+ [_HSI] = "clk-hsi",
+ [_HSE] = "clk-hse",
+ [_CSI] = "clk-csi",
+ [_I2S_CKIN] = "i2s_ckin",
+ [_USB_PHY_48] = "ck_usbo_48m"};
+
+ for (i = 0; i < NB_OSC; i++) {
+ stm32mp1_osc_clk_init(name[i], priv, i);
+ debug("%d: %s => %x\n", i, name[i], (u32)priv->osc[i]);
+ }
+}
+
+static int stm32mp1_clk_probe(struct udevice *dev)
+{
+ int result = 0;
+ struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev->parent);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->data = (void *)&stm32mp1_data;
+
+ if (!priv->data->gate || !priv->data->sel ||
+ !priv->data->pll)
+ return -EINVAL;
+
+ stm32mp1_osc_init(dev);
+
+#ifdef STM32MP1_CLOCK_TREE_INIT
+ /* clock tree init is done only one time, before relocation */
+ if (!(gd->flags & GD_FLG_RELOC))
+ result = stm32mp1_clktree(dev);
+#endif
+
+ return result;
+}
+
+static const struct clk_ops stm32mp1_clk_ops = {
+ .enable = stm32mp1_clk_enable,
+ .disable = stm32mp1_clk_disable,
+ .get_rate = stm32mp1_clk_get_rate,
+};
+
+static const struct udevice_id stm32mp1_clk_ids[] = {
+ { .compatible = "st,stm32mp1-rcc-clk" },
+ { }
+};
+
+U_BOOT_DRIVER(stm32mp1_clock) = {
+ .name = "stm32mp1_clk",
+ .id = UCLASS_CLK,
+ .of_match = stm32mp1_clk_ids,
+ .ops = &stm32mp1_clk_ops,
+ .priv_auto_alloc_size = sizeof(struct stm32mp1_clk_priv),
+ .probe = stm32mp1_clk_probe,
+};
diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c
index 50f2a65c20..3845e07309 100644
--- a/drivers/clk/clk_zynq.c
+++ b/drivers/clk/clk_zynq.c
@@ -394,7 +394,7 @@ static ulong zynq_clk_get_rate(struct clk *clk)
return zynq_clk_get_peripheral_rate(priv, id, two_divs);
case dma_clk:
return zynq_clk_get_cpu_rate(priv, cpu_2x_clk);
- case usb0_aper_clk ... smc_aper_clk:
+ case usb0_aper_clk ... swdt_clk:
return zynq_clk_get_cpu_rate(priv, cpu_1x_clk);
default:
return -ENXIO;
diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c
index bcc62904f1..d0d6c898bc 100644
--- a/drivers/clk/clk_zynqmp.c
+++ b/drivers/clk/clk_zynqmp.c
@@ -226,6 +226,18 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRL_APB_CAN0_REF_CTRL;
case can1_ref:
return CRL_APB_CAN1_REF_CTRL;
+ case pl0:
+ return CRL_APB_PL0_REF_CTRL;
+ case pl1:
+ return CRL_APB_PL1_REF_CTRL;
+ case pl2:
+ return CRL_APB_PL2_REF_CTRL;
+ case pl3:
+ return CRL_APB_PL3_REF_CTRL;
+ case wdt:
+ return CRF_APB_TOPSW_LSBUS_CTRL;
+ case iopll_to_fpd:
+ return CRL_APB_IOPLL_TO_FPD_CTRL;
default:
debug("Invalid clk id%d\n", id);
}
@@ -278,6 +290,22 @@ static enum zynqmp_clk zynqmp_clk_get_peripheral_pll(u32 clk_ctrl)
}
}
+static enum zynqmp_clk zynqmp_clk_get_wdt_pll(u32 clk_ctrl)
+{
+ u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
+ CLK_CTRL_SRCSEL_SHIFT;
+
+ switch (srcsel) {
+ case 2:
+ return iopll_to_fpd;
+ case 3:
+ return dpll;
+ case 0 ... 1:
+ default:
+ return apll;
+ }
+}
+
static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
struct zynqmp_clk_priv *priv,
bool is_pre_src)
@@ -420,6 +448,49 @@ static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
DIV_ROUND_CLOSEST(pllrate, div0), div1);
}
+static ulong zynqmp_clk_get_wdt_rate(struct zynqmp_clk_priv *priv,
+ enum zynqmp_clk id, bool two_divs)
+{
+ enum zynqmp_clk pll;
+ u32 clk_ctrl, div0;
+ u32 div1 = 1;
+ int ret;
+ ulong pllrate;
+
+ ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
+ if (ret) {
+ printf("%d %s mio read fail\n", __LINE__, __func__);
+ return -EIO;
+ }
+
+ div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ if (!div0)
+ div0 = 1;
+
+ pll = zynqmp_clk_get_wdt_pll(clk_ctrl);
+ if (two_divs) {
+ ret = zynqmp_mmio_read(zynqmp_clk_get_register(pll), &clk_ctrl);
+ if (ret) {
+ printf("%d %s mio read fail\n", __LINE__, __func__);
+ return -EIO;
+ }
+ div1 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ if (!div1)
+ div1 = 1;
+ }
+
+ if (pll == iopll_to_fpd)
+ pll = iopll;
+
+ pllrate = zynqmp_clk_get_pll_rate(priv, pll);
+ if (IS_ERR_VALUE(pllrate))
+ return pllrate;
+
+ return
+ DIV_ROUND_CLOSEST(
+ DIV_ROUND_CLOSEST(pllrate, div0), div1);
+}
+
static unsigned long zynqmp_clk_calc_peripheral_two_divs(ulong rate,
ulong pll_rate,
u32 *div0, u32 *div1)
@@ -510,8 +581,12 @@ static ulong zynqmp_clk_get_rate(struct clk *clk)
return zynqmp_clk_get_ddr_rate(priv);
case gem0_ref ... gem3_ref:
case qspi_ref ... can1_ref:
+ case pl0 ... pl3:
two_divs = true;
return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
+ case wdt:
+ two_divs = true;
+ return zynqmp_clk_get_wdt_rate(priv, id, two_divs);
default:
return -ENXIO;
}
@@ -627,6 +702,7 @@ static struct clk_ops zynqmp_clk_ops = {
};
static const struct udevice_id zynqmp_clk_ids[] = {
+ { .compatible = "xlnx,zynqmp-clk" },
{ .compatible = "xlnx,zynqmp-clkc" },
{ }
};
diff --git a/drivers/clk/renesas/r8a7790-cpg-mssr.c b/drivers/clk/renesas/r8a7790-cpg-mssr.c
index 33ab9ad7cc..360c02c5fd 100644
--- a/drivers/clk/renesas/r8a7790-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7790-cpg-mssr.c
@@ -40,7 +40,7 @@ enum clk_ids {
MOD_CLK_BASE
};
-static const struct cpg_core_clk r8a7790_core_clks[] __initconst = {
+static const struct cpg_core_clk r8a7790_core_clks[] = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("usb_extal", CLK_USB_EXTAL),
@@ -90,7 +90,7 @@ static const struct cpg_core_clk r8a7790_core_clks[] __initconst = {
DEF_DIV6P1("ssprs", R8A7790_CLK_SSPRS, CLK_PLL1_DIV2, 0x24c),
};
-static const struct mssr_mod_clk r8a7790_mod_clks[] __initconst = {
+static const struct mssr_mod_clk r8a7790_mod_clks[] = {
DEF_MOD("msiof0", 0, R8A7790_CLK_MP),
DEF_MOD("vcp1", 100, R8A7790_CLK_ZS),
DEF_MOD("vcp0", 101, R8A7790_CLK_ZS),
@@ -209,10 +209,6 @@ static const struct mssr_mod_clk r8a7790_mod_clks[] __initconst = {
DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
};
-static const unsigned int r8a7790_crit_mod_clks[] __initconst = {
- MOD_CLK_ID(408), /* INTC-SYS (GIC) */
-};
-
/*
* CPG Clock Data
*/
@@ -235,7 +231,7 @@ static const unsigned int r8a7790_crit_mod_clks[] __initconst = {
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
(((md) & BIT(13)) >> 12) | \
(((md) & BIT(19)) >> 19))
-static const struct rcar_gen2_cpg_pll_config cpg_pll_configs[8] __initconst = {
+static const struct rcar_gen2_cpg_pll_config cpg_pll_configs[8] = {
{ 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 },
{ 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 },
};
diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c
index 510a00a3aa..560222b96c 100644
--- a/drivers/clk/rockchip/clk_rk3036.c
+++ b/drivers/clk/rockchip/clk_rk3036.c
@@ -321,7 +321,7 @@ static int rk3036_clk_probe(struct udevice *dev)
{
struct rk3036_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rk3036_cru *)devfdt_get_addr(dev);
+ priv->cru = dev_read_addr_ptr(dev);
rkclk_init(priv->cru);
return 0;
diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c
index 6451c95a32..cfe6abe470 100644
--- a/drivers/clk/rockchip/clk_rk3188.c
+++ b/drivers/clk/rockchip/clk_rk3188.c
@@ -123,7 +123,7 @@ static int rkclk_configure_ddr(struct rk3188_cru *cru, struct rk3188_grf *grf,
unsigned int hz, bool has_bwadj)
{
static const struct pll_div dpll_cfg[] = {
- {.nf = 25, .nr = 2, .no = 1},
+ {.nf = 75, .nr = 1, .no = 6},
{.nf = 400, .nr = 9, .no = 2},
{.nf = 500, .nr = 9, .no = 2},
{.nf = 100, .nr = 3, .no = 1},
@@ -541,7 +541,7 @@ static int rk3188_clk_ofdata_to_platdata(struct udevice *dev)
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct rk3188_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rk3188_cru *)devfdt_get_addr(dev);
+ priv->cru = dev_read_addr_ptr(dev);
#endif
return 0;
diff --git a/drivers/clk/rockchip/clk_rk322x.c b/drivers/clk/rockchip/clk_rk322x.c
index 4e6d2f0834..ebcab73002 100644
--- a/drivers/clk/rockchip/clk_rk322x.c
+++ b/drivers/clk/rockchip/clk_rk322x.c
@@ -475,7 +475,7 @@ static int rk322x_clk_ofdata_to_platdata(struct udevice *dev)
{
struct rk322x_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rk322x_cru *)devfdt_get_addr(dev);
+ priv->cru = dev_read_addr_ptr(dev);
return 0;
}
diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c
index 552a71a82f..3a36d04096 100644
--- a/drivers/clk/rockchip/clk_rk3288.c
+++ b/drivers/clk/rockchip/clk_rk3288.c
@@ -906,7 +906,7 @@ static int rk3288_clk_ofdata_to_platdata(struct udevice *dev)
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct rk3288_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rk3288_cru *)devfdt_get_addr(dev);
+ priv->cru = dev_read_addr_ptr(dev);
#endif
return 0;
diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c
index 2ccc79851c..046b4e4c2f 100644
--- a/drivers/clk/rockchip/clk_rk3328.c
+++ b/drivers/clk/rockchip/clk_rk3328.c
@@ -767,7 +767,7 @@ static int rk3328_clk_ofdata_to_platdata(struct udevice *dev)
{
struct rk3328_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rk3328_cru *)devfdt_get_addr(dev);
+ priv->cru = dev_read_addr_ptr(dev);
return 0;
}
diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c
index 224c81355e..958fc78592 100644
--- a/drivers/clk/rockchip/clk_rv1108.c
+++ b/drivers/clk/rockchip/clk_rv1108.c
@@ -213,7 +213,7 @@ static int rv1108_clk_probe(struct udevice *dev)
{
struct rv1108_clk_priv *priv = dev_get_priv(dev);
- priv->cru = (struct rv1108_cru *)devfdt_get_addr(dev);
+ priv->cru = dev_read_addr_ptr(dev);
rkclk_init(priv->cru);
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index 3847dd836e..9a3b4c312a 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -49,12 +49,17 @@ fdt_addr_t devfdt_get_addr_index(struct udevice *dev, int index)
reg += index * (na + ns);
- /*
- * Use the full-fledged translate function for complex
- * bus setups.
- */
- addr = fdt_translate_address((void *)gd->fdt_blob,
- dev_of_offset(dev), reg);
+ if (ns) {
+ /*
+ * Use the full-fledged translate function for complex
+ * bus setups.
+ */
+ addr = fdt_translate_address((void *)gd->fdt_blob,
+ dev_of_offset(dev), reg);
+ } else {
+ /* Non translatable if #size-cells == 0 */
+ addr = fdt_read_number(reg, na);
+ }
} else {
/*
* Use the "simple" translate function for less complex
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 4e4532651f..5909a25f85 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -227,13 +227,16 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
uint flags;
u64 size;
int na;
+ int ns;
prop_val = of_get_address(ofnode_to_np(node), index, &size,
&flags);
if (!prop_val)
return FDT_ADDR_T_NONE;
- if (IS_ENABLED(CONFIG_OF_TRANSLATE)) {
+ ns = of_n_size_cells(ofnode_to_np(node));
+
+ if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
return of_translate_address(ofnode_to_np(node), prop_val);
} else {
na = of_n_addr_cells(ofnode_to_np(node));
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 3a426ab4b7..9000ed55ca 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -333,7 +333,8 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
{
- int node, ret;
+ int ret;
+ ofnode node;
ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
if (ret) {
@@ -342,13 +343,18 @@ int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
}
/* bind fixed-clock */
- node = ofnode_to_offset(ofnode_path("/clocks"));
+ node = ofnode_path("/clocks");
/* if no DT "clocks" node, no need to go further */
- if (node < 0)
+ if (!ofnode_valid(node))
return ret;
- ret = dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node,
- pre_reloc_only);
+#if CONFIG_IS_ENABLED(OF_LIVE)
+ if (of_live_active())
+ ret = dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only);
+ else
+#endif
+ ret = dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset,
+ pre_reloc_only);
if (ret)
debug("dm_scan_fdt_node() failed: %d\n", ret);
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 1aedaa08f0..628e2e13ff 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -457,6 +457,32 @@ int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
}
#if CONFIG_IS_ENABLED(OF_CONTROL)
+int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ uint phandle;
+
+ phandle = dev_read_phandle(dev);
+
+ if (phandle == phandle_id) {
+ *devp = dev;
+ return uclass_get_device_tail(dev, ret, devp);
+ }
+ }
+
+ return -ENODEV;
+}
+
int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
const char *name, struct udevice **devp)
{
diff --git a/drivers/cpu/bmips_cpu.c b/drivers/cpu/bmips_cpu.c
index 4ad291a56e..6c612bacdc 100644
--- a/drivers/cpu/bmips_cpu.c
+++ b/drivers/cpu/bmips_cpu.c
@@ -50,6 +50,10 @@ DECLARE_GLOBAL_DATA_PTR;
#define DMIPSPLLCFG_6358_N2_SHIFT 29
#define DMIPSPLLCFG_6358_N2_MASK (0x7 << DMIPSPLLCFG_6358_N2_SHIFT)
+#define REG_BCM6362_MISC_STRAPBUS 0x1814
+#define STRAPBUS_6362_FCVO_SHIFT 1
+#define STRAPBUS_6362_FCVO_MASK (0x1f << STRAPBUS_6362_FCVO_SHIFT)
+
#define REG_BCM6368_DDR_DMIPSPLLCFG 0x12a0
#define DMIPSPLLCFG_6368_P1_SHIFT 0
#define DMIPSPLLCFG_6368_P1_MASK (0xf << DMIPSPLLCFG_6368_P1_SHIFT)
@@ -194,6 +198,44 @@ static ulong bcm6358_get_cpu_freq(struct bmips_cpu_priv *priv)
return (16 * 1000000 * n1 * n2) / m1;
}
+static ulong bcm6362_get_cpu_freq(struct bmips_cpu_priv *priv)
+{
+ unsigned int mips_pll_fcvo;
+
+ mips_pll_fcvo = readl_be(priv->regs + REG_BCM6362_MISC_STRAPBUS);
+ mips_pll_fcvo = (mips_pll_fcvo & STRAPBUS_6362_FCVO_MASK)
+ >> STRAPBUS_6362_FCVO_SHIFT;
+
+ switch (mips_pll_fcvo) {
+ case 0x03:
+ case 0x0b:
+ case 0x13:
+ case 0x1b:
+ return 240000000;
+ case 0x04:
+ case 0x0c:
+ case 0x14:
+ case 0x1c:
+ return 160000000;
+ case 0x05:
+ case 0x0e:
+ case 0x16:
+ case 0x1e:
+ case 0x1f:
+ return 400000000;
+ case 0x06:
+ return 440000000;
+ case 0x07:
+ case 0x17:
+ return 384000000;
+ case 0x15:
+ case 0x1d:
+ return 200000000;
+ default:
+ return 320000000;
+ }
+}
+
static ulong bcm6368_get_cpu_freq(struct bmips_cpu_priv *priv)
{
unsigned int tmp, p1, p2, ndiv, m1;
@@ -289,6 +331,12 @@ static const struct bmips_cpu_hw bmips_cpu_bcm6358 = {
.get_cpu_count = bcm6358_get_cpu_count,
};
+static const struct bmips_cpu_hw bmips_cpu_bcm6362 = {
+ .get_cpu_desc = bmips_short_cpu_desc,
+ .get_cpu_freq = bcm6362_get_cpu_freq,
+ .get_cpu_count = bcm6358_get_cpu_count,
+};
+
static const struct bmips_cpu_hw bmips_cpu_bcm6368 = {
.get_cpu_desc = bmips_short_cpu_desc,
.get_cpu_freq = bcm6368_get_cpu_freq,
@@ -395,6 +443,9 @@ static const struct udevice_id bmips_cpu_ids[] = {
.compatible = "brcm,bcm6358-cpu",
.data = (ulong)&bmips_cpu_bcm6358,
}, {
+ .compatible = "brcm,bcm6362-cpu",
+ .data = (ulong)&bmips_cpu_bcm6362,
+ }, {
.compatible = "brcm,bcm6368-cpu",
.data = (ulong)&bmips_cpu_bcm6368,
}, {
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index 6aead27f16..ac01612d75 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -148,20 +148,21 @@ int fpga_add(fpga_type devtype, void *desc)
{
int devnum = FPGA_INVALID_DEVICE;
+ if (!desc) {
+ printf("%s: NULL device descriptor\n", __func__);
+ return devnum;
+ }
+
if (next_desc < 0) {
printf("%s: FPGA support not initialized!\n", __func__);
} else if ((devtype > fpga_min_type) && (devtype < fpga_undefined)) {
- if (desc) {
- if (next_desc < CONFIG_MAX_FPGA_DEVICES) {
- devnum = next_desc;
- desc_table[next_desc].devtype = devtype;
- desc_table[next_desc++].devdesc = desc;
- } else {
- printf("%s: Exceeded Max FPGA device count\n",
- __func__);
- }
+ if (next_desc < CONFIG_MAX_FPGA_DEVICES) {
+ devnum = next_desc;
+ desc_table[next_desc].devtype = devtype;
+ desc_table[next_desc++].devdesc = desc;
} else {
- printf("%s: NULL device descriptor\n", __func__);
+ printf("%s: Exceeded Max FPGA device count\n",
+ __func__);
}
} else {
printf("%s: Unsupported FPGA type %d\n", __func__, devtype);
diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c
index 57a4e6c88e..43e8b2520e 100644
--- a/drivers/fpga/zynqmppl.c
+++ b/drivers/fpga/zynqmppl.c
@@ -11,6 +11,7 @@
#include <zynqmppl.h>
#include <linux/sizes.h>
#include <asm/arch/sys_proto.h>
+#include <memalign.h>
#define DUMMY_WORD 0xffffffff
@@ -195,6 +196,7 @@ static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf,
static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
+ ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1);
u32 swap;
ulong bin_buf;
int ret;
@@ -205,25 +207,37 @@ static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
return FPGA_FAIL;
bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap);
+ bsizeptr = (u32 *)&bsize;
debug("%s called!\n", __func__);
flush_dcache_range(bin_buf, bin_buf + bsize);
-
- if (bsize % 4)
- bsize = bsize / 4 + 1;
- else
- bsize = bsize / 4;
+ flush_dcache_range((ulong)bsizeptr, (ulong)bsizeptr + sizeof(size_t));
buf_lo = (u32)bin_buf;
buf_hi = upper_32_bits(bin_buf);
- ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi, bsize,
- bstype, ret_payload);
+ bstype |= BIT(ZYNQMP_FPGA_BIT_NS);
+ ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi,
+ (u32)(uintptr_t)bsizeptr, bstype, ret_payload);
if (ret)
debug("PL FPGA LOAD fail\n");
return ret;
}
+static int zynqmp_pcap_info(xilinx_desc *desc)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_STATUS, 0, 0, 0,
+ 0, ret_payload);
+ if (!ret)
+ printf("PCAP status\t0x%x\n", ret_payload[1]);
+
+ return ret;
+}
+
struct xilinx_fpga_op zynqmp_op = {
.load = zynqmp_load,
+ .info = zynqmp_pcap_info,
};
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index 2ff716c252..db9bd12992 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -17,6 +17,7 @@
#include <asm/arch/sys_proto.h>
#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000
+#define DEVCFG_CTRL_PCFG_AES_EFUSE_MASK 0x00001000
#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040
#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840
#define DEVCFG_ISR_RX_FIFO_OV 0x00040000
@@ -205,9 +206,24 @@ static int zynq_dma_xfer_init(bitstream_type bstype)
/* Setting PCFG_PROG_B signal to high */
control = readl(&devcfg_base->ctrl);
writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+ /*
+ * Delay is required if AES efuse is selected as
+ * key source.
+ */
+ if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
+ mdelay(5);
+
/* Setting PCFG_PROG_B signal to low */
writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+ /*
+ * Delay is required if AES efuse is selected as
+ * key source.
+ */
+ if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
+ mdelay(5);
+
/* Polling the PCAP_INIT status for Reset */
ts = get_timer(0);
while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) {
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index cc75aece6a..b7e4ffb09d 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -234,7 +234,7 @@ config PIC32_GPIO
config STM32F7_GPIO
bool "ST STM32 GPIO driver"
- depends on DM_GPIO && STM32
+ depends on DM_GPIO && (STM32 || ARCH_STM32MP)
default y
help
Device model driver support for STM32 GPIO controller. It should be
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 9faf3357af..1fbfdef477 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -655,7 +655,7 @@ static int gpio_request_tail(int ret, ofnode node,
ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node,
&desc->dev);
if (ret) {
- debug("%s: uclass_get_device_by_of_offset failed\n", __func__);
+ debug("%s: uclass_get_device_by_ofnode failed\n", __func__);
goto err;
}
ret = gpio_find_and_xlate(desc, args);
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 7243100219..559f29b801 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -345,6 +345,7 @@ U_BOOT_DRIVER(gpio_omap) = {
.bind = omap_gpio_bind,
.probe = omap_gpio_probe,
.priv_auto_alloc_size = sizeof(struct gpio_bank),
+ .flags = DM_FLAG_PRE_RELOC,
};
#endif /* CONFIG_DM_GPIO */
diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c
index a7cfb8c923..376e86cd69 100644
--- a/drivers/gpio/stm32f7_gpio.c
+++ b/drivers/gpio/stm32f7_gpio.c
@@ -16,14 +16,11 @@
#include <linux/errno.h>
#include <linux/io.h>
-#define MAX_SIZE_BANK_NAME 5
#define STM32_GPIOS_PER_BANK 16
#define MODE_BITS(gpio_pin) (gpio_pin * 2)
#define MODE_BITS_MASK 3
#define IN_OUT_BIT_INDEX(gpio_pin) (1UL << (gpio_pin))
-DECLARE_GLOBAL_DATA_PTR;
-
static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
@@ -82,21 +79,19 @@ static int gpio_stm32_probe(struct udevice *dev)
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct stm32_gpio_priv *priv = dev_get_priv(dev);
fdt_addr_t addr;
- char *name;
+ const char *name;
- addr = devfdt_get_addr(dev);
+ addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = (struct stm32_gpio_regs *)addr;
- name = (char *)fdtdec_locate_byte_array(gd->fdt_blob,
- dev_of_offset(dev),
- "st,bank-name",
- MAX_SIZE_BANK_NAME);
+ name = dev_read_string(dev, "st,bank-name");
if (!name)
return -EINVAL;
uc_priv->bank_name = name;
- uc_priv->gpio_count = STM32_GPIOS_PER_BANK;
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios",
+ STM32_GPIOS_PER_BANK);
debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs,
uc_priv->bank_name);
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 3cf01b6e36..ea6f3593b9 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -354,12 +354,15 @@ static const struct udevice_id sunxi_gpio_ids[] = {
ID("allwinner,sun8i-a83t-pinctrl", a_all),
ID("allwinner,sun8i-h3-pinctrl", a_all),
ID("allwinner,sun8i-r40-pinctrl", a_all),
+ ID("allwinner,sun8i-v3s-pinctrl", a_all),
ID("allwinner,sun9i-a80-pinctrl", a_all),
+ ID("allwinner,sun50i-a64-pinctrl", a_all),
ID("allwinner,sun6i-a31-r-pinctrl", l_2),
ID("allwinner,sun8i-a23-r-pinctrl", l_1),
ID("allwinner,sun8i-a83t-r-pinctrl", l_1),
ID("allwinner,sun8i-h3-r-pinctrl", l_1),
ID("allwinner,sun9i-a80-r-pinctrl", l_3),
+ ID("allwinner,sun50i-a64-r-pinctrl", l_1),
{ }
};
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 286ae487ca..7fb201d8e6 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -370,7 +370,7 @@ config SYS_I2C_S3C24X0
config SYS_I2C_STM32F7
bool "STMicroelectronics STM32F7 I2C support"
- depends on (STM32F7 || STM32H7) && DM_I2C
+ depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C
help
Enable this option to add support for STM32 I2C controller
introduced with STM32F7/H7 SoCs. This I2C controller supports :
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index cb0f5ea233..450a91ded6 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -12,6 +12,7 @@
#include <i2c.h> /* Functional interface */
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
+#include <clk.h>
#include <dm.h>
#include <mapmem.h>
@@ -573,11 +574,9 @@ static int fsl_i2c_set_bus_speed(struct udevice *bus, uint speed)
static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
- fdt_addr_t addr;
+ struct clk clock;
- addr = dev_read_u32_default(bus, "reg", -1);
-
- dev->base = map_sysmem(CONFIG_SYS_IMMR + addr, sizeof(struct fsl_i2c_base));
+ dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct fsl_i2c_base));
if (!dev->base)
return -ENOMEM;
@@ -587,7 +586,11 @@ static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
0x7f);
dev->speed = dev_read_u32_default(bus, "clock-frequency", 400000);
- dev->i2c_clk = dev->index ? gd->arch.i2c2_clk : gd->arch.i2c1_clk;
+ if (!clk_get_by_index(bus, 0, &clock))
+ dev->i2c_clk = clk_get_rate(&clock);
+ else
+ dev->i2c_clk = dev->index ? gd->arch.i2c2_clk :
+ gd->arch.i2c1_clk;
return 0;
}
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 920811a075..4ac6ef84f5 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -11,9 +11,19 @@
#include <malloc.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#ifdef CONFIG_DM_GPIO
+#include <asm/gpio.h>
+#endif
#define I2C_MAX_OFFSET_LEN 4
+enum {
+ PIN_SDA = 0,
+ PIN_SCL,
+ PIN_COUNT,
+};
+
/* Useful debugging function */
void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
{
@@ -445,20 +455,110 @@ int i2c_get_chip_offset_len(struct udevice *dev)
return chip->offset_len;
}
+#ifdef CONFIG_DM_GPIO
+static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
+{
+ if (bit)
+ dm_gpio_set_dir_flags(pin, GPIOD_IS_IN);
+ else
+ dm_gpio_set_dir_flags(pin, GPIOD_IS_OUT |
+ GPIOD_ACTIVE_LOW |
+ GPIOD_IS_OUT_ACTIVE);
+}
+
+static int i2c_gpio_get_pin(struct gpio_desc *pin)
+{
+ return dm_gpio_get_value(pin);
+}
+
+static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
+ struct gpio_desc *scl_pin)
+{
+ int counter = 9;
+ int ret = 0;
+
+ i2c_gpio_set_pin(sda_pin, 1);
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(5);
+
+ /* Toggle SCL until slave release SDA */
+ while (counter-- >= 0) {
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(5);
+ i2c_gpio_set_pin(scl_pin, 0);
+ udelay(5);
+ if (i2c_gpio_get_pin(sda_pin))
+ break;
+ }
+
+ /* Then, send I2C stop */
+ i2c_gpio_set_pin(sda_pin, 0);
+ udelay(5);
+
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(5);
+
+ i2c_gpio_set_pin(sda_pin, 1);
+ udelay(5);
+
+ if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
+ ret = -EREMOTEIO;
+
+ return ret;
+}
+
+static int i2c_deblock_gpio(struct udevice *bus)
+{
+ struct gpio_desc gpios[PIN_COUNT];
+ int ret, ret0;
+
+ ret = gpio_request_list_by_name(bus, "gpios", gpios,
+ ARRAY_SIZE(gpios), GPIOD_IS_IN);
+ if (ret != ARRAY_SIZE(gpios)) {
+ debug("%s: I2C Node '%s' has no 'gpios' property %s\n",
+ __func__, dev_read_name(bus), bus->name);
+ if (ret >= 0) {
+ gpio_free_list(bus, gpios, ret);
+ ret = -ENOENT;
+ }
+ goto out;
+ }
+
+ ret = pinctrl_select_state(bus, "gpio");
+ if (ret) {
+ debug("%s: I2C Node '%s' has no 'gpio' pinctrl state. %s\n",
+ __func__, dev_read_name(bus), bus->name);
+ goto out_no_pinctrl;
+ }
+
+ ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]);
+
+ ret = pinctrl_select_state(bus, "default");
+ if (ret) {
+ debug("%s: I2C Node '%s' has no 'default' pinctrl state. %s\n",
+ __func__, dev_read_name(bus), bus->name);
+ }
+
+ ret = !ret ? ret0 : ret;
+
+out_no_pinctrl:
+ gpio_free_list(bus, gpios, ARRAY_SIZE(gpios));
+out:
+ return ret;
+}
+#else
+static int i2c_deblock_gpio(struct udevice *bus)
+{
+ return -ENOSYS;
+}
+#endif // CONFIG_DM_GPIO
+
int i2c_deblock(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
- /*
- * We could implement a software deblocking here if we could get
- * access to the GPIOs used by I2C, and switch them to GPIO mode
- * and then back to I2C. This is somewhat beyond our powers in
- * driver model at present, so for now just fail.
- *
- * See https://patchwork.ozlabs.org/patch/399040/
- */
if (!ops->deblock)
- return -ENOSYS;
+ return i2c_deblock_gpio(bus);
return ops->deblock(bus);
}
diff --git a/drivers/i2c/ihs_i2c.c b/drivers/i2c/ihs_i2c.c
index 9298521220..82abb439f0 100644
--- a/drivers/i2c/ihs_i2c.c
+++ b/drivers/i2c/ihs_i2c.c
@@ -99,7 +99,8 @@ static int wait_for_int(bool read)
#endif
#ifdef CONFIG_DM_I2C
- fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
+ fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
+ FPGAMAP_SIZE_16);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
@@ -110,7 +111,8 @@ static int wait_for_int(bool read)
if (ctr++ > 5000)
return 1;
#ifdef CONFIG_DM_I2C
- fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
+ fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
+ FPGAMAP_SIZE_16);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
@@ -128,6 +130,7 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
#endif
{
u16 val;
+ u16 data;
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv *priv = dev_get_priv(dev);
struct udevice *fpga;
@@ -136,13 +139,14 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
#endif
/* Clear interrupt status */
+ data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
#ifdef CONFIG_DM_I2C
- fpgamap_write16(fpga, priv->addr + REG_INTERRUPT_STATUS,
- I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
- fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
+ fpgamap_write(fpga, priv->addr + REG_INTERRUPT_STATUS, &data,
+ FPGAMAP_SIZE_16);
+ fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
+ FPGAMAP_SIZE_16);
#else
- I2C_SET_REG(interrupt_status, I2CINT_ERROR_EV
- | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
+ I2C_SET_REG(interrupt_status, data);
I2C_GET_REG(interrupt_status, &val);
#endif
@@ -153,26 +157,24 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
if (len > 1)
val |= buffer[1] << 8;
#ifdef CONFIG_DM_I2C
- fpgamap_write16(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, val);
+ fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, &val,
+ FPGAMAP_SIZE_16);
#else
I2C_SET_REG(write_mailbox_ext, val);
#endif
}
+ data = I2CMB_NATIVE
+ | (read ? 0 : I2CMB_WRITE)
+ | (chip << 1)
+ | ((len > 1) ? I2CMB_2BYTE : 0)
+ | (is_last ? 0 : I2CMB_HOLD_BUS);
+
#ifdef CONFIG_DM_I2C
- fpgamap_write16(fpga, priv->addr + REG_WRITE_MAILBOX,
- I2CMB_NATIVE
- | (read ? I2CMB_READ : I2CMB_WRITE)
- | (chip << 1)
- | ((len > 1) ? I2CMB_2BYTE : I2CMB_1BYTE)
- | (!is_last ? I2CMB_HOLD_BUS : I2CMB_DONT_HOLD_BUS));
+ fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX, &data,
+ FPGAMAP_SIZE_16);
#else
- I2C_SET_REG(write_mailbox,
- I2CMB_NATIVE
- | (read ? 0 : I2CMB_WRITE)
- | (chip << 1)
- | ((len > 1) ? I2CMB_2BYTE : 0)
- | (is_last ? 0 : I2CMB_HOLD_BUS));
+ I2C_SET_REG(write_mailbox, data);
#endif
#ifdef CONFIG_DM_I2C
@@ -185,7 +187,8 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
/* If we want to read, get the bytes from the mailbox */
if (read) {
#ifdef CONFIG_DM_I2C
- fpgamap_read16(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val);
+ fpgamap_read(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val,
+ FPGAMAP_SIZE_16);
#else
I2C_GET_REG(read_mailbox_ext, &val);
#endif
diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c
index de74e89efd..32d7809dba 100644
--- a/drivers/i2c/imx_lpi2c.c
+++ b/drivers/i2c/imx_lpi2c.c
@@ -156,7 +156,7 @@ static int bus_i2c_receive(struct imx_lpi2c_reg *regs, u8 *rxbuf, int len)
static int bus_i2c_start(struct imx_lpi2c_reg *regs, u8 addr, u8 dir)
{
- lpi2c_status_t result = LPI2C_SUCESS;
+ lpi2c_status_t result;
u32 val;
result = imx_lpci2c_check_busy_bus(regs);
@@ -184,7 +184,7 @@ static int bus_i2c_start(struct imx_lpi2c_reg *regs, u8 addr, u8 dir)
static int bus_i2c_stop(struct imx_lpi2c_reg *regs)
{
- lpi2c_status_t result = LPI2C_SUCESS;
+ lpi2c_status_t result;
u32 status;
result = bus_i2c_wait_for_tx_ready(regs);
@@ -213,7 +213,7 @@ static int bus_i2c_stop(struct imx_lpi2c_reg *regs)
static int bus_i2c_read(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
{
- lpi2c_status_t result = LPI2C_SUCESS;
+ lpi2c_status_t result;
result = bus_i2c_start(regs, chip, 1);
if (result)
@@ -230,7 +230,7 @@ static int bus_i2c_read(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
static int bus_i2c_write(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
{
- lpi2c_status_t result = LPI2C_SUCESS;
+ lpi2c_status_t result;
result = bus_i2c_start(regs, chip, 0);
if (result)
@@ -354,7 +354,7 @@ static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
u32 chip_flags)
{
struct imx_lpi2c_reg *regs;
- lpi2c_status_t result = LPI2C_SUCESS;
+ lpi2c_status_t result;
regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
result = bus_i2c_start(regs, chip, 0);
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index 4fd5551a22..cc9c5ef356 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -25,9 +25,6 @@
#include <asm/arch/gpio.h>
#endif
#endif
-#if defined(CONFIG_8xx)
-#include <asm/io.h>
-#endif
#include <i2c.h>
#if defined(CONFIG_SOFT_I2C_GPIO_SCL)
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
index 86624878e2..81f061aecd 100644
--- a/drivers/i2c/stm32f7_i2c.c
+++ b/drivers/i2c/stm32f7_i2c.c
@@ -533,7 +533,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
if (((sdadel >= sdadel_min) &&
(sdadel <= sdadel_max)) &&
(p != p_prev)) {
- v = kmalloc(sizeof(*v), GFP_KERNEL);
+ v = calloc(1, sizeof(*v));
if (!v)
return -ENOMEM;
@@ -689,7 +689,7 @@ exit:
/* Release list and memory */
list_for_each_entry_safe(v, _v, &solutions, node) {
list_del(&v->node);
- kfree(v);
+ free(v);
}
return ret;
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 9109ac6dba..ee7bfc4d2c 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -12,9 +12,5 @@ obj-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o
obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
obj-$(CONFIG_TWL6030_INPUT) += twl6030.o
obj-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o
-ifdef CONFIG_PS2KBD
-obj-y += keyboard.o pc_keyb.o
-obj-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
-endif
obj-y += input.o
obj-$(CONFIG_$(SPL_)OF_CONTROL) += key_matrix.o
diff --git a/drivers/input/keyboard.c b/drivers/input/keyboard.c
deleted file mode 100644
index 84ee015cb3..0000000000
--- a/drivers/input/keyboard.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/***********************************************************************
- *
- * (C) Copyright 2004
- * DENX Software Engineering
- * Wolfgang Denk, wd@denx.de
- *
- * Keyboard driver
- *
- ***********************************************************************/
-
-#include <common.h>
-#include <console.h>
-#include <input.h>
-
-#include <stdio_dev.h>
-#include <keyboard.h>
-#include <stdio_dev.h>
-
-static struct input_config config;
-
-static int kbd_read_keys(struct input_config *config)
-{
-#if defined(CONFIG_ARCH_MPC8540) || \
- defined(CONFIG_ARCH_MPC8541) || defined(CONFIG_ARCH_MPC8555)
- /* no ISR is used, so received chars must be polled */
- ps2ser_check();
-#endif
-
- return 1;
-}
-
-static int check_leds(int ret)
-{
- int leds;
-
- leds = input_leds_changed(&config);
- if (leds >= 0)
- pckbd_leds(leds);
-
- return ret;
-}
-
-/* test if a character is in the queue */
-static int kbd_testc(struct stdio_dev *dev)
-{
- return check_leds(input_tstc(&config));
-}
-
-/* gets the character from the queue */
-static int kbd_getc(struct stdio_dev *dev)
-{
- return check_leds(input_getc(&config));
-}
-
-void handle_scancode(unsigned char scan_code)
-{
- bool release = false;
-
- /* Compare with i8042_kbd_check() in i8042.c if some logic is missing */
- if (scan_code & 0x80) {
- scan_code &= 0x7f;
- release = true;
- }
-
- input_add_keycode(&config, scan_code, release);
-}
-
-/* TODO: convert to driver model */
-int kbd_init (void)
-{
- struct stdio_dev kbddev;
- struct input_config *input = &config;
-
- if(kbd_init_hw()==-1)
- return -1;
- memset (&kbddev, 0, sizeof(kbddev));
- strcpy(kbddev.name, "kbd");
- kbddev.flags = DEV_FLAGS_INPUT;
- kbddev.getc = kbd_getc;
- kbddev.tstc = kbd_testc;
-
- input_init(input, 0);
- input->read_keys = kbd_read_keys;
- input_add_tables(input, true);
-
- return input_stdio_register(&kbddev);
-}
diff --git a/drivers/input/pc_keyb.c b/drivers/input/pc_keyb.c
deleted file mode 100644
index 1606ab33ff..0000000000
--- a/drivers/input/pc_keyb.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/***********************************************************************
- *
- * (C) Copyright 2004
- * DENX Software Engineering
- * Wolfgang Denk, wd@denx.de
- *
- * PS/2 keyboard driver
- *
- * Originally from linux source (drivers/char/pc_keyb.c)
- *
- ***********************************************************************/
-
-#include <common.h>
-
-#include <keyboard.h>
-#include <pc_keyb.h>
-
-#undef KBG_DEBUG
-
-#ifdef KBG_DEBUG
-#define PRINTF(fmt,args...) printf (fmt ,##args)
-#else
-#define PRINTF(fmt,args...)
-#endif
-
-
-/*
- * This reads the keyboard status port, and does the
- * appropriate action.
- *
- */
-static unsigned char handle_kbd_event(void)
-{
- unsigned char status = kbd_read_status();
- unsigned int work = 10000;
-
- while ((--work > 0) && (status & KBD_STAT_OBF)) {
- unsigned char scancode;
-
- scancode = kbd_read_input();
-
- /* Error bytes must be ignored to make the
- Synaptics touchpads compaq use work */
- /* Ignore error bytes */
- if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
- if (status & KBD_STAT_MOUSE_OBF)
- ; /* not supported: handle_mouse_event(scancode); */
- else
- handle_scancode(scancode);
- }
- status = kbd_read_status();
- }
- if (!work)
- PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
- return status;
-}
-
-
-static int kbd_read_data(void)
-{
- int val;
- unsigned char status;
-
- val = -1;
- status = kbd_read_status();
- if (status & KBD_STAT_OBF) {
- val = kbd_read_input();
- if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
- val = -2;
- }
- return val;
-}
-
-static int kbd_wait_for_input(void)
-{
- unsigned long timeout;
- int val;
-
- timeout = KBD_TIMEOUT;
- val=kbd_read_data();
- while(val < 0) {
- if(timeout--==0)
- return -1;
- udelay(1000);
- val=kbd_read_data();
- }
- return val;
-}
-
-
-static int kb_wait(void)
-{
- unsigned long timeout = KBC_TIMEOUT * 10;
-
- do {
- unsigned char status = handle_kbd_event();
- if (!(status & KBD_STAT_IBF))
- return 0; /* ok */
- udelay(1000);
- timeout--;
- } while (timeout);
- return 1;
-}
-
-static void kbd_write_command_w(int data)
-{
- if(kb_wait())
- PRINTF("timeout in kbd_write_command_w\n");
- kbd_write_command(data);
-}
-
-static void kbd_write_output_w(int data)
-{
- if(kb_wait())
- PRINTF("timeout in kbd_write_output_w\n");
- kbd_write_output(data);
-}
-
-static void kbd_send_data(unsigned char data)
-{
- kbd_write_output_w(data);
- kbd_wait_for_input();
-}
-
-
-static char * kbd_initialize(void)
-{
- int status;
-
- /*
- * Test the keyboard interface.
- * This seems to be the only way to get it going.
- * If the test is successful a x55 is placed in the input buffer.
- */
- kbd_write_command_w(KBD_CCMD_SELF_TEST);
- if (kbd_wait_for_input() != 0x55)
- return "Kbd: failed self test";
- /*
- * Perform a keyboard interface test. This causes the controller
- * to test the keyboard clock and data lines. The results of the
- * test are placed in the input buffer.
- */
- kbd_write_command_w(KBD_CCMD_KBD_TEST);
- if (kbd_wait_for_input() != 0x00)
- return "Kbd: interface failed self test";
- /*
- * Enable the keyboard by allowing the keyboard clock to run.
- */
- kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
-
- /*
- * Reset keyboard. If the read times out
- * then the assumption is that no keyboard is
- * plugged into the machine.
- * This defaults the keyboard to scan-code set 2.
- *
- * Set up to try again if the keyboard asks for RESEND.
- */
- do {
- kbd_write_output_w(KBD_CMD_RESET);
- status = kbd_wait_for_input();
- if (status == KBD_REPLY_ACK)
- break;
- if (status != KBD_REPLY_RESEND) {
- PRINTF("status: %X\n",status);
- return "Kbd: reset failed, no ACK";
- }
- } while (1);
- if (kbd_wait_for_input() != KBD_REPLY_POR)
- return "Kbd: reset failed, no POR";
-
- /*
- * Set keyboard controller mode. During this, the keyboard should be
- * in the disabled state.
- *
- * Set up to try again if the keyboard asks for RESEND.
- */
- do {
- kbd_write_output_w(KBD_CMD_DISABLE);
- status = kbd_wait_for_input();
- if (status == KBD_REPLY_ACK)
- break;
- if (status != KBD_REPLY_RESEND)
- return "Kbd: disable keyboard: no ACK";
- } while (1);
-
- kbd_write_command_w(KBD_CCMD_WRITE_MODE);
- kbd_write_output_w(KBD_MODE_KBD_INT
- | KBD_MODE_SYS
- | KBD_MODE_DISABLE_MOUSE
- | KBD_MODE_KCC);
-
- /* AMCC powerpc portables need this to use scan-code set 1 -- Cort */
- kbd_write_command_w(KBD_CCMD_READ_MODE);
- if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
- /*
- * If the controller does not support conversion,
- * Set the keyboard to scan-code set 1.
- */
- kbd_write_output_w(0xF0);
- kbd_wait_for_input();
- kbd_write_output_w(0x01);
- kbd_wait_for_input();
- }
- kbd_write_output_w(KBD_CMD_ENABLE);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Kbd: enable keyboard: no ACK";
-
- /*
- * Finally, set the typematic rate to maximum.
- */
- kbd_write_output_w(KBD_CMD_SET_RATE);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Kbd: Set rate: no ACK";
- kbd_write_output_w(0x00);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Kbd: Set rate: no ACK";
- return NULL;
-}
-
-static void kbd_interrupt(void *dev_id)
-{
- handle_kbd_event();
-}
-
-/******************************************************************
- * Init
- ******************************************************************/
-
-int kbd_init_hw(void)
-{
- char* result;
-
- kbd_request_region();
-
- result=kbd_initialize();
- if (result==NULL) {
- PRINTF("AT Keyboard initialized\n");
- kbd_request_irq(kbd_interrupt);
- return (1);
- } else {
- printf("%s\n",result);
- return (-1);
- }
-}
-
-void pckbd_leds(unsigned char leds)
-{
- kbd_send_data(KBD_CMD_SET_LEDS);
- kbd_send_data(leds);
-}
diff --git a/drivers/input/ps2mult.c b/drivers/input/ps2mult.c
deleted file mode 100644
index ab749336bf..0000000000
--- a/drivers/input/ps2mult.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/***********************************************************************
- *
- * (C) Copyright 2004
- * DENX Software Engineering
- * Wolfgang Denk, wd@denx.de
- *
- * PS/2 multiplexer driver
- *
- * Originally from linux source (drivers/char/ps2mult.c)
- *
- * Uses simple serial driver (ps2ser.c) to access the multiplexer
- * Used by PS/2 keyboard driver (pc_keyb.c)
- *
- ***********************************************************************/
-
-#include <common.h>
-
-#include <pc_keyb.h>
-#include <asm/atomic.h>
-#include <ps2mult.h>
-
-/* #define DEBUG_MULT */
-/* #define DEBUG_KEYB */
-
-#define KBD_STAT_DEFAULT (KBD_STAT_SELFTEST | KBD_STAT_UNLOCKED)
-
-#define PRINTF(format, args...) printf("ps2mult.c: " format, ## args)
-
-#ifdef DEBUG_MULT
-#define PRINTF_MULT(format, args...) printf("PS2MULT: " format, ## args)
-#else
-#define PRINTF_MULT(format, args...)
-#endif
-
-#ifdef DEBUG_KEYB
-#define PRINTF_KEYB(format, args...) printf("KEYB: " format, ## args)
-#else
-#define PRINTF_KEYB(format, args...)
-#endif
-
-
-static ulong start_time;
-static int init_done = 0;
-
-static int received_escape = 0;
-static int received_bsync = 0;
-static int received_selector = 0;
-
-static int kbd_command_active = 0;
-static int mouse_command_active = 0;
-static int ctl_command_active = 0;
-
-static u_char command_byte = 0;
-
-static void (*keyb_handler)(void *dev_id);
-
-static u_char ps2mult_buf [PS2BUF_SIZE];
-static atomic_t ps2mult_buf_cnt;
-static int ps2mult_buf_in_idx;
-static int ps2mult_buf_out_idx;
-
-static u_char ps2mult_buf_status [PS2BUF_SIZE];
-
-#ifndef CONFIG_BOARD_EARLY_INIT_R
-#error #define CONFIG_BOARD_EARLY_INIT_R and call ps2mult_early_init() in board_early_init_r()
-#endif
-void ps2mult_early_init (void)
-{
- start_time = get_timer(0);
-}
-
-static void ps2mult_send_byte(u_char byte, u_char sel)
-{
- ps2ser_putc(sel);
-
- if (sel == PS2MULT_KB_SELECTOR) {
- PRINTF_MULT("0x%02x send KEYBOARD\n", byte);
- kbd_command_active = 1;
- } else {
- PRINTF_MULT("0x%02x send MOUSE\n", byte);
- mouse_command_active = 1;
- }
-
- switch (byte) {
- case PS2MULT_ESCAPE:
- case PS2MULT_BSYNC:
- case PS2MULT_KB_SELECTOR:
- case PS2MULT_MS_SELECTOR:
- case PS2MULT_SESSION_START:
- case PS2MULT_SESSION_END:
- ps2ser_putc(PS2MULT_ESCAPE);
- break;
- default:
- break;
- }
-
- ps2ser_putc(byte);
-}
-
-static void ps2mult_receive_byte(u_char byte, u_char sel)
-{
- u_char status = KBD_STAT_DEFAULT;
-
-#if 1 /* Ignore mouse in U-Boot */
- if (sel == PS2MULT_MS_SELECTOR) return;
-#endif
-
- if (sel == PS2MULT_KB_SELECTOR) {
- if (kbd_command_active) {
- if (!received_bsync) {
- PRINTF_MULT("0x%02x lost KEYBOARD !!!\n", byte);
- return;
- } else {
- kbd_command_active = 0;
- received_bsync = 0;
- }
- }
- PRINTF_MULT("0x%02x receive KEYBOARD\n", byte);
- status |= KBD_STAT_IBF | KBD_STAT_OBF;
- } else {
- if (mouse_command_active) {
- if (!received_bsync) {
- PRINTF_MULT("0x%02x lost MOUSE !!!\n", byte);
- return;
- } else {
- mouse_command_active = 0;
- received_bsync = 0;
- }
- }
- PRINTF_MULT("0x%02x receive MOUSE\n", byte);
- status |= KBD_STAT_IBF | KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
- }
-
- if (atomic_read(&ps2mult_buf_cnt) < PS2BUF_SIZE) {
- ps2mult_buf_status[ps2mult_buf_in_idx] = status;
- ps2mult_buf[ps2mult_buf_in_idx++] = byte;
- ps2mult_buf_in_idx &= (PS2BUF_SIZE - 1);
- atomic_inc(&ps2mult_buf_cnt);
- } else {
- PRINTF("buffer overflow\n");
- }
-
- if (received_bsync) {
- PRINTF("unexpected BSYNC\n");
- received_bsync = 0;
- }
-}
-
-void ps2mult_callback (int in_cnt)
-{
- int i;
- u_char byte;
- static int keyb_handler_active = 0;
-
- if (!init_done) {
- return;
- }
-
- for (i = 0; i < in_cnt; i ++) {
- byte = ps2ser_getc();
-
- if (received_escape) {
- ps2mult_receive_byte(byte, received_selector);
- received_escape = 0;
- } else switch (byte) {
- case PS2MULT_ESCAPE:
- PRINTF_MULT("ESCAPE receive\n");
- received_escape = 1;
- break;
-
- case PS2MULT_BSYNC:
- PRINTF_MULT("BSYNC receive\n");
- received_bsync = 1;
- break;
-
- case PS2MULT_KB_SELECTOR:
- case PS2MULT_MS_SELECTOR:
- PRINTF_MULT("%s receive\n",
- byte == PS2MULT_KB_SELECTOR ? "KB_SEL" : "MS_SEL");
- received_selector = byte;
- break;
-
- case PS2MULT_SESSION_START:
- case PS2MULT_SESSION_END:
- PRINTF_MULT("%s receive\n",
- byte == PS2MULT_SESSION_START ?
- "SESSION_START" : "SESSION_END");
- break;
-
- default:
- ps2mult_receive_byte(byte, received_selector);
- }
- }
-
- if (keyb_handler && !keyb_handler_active &&
- atomic_read(&ps2mult_buf_cnt)) {
- keyb_handler_active = 1;
- keyb_handler(NULL);
- keyb_handler_active = 0;
- }
-}
-
-u_char ps2mult_read_status(void)
-{
- u_char byte;
-
- if (atomic_read(&ps2mult_buf_cnt) == 0) {
- ps2ser_check();
- }
-
- if (atomic_read(&ps2mult_buf_cnt)) {
- byte = ps2mult_buf_status[ps2mult_buf_out_idx];
- } else {
- byte = KBD_STAT_DEFAULT;
- }
- PRINTF_KEYB("read_status()=0x%02x\n", byte);
- return byte;
-}
-
-u_char ps2mult_read_input(void)
-{
- u_char byte = 0;
-
- if (atomic_read(&ps2mult_buf_cnt) == 0) {
- ps2ser_check();
- }
-
- if (atomic_read(&ps2mult_buf_cnt)) {
- byte = ps2mult_buf[ps2mult_buf_out_idx++];
- ps2mult_buf_out_idx &= (PS2BUF_SIZE - 1);
- atomic_dec(&ps2mult_buf_cnt);
- }
- PRINTF_KEYB("read_input()=0x%02x\n", byte);
- return byte;
-}
-
-void ps2mult_write_output(u_char val)
-{
- int i;
-
- PRINTF_KEYB("write_output(0x%02x)\n", val);
-
- for (i = 0; i < KBD_TIMEOUT; i++) {
- if (!kbd_command_active && !mouse_command_active) {
- break;
- }
- udelay(1000);
- ps2ser_check();
- }
-
- if (kbd_command_active) {
- PRINTF("keyboard command not acknoledged\n");
- kbd_command_active = 0;
- }
-
- if (mouse_command_active) {
- PRINTF("mouse command not acknoledged\n");
- mouse_command_active = 0;
- }
-
- if (ctl_command_active) {
- switch (ctl_command_active) {
- case KBD_CCMD_WRITE_MODE:
- /* Scan code conversion not supported */
- command_byte = val & ~KBD_MODE_KCC;
- break;
-
- case KBD_CCMD_WRITE_AUX_OBUF:
- ps2mult_receive_byte(val, PS2MULT_MS_SELECTOR);
- break;
-
- case KBD_CCMD_WRITE_MOUSE:
- ps2mult_send_byte(val, PS2MULT_MS_SELECTOR);
- break;
-
- default:
- PRINTF("invalid controller command\n");
- break;
- }
-
- ctl_command_active = 0;
- return;
- }
-
- ps2mult_send_byte(val, PS2MULT_KB_SELECTOR);
-}
-
-void ps2mult_write_command(u_char val)
-{
- ctl_command_active = 0;
-
- PRINTF_KEYB("write_command(0x%02x)\n", val);
-
- switch (val) {
- case KBD_CCMD_READ_MODE:
- ps2mult_receive_byte(command_byte, PS2MULT_KB_SELECTOR);
- break;
-
- case KBD_CCMD_WRITE_MODE:
- ctl_command_active = val;
- break;
-
- case KBD_CCMD_MOUSE_DISABLE:
- break;
-
- case KBD_CCMD_MOUSE_ENABLE:
- break;
-
- case KBD_CCMD_SELF_TEST:
- ps2mult_receive_byte(0x55, PS2MULT_KB_SELECTOR);
- break;
-
- case KBD_CCMD_KBD_TEST:
- ps2mult_receive_byte(0x00, PS2MULT_KB_SELECTOR);
- break;
-
- case KBD_CCMD_KBD_DISABLE:
- break;
-
- case KBD_CCMD_KBD_ENABLE:
- break;
-
- case KBD_CCMD_WRITE_AUX_OBUF:
- ctl_command_active = val;
- break;
-
- case KBD_CCMD_WRITE_MOUSE:
- ctl_command_active = val;
- break;
-
- default:
- PRINTF("invalid controller command\n");
- break;
- }
-}
-
-static int ps2mult_getc_w (void)
-{
- int res = -1;
- int i;
-
- for (i = 0; i < KBD_TIMEOUT; i++) {
- if (ps2ser_check()) {
- res = ps2ser_getc();
- break;
- }
- udelay(1000);
- }
-
- switch (res) {
- case PS2MULT_KB_SELECTOR:
- case PS2MULT_MS_SELECTOR:
- received_selector = res;
- break;
- default:
- break;
- }
-
- return res;
-}
-
-int ps2mult_init (void)
-{
- int byte;
- int kbd_found = 0;
- int mouse_found = 0;
-
- while (get_timer(start_time) < CONFIG_PS2MULT_DELAY);
-
- ps2ser_init();
-
- ps2ser_putc(PS2MULT_SESSION_START);
-
- ps2ser_putc(PS2MULT_KB_SELECTOR);
- ps2ser_putc(KBD_CMD_RESET);
-
- do {
- byte = ps2mult_getc_w();
- } while (byte >= 0 && byte != KBD_REPLY_ACK);
-
- if (byte == KBD_REPLY_ACK) {
- byte = ps2mult_getc_w();
- if (byte == 0xaa) {
- kbd_found = 1;
- puts("keyboard");
- }
- }
-
- if (!kbd_found) {
- while (byte >= 0) {
- byte = ps2mult_getc_w();
- }
- }
-
-#if 1 /* detect mouse */
- ps2ser_putc(PS2MULT_MS_SELECTOR);
- ps2ser_putc(AUX_RESET);
-
- do {
- byte = ps2mult_getc_w();
- } while (byte >= 0 && byte != AUX_ACK);
-
- if (byte == AUX_ACK) {
- byte = ps2mult_getc_w();
- if (byte == 0xaa) {
- byte = ps2mult_getc_w();
- if (byte == 0x00) {
- mouse_found = 1;
- puts(", mouse");
- }
- }
- }
-
- if (!mouse_found) {
- while (byte >= 0) {
- byte = ps2mult_getc_w();
- }
- }
-#endif
-
- if (mouse_found || kbd_found) {
- if (!received_selector) {
- if (mouse_found) {
- received_selector = PS2MULT_MS_SELECTOR;
- } else {
- received_selector = PS2MULT_KB_SELECTOR;
- }
- }
-
- init_done = 1;
- } else {
- puts("No device found");
- }
-
- puts("\n");
-
-#if 0 /* for testing */
- {
- int i;
- u_char key[] = {
- 0x1f, 0x12, 0x14, 0x12, 0x31, 0x2f, 0x39, /* setenv */
- 0x1f, 0x14, 0x20, 0x17, 0x31, 0x39, /* stdin */
- 0x1f, 0x12, 0x13, 0x17, 0x1e, 0x26, 0x1c, /* serial */
- };
-
- for (i = 0; i < sizeof (key); i++) {
- ps2mult_receive_byte (key[i], PS2MULT_KB_SELECTOR);
- ps2mult_receive_byte (key[i] | 0x80, PS2MULT_KB_SELECTOR);
- }
- }
-#endif
-
- return init_done ? 0 : -1;
-}
-
-int ps2mult_request_irq(void (*handler)(void *))
-{
- keyb_handler = handler;
-
- return 0;
-}
diff --git a/drivers/input/ps2ser.c b/drivers/input/ps2ser.c
deleted file mode 100644
index 0b5ce06853..0000000000
--- a/drivers/input/ps2ser.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/***********************************************************************
- *
- * (C) Copyright 2004-2009
- * DENX Software Engineering
- * Wolfgang Denk, wd@denx.de
- *
- * Simple 16550A serial driver
- *
- * Originally from linux source (drivers/char/ps2ser.c)
- *
- * Used by the PS/2 multiplexer driver (ps2mult.c)
- *
- ***********************************************************************/
-
-#include <common.h>
-
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <ps2mult.h>
-/* This is needed for ns16550.h */
-#ifndef CONFIG_SYS_NS16550_REG_SIZE
-#define CONFIG_SYS_NS16550_REG_SIZE 1
-#endif
-#include <ns16550.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/* #define DEBUG */
-
-#define PS2SER_BAUD 57600
-
-#if CONFIG_PS2SERIAL == 1
-#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
-#elif CONFIG_PS2SERIAL == 2
-#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600)
-#else
-#error CONFIG_PS2SERIAL must be in 1 ... 2
-#endif
-
-static int ps2ser_getc_hw(void);
-static void ps2ser_interrupt(void *dev_id);
-
-extern struct serial_state rs_table[]; /* in serial.c */
-
-static u_char ps2buf[PS2BUF_SIZE];
-static atomic_t ps2buf_cnt;
-static int ps2buf_in_idx;
-static int ps2buf_out_idx;
-
-int ps2ser_init(void)
-{
- NS16550_t com_port = (NS16550_t)COM_BASE;
-
- com_port->ier = 0x00;
- com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1;
- com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
- com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
- com_port->lcr = UART_LCR_8N1;
- com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS);
- com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
-
- return (0);
-}
-
-void ps2ser_putc(int chr)
-{
- NS16550_t com_port = (NS16550_t)COM_BASE;
- debug(">>>> 0x%02x\n", chr);
-
- while ((com_port->lsr & UART_LSR_THRE) == 0);
- com_port->thr = chr;
-}
-
-static int ps2ser_getc_hw(void)
-{
- NS16550_t com_port = (NS16550_t)COM_BASE;
- int res = -1;
-
- if (com_port->lsr & UART_LSR_DR) {
- res = com_port->rbr;
- }
-
- return res;
-}
-
-int ps2ser_getc(void)
-{
- volatile int chr;
- int flags;
-
- debug("<< ");
-
- flags = disable_interrupts();
-
- do {
- if (atomic_read(&ps2buf_cnt) != 0) {
- chr = ps2buf[ps2buf_out_idx++];
- ps2buf_out_idx &= (PS2BUF_SIZE - 1);
- atomic_dec(&ps2buf_cnt);
- } else {
- chr = ps2ser_getc_hw();
- }
- }
- while (chr < 0);
-
- if (flags)
- enable_interrupts();
-
- debug("0x%02x\n", chr);
-
- return chr;
-}
-
-int ps2ser_check(void)
-{
- int flags;
-
- flags = disable_interrupts();
- ps2ser_interrupt(NULL);
- if (flags) enable_interrupts();
-
- return atomic_read(&ps2buf_cnt);
-}
-
-static void ps2ser_interrupt(void *dev_id)
-{
- NS16550_t com_port = (NS16550_t)COM_BASE;
- int chr;
- int status;
-
- do {
- chr = ps2ser_getc_hw();
- status = com_port->lsr;
- if (chr < 0) continue;
-
- if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
- ps2buf[ps2buf_in_idx++] = chr;
- ps2buf_in_idx &= (PS2BUF_SIZE - 1);
- atomic_inc(&ps2buf_cnt);
- } else {
- printf ("ps2ser.c: buffer overflow\n");
- }
- } while (status & UART_LSR_DR);
- if (atomic_read(&ps2buf_cnt)) {
- ps2mult_callback(atomic_read(&ps2buf_cnt));
- }
-}
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 5f67e336db..6935da2177 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -267,13 +267,22 @@ config SH_SDHI
Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform
config MMC_UNIPHIER
- bool "UniPhier/RCar SD/MMC Host Controller support"
- depends on ARCH_UNIPHIER || ARCH_RMOBILE
+ bool "UniPhier SD/MMC Host Controller support"
+ depends on ARCH_UNIPHIER
depends on BLK && DM_MMC
depends on OF_CONTROL
help
This selects support for the Matsushita SD/MMC Host Controller on
- SocioNext UniPhier and Renesas RCar SoCs.
+ SocioNext UniPhier SoCs.
+
+config RENESAS_SDHI
+ bool "Renesas R-Car SD/MMC Host Controller support"
+ depends on ARCH_RMOBILE
+ depends on BLK && DM_MMC
+ depends on OF_CONTROL
+ help
+ This selects support for the Matsushita SD/MMC Host Controller on
+ Renesas R-Car SoCs.
config MMC_BCM2835
bool "BCM2835 family custom SD/MMC Host Controller support"
@@ -523,18 +532,18 @@ config STM32_SDMMC2
If you have a board based on such a SoC and with a SD/MMC slot,
say Y or M here.
-config MMC_NDS32
- bool "Andestech SD/MMC controller support"
- depends on DM_MMC && OF_CONTROL && BLK && FTSDC010
- help
- This enables support for the Andestech SD/MMM controller, which is
- based on Faraday IP.
-
config FTSDC010
bool "Ftsdc010 SD/MMC controller Support"
help
This SD/MMC controller is present in Andestech SoCs which is based on Faraday IP.
+config FTSDC010_SDIO
+ bool "Support ftsdc010 sdio"
+ default n
+ depends on FTSDC010
+ help
+ This can enable ftsdc010 sdio function.
+
endif
config TEGRA124_MMC_DISABLE_EXT_LOOPBACK
@@ -548,6 +557,12 @@ config TEGRA124_MMC_DISABLE_EXT_LOOPBACK
TODO(marcel.ziswiler@toradex.com): Move to device tree controlled
approach once proper kernel integration made it mainline.
+config FSL_ESDHC
+ bool "Freescale/NXP eSDHC controller support"
+ help
+ This selects support for the eSDHC (enhanced secure digital host
+ controller) found on numerous Freescale/NXP SoCs.
+
endmenu
config SYS_FSL_ERRATUM_ESDHC111
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 42113e2603..cf46c332f1 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -42,7 +42,6 @@ obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
-obj-$(CONFIG_MMC_NDS32) += nds32_mmc.o
# SDHCI
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
@@ -63,5 +62,6 @@ 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
+obj-$(CONFIG_MMC_UNIPHIER) += tmio-common.o uniphier-sd.o
+obj-$(CONFIG_RENESAS_SDHI) += tmio-common.o renesas-sdhi.o
obj-$(CONFIG_MMC_BCM2835) += bcm2835_sdhost.o
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index 3157354d2a..08bddd410e 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -183,7 +183,7 @@ static int bcm2835_sdhci_probe(struct udevice *dev)
if (base == FDT_ADDR_T_NONE)
return -EINVAL;
- ret = bcm2835_get_mmc_clock();
+ ret = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_EMMC);
if (ret < 0) {
debug("%s: Failed to set MMC clock (err=%d)\n", __func__, ret);
return ret;
diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c
index 1bf52a3019..bccd182e50 100644
--- a/drivers/mmc/bcm2835_sdhost.c
+++ b/drivers/mmc/bcm2835_sdhost.c
@@ -35,6 +35,7 @@
#include <dm.h>
#include <mmc.h>
#include <asm/arch/msg.h>
+#include <asm/arch/mbox.h>
#include <asm/unaligned.h>
#include <linux/compat.h>
#include <linux/io.h>
@@ -941,7 +942,7 @@ static int bcm2835_probe(struct udevice *dev)
if (!host->ioaddr)
return -ENOMEM;
- host->max_clk = bcm2835_get_mmc_clock();
+ host->max_clk = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_CORE);
bcm2835_add_host(host);
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index 6ac4f83bd1..9de3a1503d 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -4,23 +4,63 @@
* (C) Copyright 2010 Faraday Technology
* Dante Su <dantesu@faraday-tech.com>
*
+ * Copyright 2018 Andes Technology, Inc.
+ * Author: Rick Chen (rick@andestech.com)
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <clk.h>
#include <malloc.h>
#include <part.h>
#include <mmc.h>
-
#include <linux/io.h>
#include <linux/errno.h>
#include <asm/byteorder.h>
#include <faraday/ftsdc010.h>
#include "ftsdc010_mci.h"
+#include <dm.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <mapmem.h>
+#include <pwrseq.h>
+#include <syscon.h>
+#include <linux/err.h>
+
+DECLARE_GLOBAL_DATA_PTR;
#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+struct ftsdc010 {
+ fdt32_t bus_width;
+ bool cap_mmc_highspeed;
+ bool cap_sd_highspeed;
+ fdt32_t clock_freq_min_max[2];
+ struct phandle_2_cell clocks[4];
+ fdt32_t fifo_depth;
+ fdt32_t reg[2];
+};
+#endif
+
+struct ftsdc010_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct ftsdc010 dtplat;
+#endif
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+struct ftsdc_priv {
+ struct clk clk;
+ struct ftsdc010_chip chip;
+ int fifo_depth;
+ bool fifo_mode;
+ u32 minmax[2];
+};
+
static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
{
struct ftsdc010_chip *chip = mmc->priv;
@@ -138,16 +178,10 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
/*
* u-boot mmc api
*/
-#ifdef CONFIG_DM_MMC
static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
-#else
-static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
-#endif
int ret = -EOPNOTSUPP;
uint32_t len = 0;
struct ftsdc010_chip *chip = mmc->priv;
@@ -248,14 +282,9 @@ static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
return ret;
}
-#ifdef CONFIG_DM_MMC
static int ftsdc010_set_ios(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
-#else
-static int ftsdc010_set_ios(struct mmc *mmc)
-{
-#endif
struct ftsdc010_chip *chip = mmc->priv;
struct ftsdc010_mmc __iomem *regs = chip->regs;
@@ -277,27 +306,17 @@ static int ftsdc010_set_ios(struct mmc *mmc)
return 0;
}
-#ifdef CONFIG_DM_MMC
static int ftsdc010_get_cd(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
-#else
-static int ftsdc010_get_cd(struct mmc *mmc)
-{
-#endif
struct ftsdc010_chip *chip = mmc->priv;
struct ftsdc010_mmc __iomem *regs = chip->regs;
return !(readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT);
}
-#ifdef CONFIG_DM_MMC
static int ftsdc010_get_wp(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
-#else
-static int ftsdc010_get_wp(struct mmc *mmc)
-{
-#endif
struct ftsdc010_chip *chip = mmc->priv;
struct ftsdc010_mmc __iomem *regs = chip->regs;
if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
@@ -337,31 +356,20 @@ static int ftsdc010_init(struct mmc *mmc)
return 0;
}
-#ifdef CONFIG_DM_MMC
-int ftsdc010_probe(struct udevice *dev)
+static int ftsdc010_probe(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
return ftsdc010_init(mmc);
}
-const struct dm_mmc_ops dm_ftsdc010_ops = {
+const struct dm_mmc_ops dm_ftsdc010_mmc_ops = {
.send_cmd = ftsdc010_request,
.set_ios = ftsdc010_set_ios,
.get_cd = ftsdc010_get_cd,
.get_wp = ftsdc010_get_wp,
};
-#else
-static const struct mmc_ops ftsdc010_ops = {
- .send_cmd = ftsdc010_request,
- .set_ios = ftsdc010_set_ios,
- .getcd = ftsdc010_get_cd,
- .getwp = ftsdc010_get_wp,
- .init = ftsdc010_init,
-};
-#endif
-
-void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
+static void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
uint caps, u32 max_clk, u32 min_clk)
{
cfg->name = name;
@@ -380,73 +388,94 @@ void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
}
-void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg)
+static int ftsdc010_mmc_ofdata_to_platdata(struct udevice *dev)
{
- switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
- case FTSDC010_BWR_CAPS_4BIT:
- cfg->host_caps |= MMC_MODE_4BIT;
- break;
- case FTSDC010_BWR_CAPS_8BIT:
- cfg->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
- break;
- default:
- break;
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct ftsdc_priv *priv = dev_get_priv(dev);
+ struct ftsdc010_chip *chip = &priv->chip;
+ chip->name = dev->name;
+ chip->ioaddr = (void *)devfdt_get_addr(dev);
+ chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "bus-width", 4);
+ chip->priv = dev;
+ priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "fifo-depth", 0);
+ priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "fifo-mode");
+ if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
+ "clock-freq-min-max", priv->minmax, 2)) {
+ int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "max-frequency", -EINVAL);
+ if (val < 0)
+ return val;
+
+ priv->minmax[0] = 400000; /* 400 kHz */
+ priv->minmax[1] = val;
+ } else {
+ debug("%s: 'clock-freq-min-max' property was deprecated.\n",
+ __func__);
}
+#endif
+ chip->sclk = priv->minmax[1];
+ chip->regs = chip->ioaddr;
+ return 0;
}
-#ifdef CONFIG_BLK
-int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg)
+static int ftsdc010_mmc_probe(struct udevice *dev)
{
- return mmc_bind(dev, mmc, cfg);
+ struct ftsdc010_plat *plat = dev_get_platdata(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct ftsdc_priv *priv = dev_get_priv(dev);
+ struct ftsdc010_chip *chip = &priv->chip;
+ struct udevice *pwr_dev __maybe_unused;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ int ret;
+ struct ftsdc010 *dtplat = &plat->dtplat;
+ chip->name = dev->name;
+ chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
+ chip->buswidth = dtplat->bus_width;
+ chip->priv = dev;
+ chip->dev_index = 1;
+ memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
+ ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
+ if (ret < 0)
+ return ret;
+#endif
+
+ if (dev_read_bool(dev, "cap-mmc-highspeed") || \
+ dev_read_bool(dev, "cap-sd-highspeed"))
+ chip->caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
+
+ ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps,
+ priv->minmax[1] , priv->minmax[0]);
+ chip->mmc = &plat->mmc;
+ chip->mmc->priv = &priv->chip;
+ chip->mmc->dev = dev;
+ upriv->mmc = chip->mmc;
+ return ftsdc010_probe(dev);
}
-#else
-int ftsdc010_mmc_init(int devid)
+int ftsdc010_mmc_bind(struct udevice *dev)
{
- struct mmc *mmc;
- struct ftsdc010_chip *chip;
- struct ftsdc010_mmc __iomem *regs;
-#ifdef CONFIG_FTSDC010_BASE_LIST
- uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
-
- if (devid < 0 || devid >= ARRAY_SIZE(base_list))
- return -1;
- regs = (void __iomem *)base_list[devid];
-#else
- regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
-#endif
-
- chip = malloc(sizeof(struct ftsdc010_chip));
- if (!chip)
- return -ENOMEM;
- memset(chip, 0, sizeof(struct ftsdc010_chip));
+ struct ftsdc010_plat *plat = dev_get_platdata(dev);
- chip->regs = regs;
-#ifdef CONFIG_SYS_CLK_FREQ
- chip->sclk = CONFIG_SYS_CLK_FREQ;
-#else
- chip->sclk = clk_get_rate("SDC");
-#endif
+ return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
- chip->cfg.name = "ftsdc010";
-#ifndef CONFIG_DM_MMC
- chip->cfg.ops = &ftsdc010_ops;
-#endif
- chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
- set_bus_width(regs , &chip->cfg);
- chip->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- chip->cfg.f_max = chip->sclk / 2;
- chip->cfg.f_min = chip->sclk / 0x100;
-
- chip->cfg.part_type = PART_TYPE_DOS;
- chip->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
-
- mmc = mmc_create(&chip->cfg, chip);
- if (mmc == NULL) {
- free(chip);
- return -ENOMEM;
- }
+static const struct udevice_id ftsdc010_mmc_ids[] = {
+ { .compatible = "andestech,atsdc010" },
+ { }
+};
- return 0;
-}
-#endif
+U_BOOT_DRIVER(ftsdc010_mmc) = {
+ .name = "ftsdc010_mmc",
+ .id = UCLASS_MMC,
+ .of_match = ftsdc010_mmc_ids,
+ .ofdata_to_platdata = ftsdc010_mmc_ofdata_to_platdata,
+ .ops = &dm_ftsdc010_mmc_ops,
+ .bind = ftsdc010_mmc_bind,
+ .probe = ftsdc010_mmc_probe,
+ .priv_auto_alloc_size = sizeof(struct ftsdc_priv),
+ .platdata_auto_alloc_size = sizeof(struct ftsdc010_plat),
+};
diff --git a/drivers/mmc/ftsdc010_mci.h b/drivers/mmc/ftsdc010_mci.h
index 31a27fd772..e417360662 100644
--- a/drivers/mmc/ftsdc010_mci.h
+++ b/drivers/mmc/ftsdc010_mci.h
@@ -35,19 +35,4 @@ struct ftsdc010_chip {
bool fifo_mode;
};
-
-#ifdef CONFIG_DM_MMC
-/* Export the operations to drivers */
-int ftsdc010_probe(struct udevice *dev);
-extern const struct dm_mmc_ops dm_ftsdc010_ops;
-#endif
-void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
- uint caps, u32 max_clk, u32 min_clk);
-void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg);
-
-#ifdef CONFIG_BLK
-int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
-#endif
-
-
#endif /* __FTSDC010_MCI_H */
diff --git a/drivers/mmc/nds32_mmc.c b/drivers/mmc/nds32_mmc.c
deleted file mode 100644
index 6d3c8572e5..0000000000
--- a/drivers/mmc/nds32_mmc.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Andestech ATFSDC010 SD/MMC driver
- *
- * (C) Copyright 2017
- * Rick Chen, NDS32 Software Engineering, rick@andestech.com
-
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <clk.h>
-#include <dm.h>
-#include <dt-structs.h>
-#include <errno.h>
-#include <mapmem.h>
-#include <mmc.h>
-#include <pwrseq.h>
-#include <syscon.h>
-#include <linux/err.h>
-#include <faraday/ftsdc010.h>
-#include "ftsdc010_mci.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
-struct nds_mmc {
- fdt32_t bus_width;
- bool cap_mmc_highspeed;
- bool cap_sd_highspeed;
- fdt32_t clock_freq_min_max[2];
- struct phandle_2_cell clocks[4];
- fdt32_t fifo_depth;
- fdt32_t reg[2];
-};
-#endif
-
-struct nds_mmc_plat {
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
- struct nds_mmc dtplat;
-#endif
- struct mmc_config cfg;
- struct mmc mmc;
-};
-
-struct ftsdc_priv {
- struct clk clk;
- struct ftsdc010_chip chip;
- int fifo_depth;
- bool fifo_mode;
- u32 minmax[2];
-};
-
-static int nds32_mmc_ofdata_to_platdata(struct udevice *dev)
-{
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
- struct ftsdc_priv *priv = dev_get_priv(dev);
- struct ftsdc010_chip *chip = &priv->chip;
- chip->name = dev->name;
- chip->ioaddr = (void *)devfdt_get_addr(dev);
- chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "bus-width", 4);
- chip->priv = dev;
- priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "fifo-depth", 0);
- priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
- "fifo-mode");
- if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
- "clock-freq-min-max", priv->minmax, 2)) {
- int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "max-frequency", -EINVAL);
- if (val < 0)
- return val;
-
- priv->minmax[0] = 400000; /* 400 kHz */
- priv->minmax[1] = val;
- } else {
- debug("%s: 'clock-freq-min-max' property was deprecated.\n",
- __func__);
- }
-#endif
- chip->sclk = priv->minmax[1];
- chip->regs = chip->ioaddr;
- return 0;
-}
-
-static int nds32_mmc_probe(struct udevice *dev)
-{
- struct nds_mmc_plat *plat = dev_get_platdata(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct ftsdc_priv *priv = dev_get_priv(dev);
- struct ftsdc010_chip *chip = &priv->chip;
- struct udevice *pwr_dev __maybe_unused;
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
- int ret;
- struct nds_mmc *dtplat = &plat->dtplat;
- chip->name = dev->name;
- chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
- chip->buswidth = dtplat->bus_width;
- chip->priv = dev;
- chip->dev_index = 1;
- memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
- ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
- if (ret < 0)
- return ret;
-#endif
- ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps,
- priv->minmax[1] , priv->minmax[0]);
- chip->mmc = &plat->mmc;
- chip->mmc->priv = &priv->chip;
- chip->mmc->dev = dev;
- upriv->mmc = chip->mmc;
- return ftsdc010_probe(dev);
-}
-
-static int nds32_mmc_bind(struct udevice *dev)
-{
- struct nds_mmc_plat *plat = dev_get_platdata(dev);
- return ftsdc010_bind(dev, &plat->mmc, &plat->cfg);
-}
-
-static const struct udevice_id nds32_mmc_ids[] = {
- { .compatible = "andestech,atsdc010" },
- { }
-};
-
-U_BOOT_DRIVER(nds32_mmc_drv) = {
- .name = "nds32_mmc",
- .id = UCLASS_MMC,
- .of_match = nds32_mmc_ids,
- .ofdata_to_platdata = nds32_mmc_ofdata_to_platdata,
- .ops = &dm_ftsdc010_ops,
- .bind = nds32_mmc_bind,
- .probe = nds32_mmc_probe,
- .priv_auto_alloc_size = sizeof(struct ftsdc_priv),
- .platdata_auto_alloc_size = sizeof(struct nds_mmc_plat),
-};
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index 05c0044a7a..b7a2ebfe3f 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -29,11 +29,10 @@ static int pci_mmc_probe(struct udevice *dev)
struct pci_mmc_plat *plat = dev_get_platdata(dev);
struct pci_mmc_priv *priv = dev_get_priv(dev);
struct sdhci_host *host = &priv->host;
- u32 ioaddr;
int ret;
- dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &ioaddr);
- host->ioaddr = map_sysmem(ioaddr, 0);
+ host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ PCI_REGION_MEM);
host->name = dev->name;
ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
if (ret)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
new file mode 100644
index 0000000000..56a43ca7d3
--- /dev/null
+++ b/drivers/mmc/renesas-sdhi.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <fdtdec.h>
+#include <mmc.h>
+#include <dm.h>
+#include <linux/compat.h>
+#include <linux/dma-direction.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <power/regulator.h>
+#include <asm/unaligned.h>
+
+#include "tmio-common.h"
+
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+
+/* SCC registers */
+#define RENESAS_SDHI_SCC_DTCNTL 0x800
+#define RENESAS_SDHI_SCC_DTCNTL_TAPEN BIT(0)
+#define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
+#define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff
+#define RENESAS_SDHI_SCC_TAPSET 0x804
+#define RENESAS_SDHI_SCC_DT2FF 0x808
+#define RENESAS_SDHI_SCC_CKSEL 0x80c
+#define RENESAS_SDHI_SCC_CKSEL_DTSEL BIT(0)
+#define RENESAS_SDHI_SCC_RVSCNTL 0x810
+#define RENESAS_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
+#define RENESAS_SDHI_SCC_RVSREQ 0x814
+#define RENESAS_SDHI_SCC_RVSREQ_RVSERR BIT(2)
+#define RENESAS_SDHI_SCC_SMPCMP 0x818
+#define RENESAS_SDHI_SCC_TMPPORT2 0x81c
+
+#define RENESAS_SDHI_MAX_TAP 3
+
+static unsigned int renesas_sdhi_init_tuning(struct tmio_sd_priv *priv)
+{
+ u32 reg;
+
+ /* Initialize SCC */
+ tmio_sd_writel(priv, 0, TMIO_SD_INFO1);
+
+ reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
+ reg &= ~TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
+
+ /* Set sampling clock selection range */
+ tmio_sd_writel(priv, 0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT,
+ RENESAS_SDHI_SCC_DTCNTL);
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL);
+ reg |= RENESAS_SDHI_SCC_DTCNTL_TAPEN;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_DTCNTL);
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL);
+ reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
+ reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
+
+ tmio_sd_writel(priv, 0x300 /* scc_tappos */,
+ RENESAS_SDHI_SCC_DT2FF);
+
+ reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
+ reg |= TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
+
+ /* Read TAPNUM */
+ return (tmio_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL) >>
+ RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) &
+ RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK;
+}
+
+static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv)
+{
+ u32 reg;
+
+ /* Reset SCC */
+ reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
+ reg &= ~TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL);
+ reg &= ~RENESAS_SDHI_SCC_CKSEL_DTSEL;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
+
+ reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
+ reg |= TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
+ reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
+ reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
+}
+
+static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv,
+ unsigned long tap)
+{
+ /* Set sampling clock position */
+ tmio_sd_writel(priv, tap, RENESAS_SDHI_SCC_TAPSET);
+}
+
+static unsigned int renesas_sdhi_compare_scc_data(struct tmio_sd_priv *priv)
+{
+ /* Get comparison of sampling data */
+ return tmio_sd_readl(priv, RENESAS_SDHI_SCC_SMPCMP);
+}
+
+static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv,
+ unsigned int tap_num, unsigned int taps,
+ unsigned int smpcmp)
+{
+ unsigned long tap_cnt; /* counter of tuning success */
+ unsigned long tap_set; /* tap position */
+ unsigned long tap_start;/* start position of tuning success */
+ unsigned long tap_end; /* end position of tuning success */
+ unsigned long ntap; /* temporary counter of tuning success */
+ unsigned long match_cnt;/* counter of matching data */
+ unsigned long i;
+ bool select = false;
+ u32 reg;
+
+ /* Clear SCC_RVSREQ */
+ tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
+
+ /* Merge the results */
+ for (i = 0; i < tap_num * 2; i++) {
+ if (!(taps & BIT(i))) {
+ taps &= ~BIT(i % tap_num);
+ taps &= ~BIT((i % tap_num) + tap_num);
+ }
+ if (!(smpcmp & BIT(i))) {
+ smpcmp &= ~BIT(i % tap_num);
+ smpcmp &= ~BIT((i % tap_num) + tap_num);
+ }
+ }
+
+ /*
+ * Find the longest consecutive run of successful probes. If that
+ * is more than RENESAS_SDHI_MAX_TAP probes long then use the
+ * center index as the tap.
+ */
+ tap_cnt = 0;
+ ntap = 0;
+ tap_start = 0;
+ tap_end = 0;
+ for (i = 0; i < tap_num * 2; i++) {
+ if (taps & BIT(i))
+ ntap++;
+ else {
+ if (ntap > tap_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ tap_cnt = ntap;
+ }
+ ntap = 0;
+ }
+ }
+
+ if (ntap > tap_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ tap_cnt = ntap;
+ }
+
+ /*
+ * If all of the TAP is OK, the sampling clock position is selected by
+ * identifying the change point of data.
+ */
+ if (tap_cnt == tap_num * 2) {
+ match_cnt = 0;
+ ntap = 0;
+ tap_start = 0;
+ tap_end = 0;
+ for (i = 0; i < tap_num * 2; i++) {
+ if (smpcmp & BIT(i))
+ ntap++;
+ else {
+ if (ntap > match_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ match_cnt = ntap;
+ }
+ ntap = 0;
+ }
+ }
+ if (ntap > match_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ match_cnt = ntap;
+ }
+ if (match_cnt)
+ select = true;
+ } else if (tap_cnt >= RENESAS_SDHI_MAX_TAP)
+ select = true;
+
+ if (select)
+ tap_set = ((tap_start + tap_end) / 2) % tap_num;
+ else
+ return -EIO;
+
+ /* Set SCC */
+ tmio_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET);
+
+ /* Enable auto re-tuning */
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
+ reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
+ tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
+
+ return 0;
+}
+
+int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct mmc *mmc = upriv->mmc;
+ unsigned int tap_num;
+ unsigned int taps = 0, smpcmp = 0;
+ int i, ret = 0;
+ u32 caps;
+
+ /* Only supported on Renesas RCar */
+ if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS))
+ return -EINVAL;
+
+ /* clock tuning is not needed for upto 52MHz */
+ if (!((mmc->selected_mode == MMC_HS_200) ||
+ (mmc->selected_mode == UHS_SDR104) ||
+ (mmc->selected_mode == UHS_SDR50)))
+ return 0;
+
+ tap_num = renesas_sdhi_init_tuning(priv);
+ if (!tap_num)
+ /* Tuning is not supported */
+ goto out;
+
+ if (tap_num * 2 >= sizeof(taps) * 8) {
+ dev_err(dev,
+ "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n");
+ goto out;
+ }
+
+ /* Issue CMD19 twice for each tap */
+ for (i = 0; i < 2 * tap_num; i++) {
+ renesas_sdhi_prepare_tuning(priv, i % tap_num);
+
+ /* Force PIO for the tuning */
+ caps = priv->caps;
+ priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL;
+
+ ret = mmc_send_tuning(mmc, opcode, NULL);
+
+ priv->caps = caps;
+
+ if (ret == 0)
+ taps |= BIT(i);
+
+ ret = renesas_sdhi_compare_scc_data(priv);
+ if (ret == 0)
+ smpcmp |= BIT(i);
+
+ mdelay(1);
+ }
+
+ ret = renesas_sdhi_select_tuning(priv, tap_num, taps, smpcmp);
+
+out:
+ if (ret < 0) {
+ dev_warn(dev, "Tuning procedure failed\n");
+ renesas_sdhi_reset_tuning(priv);
+ }
+
+ return ret;
+}
+#endif
+
+static int renesas_sdhi_set_ios(struct udevice *dev)
+{
+ int ret = tmio_sd_set_ios(dev);
+
+ mdelay(10);
+
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+
+ renesas_sdhi_reset_tuning(priv);
+#endif
+
+ return ret;
+}
+
+static const struct dm_mmc_ops renesas_sdhi_ops = {
+ .send_cmd = tmio_sd_send_cmd,
+ .set_ios = renesas_sdhi_set_ios,
+ .get_cd = tmio_sd_get_cd,
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ .execute_tuning = renesas_sdhi_execute_tuning,
+#endif
+};
+
+#define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2
+#define RENESAS_GEN3_QUIRKS \
+ TMIO_SD_CAP_64BIT | TMIO_SD_CAP_RCAR_GEN3 | TMIO_SD_CAP_RCAR_UHS
+
+static const struct udevice_id renesas_sdhi_match[] = {
+ { .compatible = "renesas,sdhi-r8a7790", .data = RENESAS_GEN2_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a7791", .data = RENESAS_GEN2_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a7792", .data = RENESAS_GEN2_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a7793", .data = RENESAS_GEN2_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS },
+ { .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_GEN3_QUIRKS },
+ { /* sentinel */ }
+};
+
+static int renesas_sdhi_probe(struct udevice *dev)
+{
+ u32 quirks = dev_get_driver_data(dev);
+ struct fdt_resource reg_res;
+ DECLARE_GLOBAL_DATA_PTR;
+ int ret;
+
+ if (quirks == RENESAS_GEN2_QUIRKS) {
+ ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev),
+ "reg", 0, &reg_res);
+ if (ret < 0) {
+ dev_err(dev, "\"reg\" resource not found, ret=%i\n",
+ ret);
+ return ret;
+ }
+
+ if (fdt_resource_size(&reg_res) == 0x100)
+ quirks |= TMIO_SD_CAP_16BIT;
+ }
+
+ ret = tmio_sd_probe(dev, quirks);
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
+ if (!ret)
+ renesas_sdhi_reset_tuning(dev_get_priv(dev));
+#endif
+ return ret;
+}
+
+U_BOOT_DRIVER(renesas_sdhi) = {
+ .name = "renesas-sdhi",
+ .id = UCLASS_MMC,
+ .of_match = renesas_sdhi_match,
+ .bind = tmio_sd_bind,
+ .probe = renesas_sdhi_probe,
+ .priv_auto_alloc_size = sizeof(struct tmio_sd_priv),
+ .platdata_auto_alloc_size = sizeof(struct tmio_sd_plat),
+ .ops = &renesas_sdhi_ops,
+};
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index be6edb2eae..ab89be4764 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -62,6 +62,13 @@ static int arasan_sdhci_probe(struct udevice *dev)
host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
host->max_clk = max_frequency;
+ /*
+ * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
+ * doesn't allow us to clear MMC_MODE_4BIT. Consequently, we don't
+ * check for other bus-width values.
+ */
+ if (host->bus_width == 8)
+ host->host_caps |= MMC_MODE_8BIT;
ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
@@ -82,6 +89,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
host->name = dev->name;
host->ioaddr = dev_read_addr_ptr(dev);
+ host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
#endif
return 0;
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
index bd2200a05c..f5b21dd097 100644
--- a/drivers/mmc/stm32_sdmmc2.c
+++ b/drivers/mmc/stm32_sdmmc2.c
@@ -72,7 +72,10 @@ struct stm32_sdmmc2_ctx {
#define SDMMC_CLKCR_HWFC_EN BIT(17)
#define SDMMC_CLKCR_DDR BIT(18)
#define SDMMC_CLKCR_BUSSPEED BIT(19)
-#define SDMMC_CLKCR_SELCLKRX GENMASK(21, 20)
+#define SDMMC_CLKCR_SELCLKRX_MASK GENMASK(21, 20)
+#define SDMMC_CLKCR_SELCLKRX_CK 0
+#define SDMMC_CLKCR_SELCLKRX_CKIN BIT(20)
+#define SDMMC_CLKCR_SELCLKRX_FBCK BIT(21)
/* SDMMC_CMD register */
#define SDMMC_CMD_CMDINDEX GENMASK(5, 0)
@@ -495,7 +498,8 @@ static int stm32_sdmmc2_set_ios(struct udevice *dev)
if (mmc->bus_width == 8)
clk |= SDMMC_CLKCR_WIDBUS_8;
- writel(clk | priv->clk_reg_msk, priv->base + SDMMC_CLKCR);
+ writel(clk | priv->clk_reg_msk | SDMMC_CLKCR_HWFC_EN,
+ priv->base + SDMMC_CLKCR);
return 0;
}
@@ -534,6 +538,8 @@ static int stm32_sdmmc2_probe(struct udevice *dev)
priv->clk_reg_msk |= SDMMC_CLKCR_NEGEDGE;
if (dev_read_bool(dev, "st,dirpol"))
priv->pwr_reg_msk |= SDMMC_POWER_DIRPOL;
+ if (dev_read_bool(dev, "st,pin-ckin"))
+ priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN;
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret)
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 4edb4be46c..df6f32850e 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -30,6 +30,7 @@ struct sunxi_mmc_priv {
uint32_t *mclkreg;
unsigned fatal_err;
struct gpio_desc cd_gpio; /* Change Detect GPIO */
+ int cd_inverted; /* Inverted Card Detect */
struct sunxi_mmc *reg;
struct mmc_config cfg;
};
@@ -544,9 +545,11 @@ static int sunxi_mmc_getcd(struct udevice *dev)
{
struct sunxi_mmc_priv *priv = dev_get_priv(dev);
- if (dm_gpio_is_valid(&priv->cd_gpio))
- return dm_gpio_get_value(&priv->cd_gpio);
+ if (dm_gpio_is_valid(&priv->cd_gpio)) {
+ int cd_state = dm_gpio_get_value(&priv->cd_gpio);
+ return cd_state ^ priv->cd_inverted;
+ }
return 1;
}
@@ -610,6 +613,9 @@ static int sunxi_mmc_probe(struct udevice *dev)
sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
}
+ /* Check if card detect is inverted */
+ priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
+
upriv->mmc = &plat->mmc;
/* Reset controller */
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c
new file mode 100644
index 0000000000..5f1c9c0bd4
--- /dev/null
+++ b/drivers/mmc/tmio-common.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <fdtdec.h>
+#include <mmc.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <linux/compat.h>
+#include <linux/dma-direction.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <power/regulator.h>
+#include <asm/unaligned.h>
+
+#include "tmio-common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u64 tmio_sd_readq(struct tmio_sd_priv *priv, unsigned int reg)
+{
+ return readq(priv->regbase + (reg << 1));
+}
+
+static void tmio_sd_writeq(struct tmio_sd_priv *priv,
+ u64 val, unsigned int reg)
+{
+ writeq(val, priv->regbase + (reg << 1));
+}
+
+static u16 tmio_sd_readw(struct tmio_sd_priv *priv, unsigned int reg)
+{
+ return readw(priv->regbase + (reg >> 1));
+}
+
+static void tmio_sd_writew(struct tmio_sd_priv *priv,
+ u16 val, unsigned int reg)
+{
+ writew(val, priv->regbase + (reg >> 1));
+}
+
+u32 tmio_sd_readl(struct tmio_sd_priv *priv, unsigned int reg)
+{
+ u32 val;
+
+ if (priv->caps & TMIO_SD_CAP_64BIT)
+ return readl(priv->regbase + (reg << 1));
+ else if (priv->caps & TMIO_SD_CAP_16BIT) {
+ val = readw(priv->regbase + (reg >> 1)) & 0xffff;
+ if ((reg == TMIO_SD_RSP10) || (reg == TMIO_SD_RSP32) ||
+ (reg == TMIO_SD_RSP54) || (reg == TMIO_SD_RSP76)) {
+ val |= readw(priv->regbase + (reg >> 1) + 2) << 16;
+ }
+ return val;
+ } else
+ return readl(priv->regbase + reg);
+}
+
+void tmio_sd_writel(struct tmio_sd_priv *priv,
+ u32 val, unsigned int reg)
+{
+ if (priv->caps & TMIO_SD_CAP_64BIT)
+ writel(val, priv->regbase + (reg << 1));
+ else if (priv->caps & TMIO_SD_CAP_16BIT) {
+ writew(val & 0xffff, priv->regbase + (reg >> 1));
+ if (reg == TMIO_SD_INFO1 || reg == TMIO_SD_INFO1_MASK ||
+ reg == TMIO_SD_INFO2 || reg == TMIO_SD_INFO2_MASK ||
+ reg == TMIO_SD_ARG)
+ writew(val >> 16, priv->regbase + (reg >> 1) + 2);
+ } else
+ writel(val, priv->regbase + reg);
+}
+
+static dma_addr_t __dma_map_single(void *ptr, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned long addr = (unsigned long)ptr;
+
+ if (dir == DMA_FROM_DEVICE)
+ invalidate_dcache_range(addr, addr + size);
+ else
+ flush_dcache_range(addr, addr + size);
+
+ return addr;
+}
+
+static void __dma_unmap_single(dma_addr_t addr, size_t size,
+ enum dma_data_direction dir)
+{
+ if (dir != DMA_TO_DEVICE)
+ invalidate_dcache_range(addr, addr + size);
+}
+
+static int tmio_sd_check_error(struct udevice *dev)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ u32 info2 = tmio_sd_readl(priv, TMIO_SD_INFO2);
+
+ if (info2 & TMIO_SD_INFO2_ERR_RTO) {
+ /*
+ * TIMEOUT must be returned for unsupported command. Do not
+ * display error log since this might be a part of sequence to
+ * distinguish between SD and MMC.
+ */
+ return -ETIMEDOUT;
+ }
+
+ if (info2 & TMIO_SD_INFO2_ERR_TO) {
+ dev_err(dev, "timeout error\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info2 & (TMIO_SD_INFO2_ERR_END | TMIO_SD_INFO2_ERR_CRC |
+ TMIO_SD_INFO2_ERR_IDX)) {
+ dev_err(dev, "communication out of sync\n");
+ return -EILSEQ;
+ }
+
+ if (info2 & (TMIO_SD_INFO2_ERR_ILA | TMIO_SD_INFO2_ERR_ILR |
+ TMIO_SD_INFO2_ERR_ILW)) {
+ dev_err(dev, "illegal access\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tmio_sd_wait_for_irq(struct udevice *dev, unsigned int reg,
+ u32 flag)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ long wait = 1000000;
+ int ret;
+
+ while (!(tmio_sd_readl(priv, reg) & flag)) {
+ if (wait-- < 0) {
+ dev_err(dev, "timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ ret = tmio_sd_check_error(dev);
+ if (ret)
+ return ret;
+
+ udelay(1);
+ }
+
+ return 0;
+}
+
+#define tmio_pio_read_fifo(__width, __suffix) \
+static void tmio_pio_read_fifo_##__width(struct tmio_sd_priv *priv, \
+ char *pbuf, uint blksz) \
+{ \
+ u##__width *buf = (u##__width *)pbuf; \
+ int i; \
+ \
+ if (likely(IS_ALIGNED((uintptr_t)buf, ((__width) / 8)))) { \
+ for (i = 0; i < blksz / ((__width) / 8); i++) { \
+ *buf++ = tmio_sd_read##__suffix(priv, \
+ TMIO_SD_BUF); \
+ } \
+ } else { \
+ for (i = 0; i < blksz / ((__width) / 8); i++) { \
+ u##__width data; \
+ data = tmio_sd_read##__suffix(priv, \
+ TMIO_SD_BUF); \
+ put_unaligned(data, buf++); \
+ } \
+ } \
+}
+
+tmio_pio_read_fifo(64, q)
+tmio_pio_read_fifo(32, l)
+tmio_pio_read_fifo(16, w)
+
+static int tmio_sd_pio_read_one_block(struct udevice *dev, char *pbuf,
+ uint blocksize)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* wait until the buffer is filled with data */
+ ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2,
+ TMIO_SD_INFO2_BRE);
+ if (ret)
+ return ret;
+
+ /*
+ * Clear the status flag _before_ read the buffer out because
+ * TMIO_SD_INFO2_BRE is edge-triggered, not level-triggered.
+ */
+ tmio_sd_writel(priv, 0, TMIO_SD_INFO2);
+
+ if (priv->caps & TMIO_SD_CAP_64BIT)
+ tmio_pio_read_fifo_64(priv, pbuf, blocksize);
+ else if (priv->caps & TMIO_SD_CAP_16BIT)
+ tmio_pio_read_fifo_16(priv, pbuf, blocksize);
+ else
+ tmio_pio_read_fifo_32(priv, pbuf, blocksize);
+
+ return 0;
+}
+
+#define tmio_pio_write_fifo(__width, __suffix) \
+static void tmio_pio_write_fifo_##__width(struct tmio_sd_priv *priv, \
+ const char *pbuf, uint blksz)\
+{ \
+ const u##__width *buf = (const u##__width *)pbuf; \
+ int i; \
+ \
+ if (likely(IS_ALIGNED((uintptr_t)buf, ((__width) / 8)))) { \
+ for (i = 0; i < blksz / ((__width) / 8); i++) { \
+ tmio_sd_write##__suffix(priv, *buf++, \
+ TMIO_SD_BUF); \
+ } \
+ } else { \
+ for (i = 0; i < blksz / ((__width) / 8); i++) { \
+ u##__width data = get_unaligned(buf++); \
+ tmio_sd_write##__suffix(priv, data, \
+ TMIO_SD_BUF); \
+ } \
+ } \
+}
+
+tmio_pio_write_fifo(64, q)
+tmio_pio_write_fifo(32, l)
+tmio_pio_write_fifo(16, w)
+
+static int tmio_sd_pio_write_one_block(struct udevice *dev,
+ const char *pbuf, uint blocksize)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* wait until the buffer becomes empty */
+ ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2,
+ TMIO_SD_INFO2_BWE);
+ if (ret)
+ return ret;
+
+ tmio_sd_writel(priv, 0, TMIO_SD_INFO2);
+
+ if (priv->caps & TMIO_SD_CAP_64BIT)
+ tmio_pio_write_fifo_64(priv, pbuf, blocksize);
+ else if (priv->caps & TMIO_SD_CAP_16BIT)
+ tmio_pio_write_fifo_16(priv, pbuf, blocksize);
+ else
+ tmio_pio_write_fifo_32(priv, pbuf, blocksize);
+
+ return 0;
+}
+
+static int tmio_sd_pio_xfer(struct udevice *dev, struct mmc_data *data)
+{
+ const char *src = data->src;
+ char *dest = data->dest;
+ int i, ret;
+
+ for (i = 0; i < data->blocks; i++) {
+ if (data->flags & MMC_DATA_READ)
+ ret = tmio_sd_pio_read_one_block(dev, dest,
+ data->blocksize);
+ else
+ ret = tmio_sd_pio_write_one_block(dev, src,
+ data->blocksize);
+ if (ret)
+ return ret;
+
+ if (data->flags & MMC_DATA_READ)
+ dest += data->blocksize;
+ else
+ src += data->blocksize;
+ }
+
+ return 0;
+}
+
+static void tmio_sd_dma_start(struct tmio_sd_priv *priv,
+ dma_addr_t dma_addr)
+{
+ u32 tmp;
+
+ tmio_sd_writel(priv, 0, TMIO_SD_DMA_INFO1);
+ tmio_sd_writel(priv, 0, TMIO_SD_DMA_INFO2);
+
+ /* enable DMA */
+ tmp = tmio_sd_readl(priv, TMIO_SD_EXTMODE);
+ tmp |= TMIO_SD_EXTMODE_DMA_EN;
+ tmio_sd_writel(priv, tmp, TMIO_SD_EXTMODE);
+
+ tmio_sd_writel(priv, dma_addr & U32_MAX, TMIO_SD_DMA_ADDR_L);
+
+ /* suppress the warning "right shift count >= width of type" */
+ dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr));
+
+ tmio_sd_writel(priv, dma_addr & U32_MAX, TMIO_SD_DMA_ADDR_H);
+
+ tmio_sd_writel(priv, TMIO_SD_DMA_CTL_START, TMIO_SD_DMA_CTL);
+}
+
+static int tmio_sd_dma_wait_for_irq(struct udevice *dev, u32 flag,
+ unsigned int blocks)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ long wait = 1000000 + 10 * blocks;
+
+ while (!(tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)) {
+ if (wait-- < 0) {
+ dev_err(dev, "timeout during DMA\n");
+ return -ETIMEDOUT;
+ }
+
+ udelay(10);
+ }
+
+ if (tmio_sd_readl(priv, TMIO_SD_DMA_INFO2)) {
+ dev_err(dev, "error during DMA\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ size_t len = data->blocks * data->blocksize;
+ void *buf;
+ enum dma_data_direction dir;
+ dma_addr_t dma_addr;
+ u32 poll_flag, tmp;
+ int ret;
+
+ tmp = tmio_sd_readl(priv, TMIO_SD_DMA_MODE);
+
+ if (data->flags & MMC_DATA_READ) {
+ buf = data->dest;
+ dir = DMA_FROM_DEVICE;
+ /*
+ * The DMA READ completion flag position differs on Socionext
+ * and Renesas SoCs. It is bit 20 on Socionext SoCs and using
+ * bit 17 is a hardware bug and forbidden. It is bit 17 on
+ * Renesas SoCs and bit 20 does not work on them.
+ */
+ poll_flag = (priv->caps & TMIO_SD_CAP_RCAR) ?
+ TMIO_SD_DMA_INFO1_END_RD :
+ TMIO_SD_DMA_INFO1_END_RD2;
+ tmp |= TMIO_SD_DMA_MODE_DIR_RD;
+ } else {
+ buf = (void *)data->src;
+ dir = DMA_TO_DEVICE;
+ poll_flag = TMIO_SD_DMA_INFO1_END_WR;
+ tmp &= ~TMIO_SD_DMA_MODE_DIR_RD;
+ }
+
+ tmio_sd_writel(priv, tmp, TMIO_SD_DMA_MODE);
+
+ dma_addr = __dma_map_single(buf, len, dir);
+
+ tmio_sd_dma_start(priv, dma_addr);
+
+ ret = tmio_sd_dma_wait_for_irq(dev, poll_flag, data->blocks);
+
+ __dma_unmap_single(dma_addr, len, dir);
+
+ return ret;
+}
+
+/* check if the address is DMA'able */
+static bool tmio_sd_addr_is_dmaable(unsigned long addr)
+{
+ if (!IS_ALIGNED(addr, TMIO_SD_DMA_MINALIGN))
+ return false;
+
+#if defined(CONFIG_ARCH_UNIPHIER) && !defined(CONFIG_ARM64) && \
+ defined(CONFIG_SPL_BUILD)
+ /*
+ * For UniPhier ARMv7 SoCs, the stack is allocated in the locked ways
+ * of L2, which is unreachable from the DMA engine.
+ */
+ if (addr < CONFIG_SPL_STACK)
+ return false;
+#endif
+
+ return true;
+}
+
+int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ int ret;
+ u32 tmp;
+
+ if (tmio_sd_readl(priv, TMIO_SD_INFO2) & TMIO_SD_INFO2_CBSY) {
+ dev_err(dev, "command busy\n");
+ return -EBUSY;
+ }
+
+ /* clear all status flags */
+ tmio_sd_writel(priv, 0, TMIO_SD_INFO1);
+ tmio_sd_writel(priv, 0, TMIO_SD_INFO2);
+
+ /* disable DMA once */
+ tmp = tmio_sd_readl(priv, TMIO_SD_EXTMODE);
+ tmp &= ~TMIO_SD_EXTMODE_DMA_EN;
+ tmio_sd_writel(priv, tmp, TMIO_SD_EXTMODE);
+
+ tmio_sd_writel(priv, cmd->cmdarg, TMIO_SD_ARG);
+
+ tmp = cmd->cmdidx;
+
+ if (data) {
+ tmio_sd_writel(priv, data->blocksize, TMIO_SD_SIZE);
+ tmio_sd_writel(priv, data->blocks, TMIO_SD_SECCNT);
+
+ /* Do not send CMD12 automatically */
+ tmp |= TMIO_SD_CMD_NOSTOP | TMIO_SD_CMD_DATA;
+
+ if (data->blocks > 1)
+ tmp |= TMIO_SD_CMD_MULTI;
+
+ if (data->flags & MMC_DATA_READ)
+ tmp |= TMIO_SD_CMD_RD;
+ }
+
+ /*
+ * Do not use the response type auto-detection on this hardware.
+ * CMD8, for example, has different response types on SD and eMMC,
+ * while this controller always assumes the response type for SD.
+ * Set the response type manually.
+ */
+ switch (cmd->resp_type) {
+ case MMC_RSP_NONE:
+ tmp |= TMIO_SD_CMD_RSP_NONE;
+ break;
+ case MMC_RSP_R1:
+ tmp |= TMIO_SD_CMD_RSP_R1;
+ break;
+ case MMC_RSP_R1b:
+ tmp |= TMIO_SD_CMD_RSP_R1B;
+ break;
+ case MMC_RSP_R2:
+ tmp |= TMIO_SD_CMD_RSP_R2;
+ break;
+ case MMC_RSP_R3:
+ tmp |= TMIO_SD_CMD_RSP_R3;
+ break;
+ default:
+ dev_err(dev, "unknown response type\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n",
+ cmd->cmdidx, tmp, cmd->cmdarg);
+ tmio_sd_writel(priv, tmp, TMIO_SD_CMD);
+
+ ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO1,
+ TMIO_SD_INFO1_RSP);
+ if (ret)
+ return ret;
+
+ if (cmd->resp_type & MMC_RSP_136) {
+ u32 rsp_127_104 = tmio_sd_readl(priv, TMIO_SD_RSP76);
+ u32 rsp_103_72 = tmio_sd_readl(priv, TMIO_SD_RSP54);
+ u32 rsp_71_40 = tmio_sd_readl(priv, TMIO_SD_RSP32);
+ u32 rsp_39_8 = tmio_sd_readl(priv, TMIO_SD_RSP10);
+
+ cmd->response[0] = ((rsp_127_104 & 0x00ffffff) << 8) |
+ ((rsp_103_72 & 0xff000000) >> 24);
+ cmd->response[1] = ((rsp_103_72 & 0x00ffffff) << 8) |
+ ((rsp_71_40 & 0xff000000) >> 24);
+ cmd->response[2] = ((rsp_71_40 & 0x00ffffff) << 8) |
+ ((rsp_39_8 & 0xff000000) >> 24);
+ cmd->response[3] = (rsp_39_8 & 0xffffff) << 8;
+ } else {
+ /* bit 39-8 */
+ cmd->response[0] = tmio_sd_readl(priv, TMIO_SD_RSP10);
+ }
+
+ if (data) {
+ /* use DMA if the HW supports it and the buffer is aligned */
+ if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL &&
+ tmio_sd_addr_is_dmaable((long)data->src))
+ ret = tmio_sd_dma_xfer(dev, data);
+ else
+ ret = tmio_sd_pio_xfer(dev, data);
+
+ ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO1,
+ TMIO_SD_INFO1_CMP);
+ if (ret)
+ return ret;
+ }
+
+ tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2, TMIO_SD_INFO2_SCLKDIVEN);
+
+ return ret;
+}
+
+static int tmio_sd_set_bus_width(struct tmio_sd_priv *priv,
+ struct mmc *mmc)
+{
+ u32 val, tmp;
+
+ switch (mmc->bus_width) {
+ case 0:
+ case 1:
+ val = TMIO_SD_OPTION_WIDTH_1;
+ break;
+ case 4:
+ val = TMIO_SD_OPTION_WIDTH_4;
+ break;
+ case 8:
+ val = TMIO_SD_OPTION_WIDTH_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = tmio_sd_readl(priv, TMIO_SD_OPTION);
+ tmp &= ~TMIO_SD_OPTION_WIDTH_MASK;
+ tmp |= val;
+ tmio_sd_writel(priv, tmp, TMIO_SD_OPTION);
+
+ return 0;
+}
+
+static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv,
+ struct mmc *mmc)
+{
+ u32 tmp;
+
+ tmp = tmio_sd_readl(priv, TMIO_SD_IF_MODE);
+ if (mmc->ddr_mode)
+ tmp |= TMIO_SD_IF_MODE_DDR;
+ else
+ tmp &= ~TMIO_SD_IF_MODE_DDR;
+ tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE);
+}
+
+static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv,
+ struct mmc *mmc)
+{
+ unsigned int divisor;
+ u32 val, tmp;
+
+ if (!mmc->clock)
+ return;
+
+ divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
+
+ if (divisor <= 1)
+ val = (priv->caps & TMIO_SD_CAP_RCAR) ?
+ TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1;
+ else if (divisor <= 2)
+ val = TMIO_SD_CLKCTL_DIV2;
+ else if (divisor <= 4)
+ val = TMIO_SD_CLKCTL_DIV4;
+ else if (divisor <= 8)
+ val = TMIO_SD_CLKCTL_DIV8;
+ else if (divisor <= 16)
+ val = TMIO_SD_CLKCTL_DIV16;
+ else if (divisor <= 32)
+ val = TMIO_SD_CLKCTL_DIV32;
+ else if (divisor <= 64)
+ val = TMIO_SD_CLKCTL_DIV64;
+ else if (divisor <= 128)
+ val = TMIO_SD_CLKCTL_DIV128;
+ else if (divisor <= 256)
+ val = TMIO_SD_CLKCTL_DIV256;
+ else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024))
+ val = TMIO_SD_CLKCTL_DIV512;
+ else
+ val = TMIO_SD_CLKCTL_DIV1024;
+
+ tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
+ if (tmp & TMIO_SD_CLKCTL_SCLKEN &&
+ (tmp & TMIO_SD_CLKCTL_DIV_MASK) == val)
+ return;
+
+ /* stop the clock before changing its rate to avoid a glitch signal */
+ tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
+
+ tmp &= ~TMIO_SD_CLKCTL_DIV_MASK;
+ tmp |= val | TMIO_SD_CLKCTL_OFFEN;
+ tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
+
+ tmp |= TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
+
+ udelay(1000);
+}
+
+static void tmio_sd_set_pins(struct udevice *dev)
+{
+ __maybe_unused struct mmc *mmc = mmc_get_mmc_dev(dev);
+
+#ifdef CONFIG_DM_REGULATOR
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+
+ if (priv->vqmmc_dev) {
+ if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
+ regulator_set_value(priv->vqmmc_dev, 1800000);
+ else
+ regulator_set_value(priv->vqmmc_dev, 3300000);
+ regulator_set_enable(priv->vqmmc_dev, true);
+ }
+#endif
+
+#ifdef CONFIG_PINCTRL
+ switch (mmc->selected_mode) {
+ case MMC_LEGACY:
+ case SD_LEGACY:
+ case MMC_HS:
+ case SD_HS:
+ case MMC_HS_52:
+ case MMC_DDR_52:
+ pinctrl_select_state(dev, "default");
+ break;
+ case UHS_SDR12:
+ case UHS_SDR25:
+ case UHS_SDR50:
+ case UHS_DDR50:
+ case UHS_SDR104:
+ case MMC_HS_200:
+ pinctrl_select_state(dev, "state_uhs");
+ break;
+ default:
+ break;
+ }
+#endif
+}
+
+int tmio_sd_set_ios(struct udevice *dev)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+ int ret;
+
+ dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n",
+ mmc->clock, mmc->ddr_mode, mmc->bus_width);
+
+ ret = tmio_sd_set_bus_width(priv, mmc);
+ if (ret)
+ return ret;
+ tmio_sd_set_ddr_mode(priv, mmc);
+ tmio_sd_set_clk_rate(priv, mmc);
+ tmio_sd_set_pins(dev);
+
+ return 0;
+}
+
+int tmio_sd_get_cd(struct udevice *dev)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+
+ if (priv->caps & TMIO_SD_CAP_NONREMOVABLE)
+ return 1;
+
+ return !!(tmio_sd_readl(priv, TMIO_SD_INFO1) &
+ TMIO_SD_INFO1_CD);
+}
+
+static void tmio_sd_host_init(struct tmio_sd_priv *priv)
+{
+ u32 tmp;
+
+ /* soft reset of the host */
+ tmp = tmio_sd_readl(priv, TMIO_SD_SOFT_RST);
+ tmp &= ~TMIO_SD_SOFT_RST_RSTX;
+ tmio_sd_writel(priv, tmp, TMIO_SD_SOFT_RST);
+ tmp |= TMIO_SD_SOFT_RST_RSTX;
+ tmio_sd_writel(priv, tmp, TMIO_SD_SOFT_RST);
+
+ /* FIXME: implement eMMC hw_reset */
+
+ tmio_sd_writel(priv, TMIO_SD_STOP_SEC, TMIO_SD_STOP);
+
+ /*
+ * Connected to 32bit AXI.
+ * This register dropped backward compatibility at version 0x10.
+ * Write an appropriate value depending on the IP version.
+ */
+ if (priv->version >= 0x10)
+ tmio_sd_writel(priv, 0x101, TMIO_SD_HOST_MODE);
+ else
+ tmio_sd_writel(priv, 0x0, TMIO_SD_HOST_MODE);
+
+ if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL) {
+ tmp = tmio_sd_readl(priv, TMIO_SD_DMA_MODE);
+ tmp |= TMIO_SD_DMA_MODE_ADDR_INC;
+ tmio_sd_writel(priv, tmp, TMIO_SD_DMA_MODE);
+ }
+}
+
+int tmio_sd_bind(struct udevice *dev)
+{
+ struct tmio_sd_plat *plat = dev_get_platdata(dev);
+
+ return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+int tmio_sd_probe(struct udevice *dev, u32 quirks)
+{
+ struct tmio_sd_plat *plat = dev_get_platdata(dev);
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ fdt_addr_t base;
+ struct clk clk;
+ int ret;
+
+ base = devfdt_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regbase = devm_ioremap(dev, base, SZ_2K);
+ if (!priv->regbase)
+ return -ENOMEM;
+
+#ifdef CONFIG_DM_REGULATOR
+ device_get_supply_regulator(dev, "vqmmc-supply", &priv->vqmmc_dev);
+#endif
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to get host clock\n");
+ return ret;
+ }
+
+ /* set to max rate */
+ priv->mclk = clk_set_rate(&clk, ULONG_MAX);
+ if (IS_ERR_VALUE(priv->mclk)) {
+ dev_err(dev, "failed to set rate for host clock\n");
+ clk_free(&clk);
+ return priv->mclk;
+ }
+
+ ret = clk_enable(&clk);
+ clk_free(&clk);
+ if (ret) {
+ dev_err(dev, "failed to enable host clock\n");
+ return ret;
+ }
+
+ ret = mmc_of_parse(dev, &plat->cfg);
+ if (ret < 0) {
+ dev_err(dev, "failed to parse host caps\n");
+ return ret;
+ }
+
+ plat->cfg.name = dev->name;
+ plat->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+ if (quirks)
+ priv->caps = quirks;
+
+ priv->version = tmio_sd_readl(priv, TMIO_SD_VERSION) &
+ TMIO_SD_VERSION_IP;
+ dev_dbg(dev, "version %x\n", priv->version);
+ if (priv->version >= 0x10) {
+ priv->caps |= TMIO_SD_CAP_DMA_INTERNAL;
+ priv->caps |= TMIO_SD_CAP_DIV1024;
+ }
+
+ if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",
+ NULL))
+ priv->caps |= TMIO_SD_CAP_NONREMOVABLE;
+
+ tmio_sd_host_init(priv);
+
+ plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+ plat->cfg.f_min = priv->mclk /
+ (priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512);
+ plat->cfg.f_max = priv->mclk;
+ plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */
+
+ upriv->mmc = &plat->mmc;
+
+ return 0;
+}
diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h
new file mode 100644
index 0000000000..ef9404409d
--- /dev/null
+++ b/drivers/mmc/tmio-common.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __TMIO_COMMON_H__
+#define __TMIO_COMMON_H__
+
+#define TMIO_SD_CMD 0x000 /* command */
+#define TMIO_SD_CMD_NOSTOP BIT(14) /* No automatic CMD12 issue */
+#define TMIO_SD_CMD_MULTI BIT(13) /* multiple block transfer */
+#define TMIO_SD_CMD_RD BIT(12) /* 1: read, 0: write */
+#define TMIO_SD_CMD_DATA BIT(11) /* data transfer */
+#define TMIO_SD_CMD_APP BIT(6) /* ACMD preceded by CMD55 */
+#define TMIO_SD_CMD_NORMAL (0 << 8)/* auto-detect of resp-type */
+#define TMIO_SD_CMD_RSP_NONE (3 << 8)/* response: none */
+#define TMIO_SD_CMD_RSP_R1 (4 << 8)/* response: R1, R5, R6, R7 */
+#define TMIO_SD_CMD_RSP_R1B (5 << 8)/* response: R1b, R5b */
+#define TMIO_SD_CMD_RSP_R2 (6 << 8)/* response: R2 */
+#define TMIO_SD_CMD_RSP_R3 (7 << 8)/* response: R3, R4 */
+#define TMIO_SD_ARG 0x008 /* command argument */
+#define TMIO_SD_STOP 0x010 /* stop action control */
+#define TMIO_SD_STOP_SEC BIT(8) /* use sector count */
+#define TMIO_SD_STOP_STP BIT(0) /* issue CMD12 */
+#define TMIO_SD_SECCNT 0x014 /* sector counter */
+#define TMIO_SD_RSP10 0x018 /* response[39:8] */
+#define TMIO_SD_RSP32 0x020 /* response[71:40] */
+#define TMIO_SD_RSP54 0x028 /* response[103:72] */
+#define TMIO_SD_RSP76 0x030 /* response[127:104] */
+#define TMIO_SD_INFO1 0x038 /* IRQ status 1 */
+#define TMIO_SD_INFO1_CD BIT(5) /* state of card detect */
+#define TMIO_SD_INFO1_INSERT BIT(4) /* card inserted */
+#define TMIO_SD_INFO1_REMOVE BIT(3) /* card removed */
+#define TMIO_SD_INFO1_CMP BIT(2) /* data complete */
+#define TMIO_SD_INFO1_RSP BIT(0) /* response complete */
+#define TMIO_SD_INFO2 0x03c /* IRQ status 2 */
+#define TMIO_SD_INFO2_ERR_ILA BIT(15) /* illegal access err */
+#define TMIO_SD_INFO2_CBSY BIT(14) /* command busy */
+#define TMIO_SD_INFO2_SCLKDIVEN BIT(13) /* command setting reg ena */
+#define TMIO_SD_INFO2_BWE BIT(9) /* write buffer ready */
+#define TMIO_SD_INFO2_BRE BIT(8) /* read buffer ready */
+#define TMIO_SD_INFO2_DAT0 BIT(7) /* SDDAT0 */
+#define TMIO_SD_INFO2_ERR_RTO BIT(6) /* response time out */
+#define TMIO_SD_INFO2_ERR_ILR BIT(5) /* illegal read err */
+#define TMIO_SD_INFO2_ERR_ILW BIT(4) /* illegal write err */
+#define TMIO_SD_INFO2_ERR_TO BIT(3) /* time out error */
+#define TMIO_SD_INFO2_ERR_END BIT(2) /* END bit error */
+#define TMIO_SD_INFO2_ERR_CRC BIT(1) /* CRC error */
+#define TMIO_SD_INFO2_ERR_IDX BIT(0) /* cmd index error */
+#define TMIO_SD_INFO1_MASK 0x040
+#define TMIO_SD_INFO2_MASK 0x044
+#define TMIO_SD_CLKCTL 0x048 /* clock divisor */
+#define TMIO_SD_CLKCTL_DIV_MASK 0x104ff
+#define TMIO_SD_CLKCTL_DIV1024 BIT(16) /* SDCLK = CLK / 1024 */
+#define TMIO_SD_CLKCTL_DIV512 BIT(7) /* SDCLK = CLK / 512 */
+#define TMIO_SD_CLKCTL_DIV256 BIT(6) /* SDCLK = CLK / 256 */
+#define TMIO_SD_CLKCTL_DIV128 BIT(5) /* SDCLK = CLK / 128 */
+#define TMIO_SD_CLKCTL_DIV64 BIT(4) /* SDCLK = CLK / 64 */
+#define TMIO_SD_CLKCTL_DIV32 BIT(3) /* SDCLK = CLK / 32 */
+#define TMIO_SD_CLKCTL_DIV16 BIT(2) /* SDCLK = CLK / 16 */
+#define TMIO_SD_CLKCTL_DIV8 BIT(1) /* SDCLK = CLK / 8 */
+#define TMIO_SD_CLKCTL_DIV4 BIT(0) /* SDCLK = CLK / 4 */
+#define TMIO_SD_CLKCTL_DIV2 0 /* SDCLK = CLK / 2 */
+#define TMIO_SD_CLKCTL_DIV1 BIT(10) /* SDCLK = CLK */
+#define TMIO_SD_CLKCTL_RCAR_DIV1 0xff /* SDCLK = CLK (RCar ver.) */
+#define TMIO_SD_CLKCTL_OFFEN BIT(9) /* stop SDCLK when unused */
+#define TMIO_SD_CLKCTL_SCLKEN BIT(8) /* SDCLK output enable */
+#define TMIO_SD_SIZE 0x04c /* block size */
+#define TMIO_SD_OPTION 0x050
+#define TMIO_SD_OPTION_WIDTH_MASK (5 << 13)
+#define TMIO_SD_OPTION_WIDTH_1 (4 << 13)
+#define TMIO_SD_OPTION_WIDTH_4 (0 << 13)
+#define TMIO_SD_OPTION_WIDTH_8 (1 << 13)
+#define TMIO_SD_BUF 0x060 /* read/write buffer */
+#define TMIO_SD_EXTMODE 0x1b0
+#define TMIO_SD_EXTMODE_DMA_EN BIT(1) /* transfer 1: DMA, 0: pio */
+#define TMIO_SD_SOFT_RST 0x1c0
+#define TMIO_SD_SOFT_RST_RSTX BIT(0) /* reset deassert */
+#define TMIO_SD_VERSION 0x1c4 /* version register */
+#define TMIO_SD_VERSION_IP 0xff /* IP version */
+#define TMIO_SD_HOST_MODE 0x1c8
+#define TMIO_SD_IF_MODE 0x1cc
+#define TMIO_SD_IF_MODE_DDR BIT(0) /* DDR mode */
+#define TMIO_SD_VOLT 0x1e4 /* voltage switch */
+#define TMIO_SD_VOLT_MASK (3 << 0)
+#define TMIO_SD_VOLT_OFF (0 << 0)
+#define TMIO_SD_VOLT_330 (1 << 0)/* 3.3V signal */
+#define TMIO_SD_VOLT_180 (2 << 0)/* 1.8V signal */
+#define TMIO_SD_DMA_MODE 0x410
+#define TMIO_SD_DMA_MODE_DIR_RD BIT(16) /* 1: from device, 0: to dev */
+#define TMIO_SD_DMA_MODE_ADDR_INC BIT(0) /* 1: address inc, 0: fixed */
+#define TMIO_SD_DMA_CTL 0x414
+#define TMIO_SD_DMA_CTL_START BIT(0) /* start DMA (auto cleared) */
+#define TMIO_SD_DMA_RST 0x418
+#define TMIO_SD_DMA_RST_RD BIT(9)
+#define TMIO_SD_DMA_RST_WR BIT(8)
+#define TMIO_SD_DMA_INFO1 0x420
+#define TMIO_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete (uniphier) */
+#define TMIO_SD_DMA_INFO1_END_RD BIT(17) /* DMA from device is complete (renesas) */
+#define TMIO_SD_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */
+#define TMIO_SD_DMA_INFO1_MASK 0x424
+#define TMIO_SD_DMA_INFO2 0x428
+#define TMIO_SD_DMA_INFO2_ERR_RD BIT(17)
+#define TMIO_SD_DMA_INFO2_ERR_WR BIT(16)
+#define TMIO_SD_DMA_INFO2_MASK 0x42c
+#define TMIO_SD_DMA_ADDR_L 0x440
+#define TMIO_SD_DMA_ADDR_H 0x444
+
+/* alignment required by the DMA engine of this controller */
+#define TMIO_SD_DMA_MINALIGN 0x10
+
+struct tmio_sd_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+struct tmio_sd_priv {
+ void __iomem *regbase;
+ unsigned long mclk;
+ unsigned int version;
+ u32 caps;
+#define TMIO_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */
+#define TMIO_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */
+#define TMIO_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */
+#define TMIO_SD_CAP_64BIT BIT(3) /* Controller is 64bit */
+#define TMIO_SD_CAP_16BIT BIT(4) /* Controller is 16bit */
+#define TMIO_SD_CAP_RCAR_GEN2 BIT(5) /* Renesas RCar version of IP */
+#define TMIO_SD_CAP_RCAR_GEN3 BIT(6) /* Renesas RCar version of IP */
+#define TMIO_SD_CAP_RCAR_UHS BIT(7) /* Renesas RCar UHS/SDR modes */
+#define TMIO_SD_CAP_RCAR \
+ (TMIO_SD_CAP_RCAR_GEN2 | TMIO_SD_CAP_RCAR_GEN3)
+#ifdef CONFIG_DM_REGULATOR
+ struct udevice *vqmmc_dev;
+#endif
+};
+
+int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data);
+int tmio_sd_set_ios(struct udevice *dev);
+int tmio_sd_get_cd(struct udevice *dev);
+
+int tmio_sd_bind(struct udevice *dev);
+int tmio_sd_probe(struct udevice *dev, u32 quirks);
+
+u32 tmio_sd_readl(struct tmio_sd_priv *priv, unsigned int reg);
+void tmio_sd_writel(struct tmio_sd_priv *priv,
+ u32 val, unsigned int reg);
+
+#endif /* __TMIO_COMMON_H__ */
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c
index 525b1702b9..47379b0328 100644
--- a/drivers/mmc/uniphier-sd.c
+++ b/drivers/mmc/uniphier-sd.c
@@ -17,857 +17,31 @@
#include <power/regulator.h>
#include <asm/unaligned.h>
-DECLARE_GLOBAL_DATA_PTR;
-
-#define UNIPHIER_SD_CMD 0x000 /* command */
-#define UNIPHIER_SD_CMD_NOSTOP BIT(14) /* No automatic CMD12 issue */
-#define UNIPHIER_SD_CMD_MULTI BIT(13) /* multiple block transfer */
-#define UNIPHIER_SD_CMD_RD BIT(12) /* 1: read, 0: write */
-#define UNIPHIER_SD_CMD_DATA BIT(11) /* data transfer */
-#define UNIPHIER_SD_CMD_APP BIT(6) /* ACMD preceded by CMD55 */
-#define UNIPHIER_SD_CMD_NORMAL (0 << 8)/* auto-detect of resp-type */
-#define UNIPHIER_SD_CMD_RSP_NONE (3 << 8)/* response: none */
-#define UNIPHIER_SD_CMD_RSP_R1 (4 << 8)/* response: R1, R5, R6, R7 */
-#define UNIPHIER_SD_CMD_RSP_R1B (5 << 8)/* response: R1b, R5b */
-#define UNIPHIER_SD_CMD_RSP_R2 (6 << 8)/* response: R2 */
-#define UNIPHIER_SD_CMD_RSP_R3 (7 << 8)/* response: R3, R4 */
-#define UNIPHIER_SD_ARG 0x008 /* command argument */
-#define UNIPHIER_SD_STOP 0x010 /* stop action control */
-#define UNIPHIER_SD_STOP_SEC BIT(8) /* use sector count */
-#define UNIPHIER_SD_STOP_STP BIT(0) /* issue CMD12 */
-#define UNIPHIER_SD_SECCNT 0x014 /* sector counter */
-#define UNIPHIER_SD_RSP10 0x018 /* response[39:8] */
-#define UNIPHIER_SD_RSP32 0x020 /* response[71:40] */
-#define UNIPHIER_SD_RSP54 0x028 /* response[103:72] */
-#define UNIPHIER_SD_RSP76 0x030 /* response[127:104] */
-#define UNIPHIER_SD_INFO1 0x038 /* IRQ status 1 */
-#define UNIPHIER_SD_INFO1_CD BIT(5) /* state of card detect */
-#define UNIPHIER_SD_INFO1_INSERT BIT(4) /* card inserted */
-#define UNIPHIER_SD_INFO1_REMOVE BIT(3) /* card removed */
-#define UNIPHIER_SD_INFO1_CMP BIT(2) /* data complete */
-#define UNIPHIER_SD_INFO1_RSP BIT(0) /* response complete */
-#define UNIPHIER_SD_INFO2 0x03c /* IRQ status 2 */
-#define UNIPHIER_SD_INFO2_ERR_ILA BIT(15) /* illegal access err */
-#define UNIPHIER_SD_INFO2_CBSY BIT(14) /* command busy */
-#define UNIPHIER_SD_INFO2_BWE BIT(9) /* write buffer ready */
-#define UNIPHIER_SD_INFO2_BRE BIT(8) /* read buffer ready */
-#define UNIPHIER_SD_INFO2_DAT0 BIT(7) /* SDDAT0 */
-#define UNIPHIER_SD_INFO2_ERR_RTO BIT(6) /* response time out */
-#define UNIPHIER_SD_INFO2_ERR_ILR BIT(5) /* illegal read err */
-#define UNIPHIER_SD_INFO2_ERR_ILW BIT(4) /* illegal write err */
-#define UNIPHIER_SD_INFO2_ERR_TO BIT(3) /* time out error */
-#define UNIPHIER_SD_INFO2_ERR_END BIT(2) /* END bit error */
-#define UNIPHIER_SD_INFO2_ERR_CRC BIT(1) /* CRC error */
-#define UNIPHIER_SD_INFO2_ERR_IDX BIT(0) /* cmd index error */
-#define UNIPHIER_SD_INFO1_MASK 0x040
-#define UNIPHIER_SD_INFO2_MASK 0x044
-#define UNIPHIER_SD_CLKCTL 0x048 /* clock divisor */
-#define UNIPHIER_SD_CLKCTL_DIV_MASK 0x104ff
-#define UNIPHIER_SD_CLKCTL_DIV1024 BIT(16) /* SDCLK = CLK / 1024 */
-#define UNIPHIER_SD_CLKCTL_DIV512 BIT(7) /* SDCLK = CLK / 512 */
-#define UNIPHIER_SD_CLKCTL_DIV256 BIT(6) /* SDCLK = CLK / 256 */
-#define UNIPHIER_SD_CLKCTL_DIV128 BIT(5) /* SDCLK = CLK / 128 */
-#define UNIPHIER_SD_CLKCTL_DIV64 BIT(4) /* SDCLK = CLK / 64 */
-#define UNIPHIER_SD_CLKCTL_DIV32 BIT(3) /* SDCLK = CLK / 32 */
-#define UNIPHIER_SD_CLKCTL_DIV16 BIT(2) /* SDCLK = CLK / 16 */
-#define UNIPHIER_SD_CLKCTL_DIV8 BIT(1) /* SDCLK = CLK / 8 */
-#define UNIPHIER_SD_CLKCTL_DIV4 BIT(0) /* SDCLK = CLK / 4 */
-#define UNIPHIER_SD_CLKCTL_DIV2 0 /* SDCLK = CLK / 2 */
-#define UNIPHIER_SD_CLKCTL_DIV1 BIT(10) /* SDCLK = CLK */
-#define UNIPHIER_SD_CLKCTL_OFFEN BIT(9) /* stop SDCLK when unused */
-#define UNIPHIER_SD_CLKCTL_SCLKEN BIT(8) /* SDCLK output enable */
-#define UNIPHIER_SD_SIZE 0x04c /* block size */
-#define UNIPHIER_SD_OPTION 0x050
-#define UNIPHIER_SD_OPTION_WIDTH_MASK (5 << 13)
-#define UNIPHIER_SD_OPTION_WIDTH_1 (4 << 13)
-#define UNIPHIER_SD_OPTION_WIDTH_4 (0 << 13)
-#define UNIPHIER_SD_OPTION_WIDTH_8 (1 << 13)
-#define UNIPHIER_SD_BUF 0x060 /* read/write buffer */
-#define UNIPHIER_SD_EXTMODE 0x1b0
-#define UNIPHIER_SD_EXTMODE_DMA_EN BIT(1) /* transfer 1: DMA, 0: pio */
-#define UNIPHIER_SD_SOFT_RST 0x1c0
-#define UNIPHIER_SD_SOFT_RST_RSTX BIT(0) /* reset deassert */
-#define UNIPHIER_SD_VERSION 0x1c4 /* version register */
-#define UNIPHIER_SD_VERSION_IP 0xff /* IP version */
-#define UNIPHIER_SD_HOST_MODE 0x1c8
-#define UNIPHIER_SD_IF_MODE 0x1cc
-#define UNIPHIER_SD_IF_MODE_DDR BIT(0) /* DDR mode */
-#define UNIPHIER_SD_VOLT 0x1e4 /* voltage switch */
-#define UNIPHIER_SD_VOLT_MASK (3 << 0)
-#define UNIPHIER_SD_VOLT_OFF (0 << 0)
-#define UNIPHIER_SD_VOLT_330 (1 << 0)/* 3.3V signal */
-#define UNIPHIER_SD_VOLT_180 (2 << 0)/* 1.8V signal */
-#define UNIPHIER_SD_DMA_MODE 0x410
-#define UNIPHIER_SD_DMA_MODE_DIR_RD BIT(16) /* 1: from device, 0: to dev */
-#define UNIPHIER_SD_DMA_MODE_ADDR_INC BIT(0) /* 1: address inc, 0: fixed */
-#define UNIPHIER_SD_DMA_CTL 0x414
-#define UNIPHIER_SD_DMA_CTL_START BIT(0) /* start DMA (auto cleared) */
-#define UNIPHIER_SD_DMA_RST 0x418
-#define UNIPHIER_SD_DMA_RST_RD BIT(9)
-#define UNIPHIER_SD_DMA_RST_WR BIT(8)
-#define UNIPHIER_SD_DMA_INFO1 0x420
-#define UNIPHIER_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete*/
-#define UNIPHIER_SD_DMA_INFO1_END_RD BIT(17) /* Don't use! Hardware bug */
-#define UNIPHIER_SD_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */
-#define UNIPHIER_SD_DMA_INFO1_MASK 0x424
-#define UNIPHIER_SD_DMA_INFO2 0x428
-#define UNIPHIER_SD_DMA_INFO2_ERR_RD BIT(17)
-#define UNIPHIER_SD_DMA_INFO2_ERR_WR BIT(16)
-#define UNIPHIER_SD_DMA_INFO2_MASK 0x42c
-#define UNIPHIER_SD_DMA_ADDR_L 0x440
-#define UNIPHIER_SD_DMA_ADDR_H 0x444
-
-/* alignment required by the DMA engine of this controller */
-#define UNIPHIER_SD_DMA_MINALIGN 0x10
-
-struct uniphier_sd_plat {
- struct mmc_config cfg;
- struct mmc mmc;
-};
-
-struct uniphier_sd_priv {
- void __iomem *regbase;
- unsigned long mclk;
- unsigned int version;
- u32 caps;
-#define UNIPHIER_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */
-#define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */
-#define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */
-#define UNIPHIER_SD_CAP_64BIT BIT(3) /* Controller is 64bit */
-};
-
-static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg)
-{
- if (priv->caps & UNIPHIER_SD_CAP_64BIT)
- return readq(priv->regbase + (reg << 1));
- else
- return readq(priv->regbase + reg);
-}
-
-static void uniphier_sd_writeq(struct uniphier_sd_priv *priv,
- u64 val, unsigned int reg)
-{
- if (priv->caps & UNIPHIER_SD_CAP_64BIT)
- writeq(val, priv->regbase + (reg << 1));
- else
- writeq(val, priv->regbase + reg);
-}
-
-static u32 uniphier_sd_readl(struct uniphier_sd_priv *priv, unsigned int reg)
-{
- if (priv->caps & UNIPHIER_SD_CAP_64BIT)
- return readl(priv->regbase + (reg << 1));
- else
- return readl(priv->regbase + reg);
-}
-
-static void uniphier_sd_writel(struct uniphier_sd_priv *priv,
- u32 val, unsigned int reg)
-{
- if (priv->caps & UNIPHIER_SD_CAP_64BIT)
- writel(val, priv->regbase + (reg << 1));
- else
- writel(val, priv->regbase + reg);
-}
-
-static dma_addr_t __dma_map_single(void *ptr, size_t size,
- enum dma_data_direction dir)
-{
- unsigned long addr = (unsigned long)ptr;
-
- if (dir == DMA_FROM_DEVICE)
- invalidate_dcache_range(addr, addr + size);
- else
- flush_dcache_range(addr, addr + size);
-
- return addr;
-}
-
-static void __dma_unmap_single(dma_addr_t addr, size_t size,
- enum dma_data_direction dir)
-{
- if (dir != DMA_TO_DEVICE)
- invalidate_dcache_range(addr, addr + size);
-}
-
-static int uniphier_sd_check_error(struct udevice *dev)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- u32 info2 = uniphier_sd_readl(priv, UNIPHIER_SD_INFO2);
-
- if (info2 & UNIPHIER_SD_INFO2_ERR_RTO) {
- /*
- * TIMEOUT must be returned for unsupported command. Do not
- * display error log since this might be a part of sequence to
- * distinguish between SD and MMC.
- */
- return -ETIMEDOUT;
- }
-
- if (info2 & UNIPHIER_SD_INFO2_ERR_TO) {
- dev_err(dev, "timeout error\n");
- return -ETIMEDOUT;
- }
-
- if (info2 & (UNIPHIER_SD_INFO2_ERR_END | UNIPHIER_SD_INFO2_ERR_CRC |
- UNIPHIER_SD_INFO2_ERR_IDX)) {
- dev_err(dev, "communication out of sync\n");
- return -EILSEQ;
- }
-
- if (info2 & (UNIPHIER_SD_INFO2_ERR_ILA | UNIPHIER_SD_INFO2_ERR_ILR |
- UNIPHIER_SD_INFO2_ERR_ILW)) {
- dev_err(dev, "illegal access\n");
- return -EIO;
- }
-
- return 0;
-}
-
-static int uniphier_sd_wait_for_irq(struct udevice *dev, unsigned int reg,
- u32 flag)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- long wait = 1000000;
- int ret;
-
- while (!(uniphier_sd_readl(priv, reg) & flag)) {
- if (wait-- < 0) {
- dev_err(dev, "timeout\n");
- return -ETIMEDOUT;
- }
-
- ret = uniphier_sd_check_error(dev);
- if (ret)
- return ret;
-
- udelay(1);
- }
-
- return 0;
-}
-
-static int uniphier_sd_pio_read_one_block(struct udevice *dev, char *pbuf,
- uint blocksize)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- int i, ret;
-
- /* wait until the buffer is filled with data */
- ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO2,
- UNIPHIER_SD_INFO2_BRE);
- if (ret)
- return ret;
-
- /*
- * Clear the status flag _before_ read the buffer out because
- * UNIPHIER_SD_INFO2_BRE is edge-triggered, not level-triggered.
- */
- uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2);
-
- if (priv->caps & UNIPHIER_SD_CAP_64BIT) {
- u64 *buf = (u64 *)pbuf;
- if (likely(IS_ALIGNED((uintptr_t)buf, 8))) {
- for (i = 0; i < blocksize / 8; i++) {
- *buf++ = uniphier_sd_readq(priv,
- UNIPHIER_SD_BUF);
- }
- } else {
- for (i = 0; i < blocksize / 8; i++) {
- u64 data;
- data = uniphier_sd_readq(priv,
- UNIPHIER_SD_BUF);
- put_unaligned(data, buf++);
- }
- }
- } else {
- u32 *buf = (u32 *)pbuf;
- if (likely(IS_ALIGNED((uintptr_t)buf, 4))) {
- for (i = 0; i < blocksize / 4; i++) {
- *buf++ = uniphier_sd_readl(priv,
- UNIPHIER_SD_BUF);
- }
- } else {
- for (i = 0; i < blocksize / 4; i++) {
- u32 data;
- data = uniphier_sd_readl(priv, UNIPHIER_SD_BUF);
- put_unaligned(data, buf++);
- }
- }
- }
-
- return 0;
-}
-
-static int uniphier_sd_pio_write_one_block(struct udevice *dev,
- const char *pbuf, uint blocksize)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- int i, ret;
-
- /* wait until the buffer becomes empty */
- ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO2,
- UNIPHIER_SD_INFO2_BWE);
- if (ret)
- return ret;
-
- uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2);
-
- if (priv->caps & UNIPHIER_SD_CAP_64BIT) {
- const u64 *buf = (const u64 *)pbuf;
- if (likely(IS_ALIGNED((uintptr_t)buf, 8))) {
- for (i = 0; i < blocksize / 8; i++) {
- uniphier_sd_writeq(priv, *buf++,
- UNIPHIER_SD_BUF);
- }
- } else {
- for (i = 0; i < blocksize / 8; i++) {
- u64 data = get_unaligned(buf++);
- uniphier_sd_writeq(priv, data,
- UNIPHIER_SD_BUF);
- }
- }
- } else {
- const u32 *buf = (const u32 *)pbuf;
- if (likely(IS_ALIGNED((uintptr_t)buf, 4))) {
- for (i = 0; i < blocksize / 4; i++) {
- uniphier_sd_writel(priv, *buf++,
- UNIPHIER_SD_BUF);
- }
- } else {
- for (i = 0; i < blocksize / 4; i++) {
- u32 data = get_unaligned(buf++);
- uniphier_sd_writel(priv, data,
- UNIPHIER_SD_BUF);
- }
- }
- }
-
- return 0;
-}
-
-static int uniphier_sd_pio_xfer(struct udevice *dev, struct mmc_data *data)
-{
- const char *src = data->src;
- char *dest = data->dest;
- int i, ret;
-
- for (i = 0; i < data->blocks; i++) {
- if (data->flags & MMC_DATA_READ)
- ret = uniphier_sd_pio_read_one_block(dev, dest,
- data->blocksize);
- else
- ret = uniphier_sd_pio_write_one_block(dev, src,
- data->blocksize);
- if (ret)
- return ret;
-
- if (data->flags & MMC_DATA_READ)
- dest += data->blocksize;
- else
- src += data->blocksize;
- }
-
- return 0;
-}
-
-static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv,
- dma_addr_t dma_addr)
-{
- u32 tmp;
-
- uniphier_sd_writel(priv, 0, UNIPHIER_SD_DMA_INFO1);
- uniphier_sd_writel(priv, 0, UNIPHIER_SD_DMA_INFO2);
-
- /* enable DMA */
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_EXTMODE);
- tmp |= UNIPHIER_SD_EXTMODE_DMA_EN;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_EXTMODE);
-
- uniphier_sd_writel(priv, dma_addr & U32_MAX, UNIPHIER_SD_DMA_ADDR_L);
-
- /* suppress the warning "right shift count >= width of type" */
- dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr));
-
- uniphier_sd_writel(priv, dma_addr & U32_MAX, UNIPHIER_SD_DMA_ADDR_H);
-
- uniphier_sd_writel(priv, UNIPHIER_SD_DMA_CTL_START, UNIPHIER_SD_DMA_CTL);
-}
-
-static int uniphier_sd_dma_wait_for_irq(struct udevice *dev, u32 flag,
- unsigned int blocks)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- long wait = 1000000 + 10 * blocks;
-
- while (!(uniphier_sd_readl(priv, UNIPHIER_SD_DMA_INFO1) & flag)) {
- if (wait-- < 0) {
- dev_err(dev, "timeout during DMA\n");
- return -ETIMEDOUT;
- }
-
- udelay(10);
- }
-
- if (uniphier_sd_readl(priv, UNIPHIER_SD_DMA_INFO2)) {
- dev_err(dev, "error during DMA\n");
- return -EIO;
- }
-
- return 0;
-}
-
-static int uniphier_sd_dma_xfer(struct udevice *dev, struct mmc_data *data)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- size_t len = data->blocks * data->blocksize;
- void *buf;
- enum dma_data_direction dir;
- dma_addr_t dma_addr;
- u32 poll_flag, tmp;
- int ret;
-
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_DMA_MODE);
-
- if (data->flags & MMC_DATA_READ) {
- buf = data->dest;
- dir = DMA_FROM_DEVICE;
- poll_flag = UNIPHIER_SD_DMA_INFO1_END_RD2;
- tmp |= UNIPHIER_SD_DMA_MODE_DIR_RD;
- } else {
- buf = (void *)data->src;
- dir = DMA_TO_DEVICE;
- poll_flag = UNIPHIER_SD_DMA_INFO1_END_WR;
- tmp &= ~UNIPHIER_SD_DMA_MODE_DIR_RD;
- }
-
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_DMA_MODE);
-
- dma_addr = __dma_map_single(buf, len, dir);
-
- uniphier_sd_dma_start(priv, dma_addr);
-
- ret = uniphier_sd_dma_wait_for_irq(dev, poll_flag, data->blocks);
-
- __dma_unmap_single(dma_addr, len, dir);
-
- return ret;
-}
-
-/* check if the address is DMA'able */
-static bool uniphier_sd_addr_is_dmaable(unsigned long addr)
-{
- if (!IS_ALIGNED(addr, UNIPHIER_SD_DMA_MINALIGN))
- return false;
-
-#if defined(CONFIG_ARCH_UNIPHIER) && !defined(CONFIG_ARM64) && \
- defined(CONFIG_SPL_BUILD)
- /*
- * For UniPhier ARMv7 SoCs, the stack is allocated in the locked ways
- * of L2, which is unreachable from the DMA engine.
- */
- if (addr < CONFIG_SPL_STACK)
- return false;
-#endif
-
- return true;
-}
-
-static int uniphier_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- int ret;
- u32 tmp;
-
- if (uniphier_sd_readl(priv, UNIPHIER_SD_INFO2) & UNIPHIER_SD_INFO2_CBSY) {
- dev_err(dev, "command busy\n");
- return -EBUSY;
- }
-
- /* clear all status flags */
- uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO1);
- uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2);
-
- /* disable DMA once */
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_EXTMODE);
- tmp &= ~UNIPHIER_SD_EXTMODE_DMA_EN;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_EXTMODE);
-
- uniphier_sd_writel(priv, cmd->cmdarg, UNIPHIER_SD_ARG);
-
- tmp = cmd->cmdidx;
-
- if (data) {
- uniphier_sd_writel(priv, data->blocksize, UNIPHIER_SD_SIZE);
- uniphier_sd_writel(priv, data->blocks, UNIPHIER_SD_SECCNT);
-
- /* Do not send CMD12 automatically */
- tmp |= UNIPHIER_SD_CMD_NOSTOP | UNIPHIER_SD_CMD_DATA;
-
- if (data->blocks > 1)
- tmp |= UNIPHIER_SD_CMD_MULTI;
-
- if (data->flags & MMC_DATA_READ)
- tmp |= UNIPHIER_SD_CMD_RD;
- }
-
- /*
- * Do not use the response type auto-detection on this hardware.
- * CMD8, for example, has different response types on SD and eMMC,
- * while this controller always assumes the response type for SD.
- * Set the response type manually.
- */
- switch (cmd->resp_type) {
- case MMC_RSP_NONE:
- tmp |= UNIPHIER_SD_CMD_RSP_NONE;
- break;
- case MMC_RSP_R1:
- tmp |= UNIPHIER_SD_CMD_RSP_R1;
- break;
- case MMC_RSP_R1b:
- tmp |= UNIPHIER_SD_CMD_RSP_R1B;
- break;
- case MMC_RSP_R2:
- tmp |= UNIPHIER_SD_CMD_RSP_R2;
- break;
- case MMC_RSP_R3:
- tmp |= UNIPHIER_SD_CMD_RSP_R3;
- break;
- default:
- dev_err(dev, "unknown response type\n");
- return -EINVAL;
- }
-
- dev_dbg(dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n",
- cmd->cmdidx, tmp, cmd->cmdarg);
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CMD);
-
- ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO1,
- UNIPHIER_SD_INFO1_RSP);
- if (ret)
- return ret;
-
- if (cmd->resp_type & MMC_RSP_136) {
- u32 rsp_127_104 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP76);
- u32 rsp_103_72 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP54);
- u32 rsp_71_40 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP32);
- u32 rsp_39_8 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP10);
-
- cmd->response[0] = ((rsp_127_104 & 0x00ffffff) << 8) |
- ((rsp_103_72 & 0xff000000) >> 24);
- cmd->response[1] = ((rsp_103_72 & 0x00ffffff) << 8) |
- ((rsp_71_40 & 0xff000000) >> 24);
- cmd->response[2] = ((rsp_71_40 & 0x00ffffff) << 8) |
- ((rsp_39_8 & 0xff000000) >> 24);
- cmd->response[3] = (rsp_39_8 & 0xffffff) << 8;
- } else {
- /* bit 39-8 */
- cmd->response[0] = uniphier_sd_readl(priv, UNIPHIER_SD_RSP10);
- }
-
- if (data) {
- /* use DMA if the HW supports it and the buffer is aligned */
- if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL &&
- uniphier_sd_addr_is_dmaable((long)data->src))
- ret = uniphier_sd_dma_xfer(dev, data);
- else
- ret = uniphier_sd_pio_xfer(dev, data);
-
- ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO1,
- UNIPHIER_SD_INFO1_CMP);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static int uniphier_sd_set_bus_width(struct uniphier_sd_priv *priv,
- struct mmc *mmc)
-{
- u32 val, tmp;
-
- switch (mmc->bus_width) {
- case 1:
- val = UNIPHIER_SD_OPTION_WIDTH_1;
- break;
- case 4:
- val = UNIPHIER_SD_OPTION_WIDTH_4;
- break;
- case 8:
- val = UNIPHIER_SD_OPTION_WIDTH_8;
- break;
- default:
- return -EINVAL;
- }
-
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_OPTION);
- tmp &= ~UNIPHIER_SD_OPTION_WIDTH_MASK;
- tmp |= val;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_OPTION);
-
- return 0;
-}
-
-static void uniphier_sd_set_ddr_mode(struct uniphier_sd_priv *priv,
- struct mmc *mmc)
-{
- u32 tmp;
-
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_IF_MODE);
- if (mmc->ddr_mode)
- tmp |= UNIPHIER_SD_IF_MODE_DDR;
- else
- tmp &= ~UNIPHIER_SD_IF_MODE_DDR;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_IF_MODE);
-}
-
-static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv,
- struct mmc *mmc)
-{
- unsigned int divisor;
- u32 val, tmp;
-
- if (!mmc->clock)
- return;
-
- divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
-
- if (divisor <= 1)
- val = UNIPHIER_SD_CLKCTL_DIV1;
- else if (divisor <= 2)
- val = UNIPHIER_SD_CLKCTL_DIV2;
- else if (divisor <= 4)
- val = UNIPHIER_SD_CLKCTL_DIV4;
- else if (divisor <= 8)
- val = UNIPHIER_SD_CLKCTL_DIV8;
- else if (divisor <= 16)
- val = UNIPHIER_SD_CLKCTL_DIV16;
- else if (divisor <= 32)
- val = UNIPHIER_SD_CLKCTL_DIV32;
- else if (divisor <= 64)
- val = UNIPHIER_SD_CLKCTL_DIV64;
- else if (divisor <= 128)
- val = UNIPHIER_SD_CLKCTL_DIV128;
- else if (divisor <= 256)
- val = UNIPHIER_SD_CLKCTL_DIV256;
- else if (divisor <= 512 || !(priv->caps & UNIPHIER_SD_CAP_DIV1024))
- val = UNIPHIER_SD_CLKCTL_DIV512;
- else
- val = UNIPHIER_SD_CLKCTL_DIV1024;
-
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL);
- if (tmp & UNIPHIER_SD_CLKCTL_SCLKEN &&
- (tmp & UNIPHIER_SD_CLKCTL_DIV_MASK) == val)
- return;
-
- /* stop the clock before changing its rate to avoid a glitch signal */
- tmp &= ~UNIPHIER_SD_CLKCTL_SCLKEN;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL);
-
- tmp &= ~UNIPHIER_SD_CLKCTL_DIV_MASK;
- tmp |= val | UNIPHIER_SD_CLKCTL_OFFEN;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL);
-
- tmp |= UNIPHIER_SD_CLKCTL_SCLKEN;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL);
-
- udelay(1000);
-}
-
-static int uniphier_sd_set_ios(struct udevice *dev)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- int ret;
-
- dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n",
- mmc->clock, mmc->ddr_mode, mmc->bus_width);
-
- ret = uniphier_sd_set_bus_width(priv, mmc);
- if (ret)
- return ret;
- uniphier_sd_set_ddr_mode(priv, mmc);
- uniphier_sd_set_clk_rate(priv, mmc);
-
- return 0;
-}
-
-static int uniphier_sd_get_cd(struct udevice *dev)
-{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
-
- if (priv->caps & UNIPHIER_SD_CAP_NONREMOVABLE)
- return 1;
-
- return !!(uniphier_sd_readl(priv, UNIPHIER_SD_INFO1) &
- UNIPHIER_SD_INFO1_CD);
-}
+#include "tmio-common.h"
static const struct dm_mmc_ops uniphier_sd_ops = {
- .send_cmd = uniphier_sd_send_cmd,
- .set_ios = uniphier_sd_set_ios,
- .get_cd = uniphier_sd_get_cd,
+ .send_cmd = tmio_sd_send_cmd,
+ .set_ios = tmio_sd_set_ios,
+ .get_cd = tmio_sd_get_cd,
};
-static void uniphier_sd_host_init(struct uniphier_sd_priv *priv)
-{
- u32 tmp;
-
- /* soft reset of the host */
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_SOFT_RST);
- tmp &= ~UNIPHIER_SD_SOFT_RST_RSTX;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_SOFT_RST);
- tmp |= UNIPHIER_SD_SOFT_RST_RSTX;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_SOFT_RST);
-
- /* FIXME: implement eMMC hw_reset */
-
- uniphier_sd_writel(priv, UNIPHIER_SD_STOP_SEC, UNIPHIER_SD_STOP);
-
- /*
- * Connected to 32bit AXI.
- * This register dropped backward compatibility at version 0x10.
- * Write an appropriate value depending on the IP version.
- */
- uniphier_sd_writel(priv, priv->version >= 0x10 ? 0x00000101 : 0x00000000,
- UNIPHIER_SD_HOST_MODE);
-
- if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL) {
- tmp = uniphier_sd_readl(priv, UNIPHIER_SD_DMA_MODE);
- tmp |= UNIPHIER_SD_DMA_MODE_ADDR_INC;
- uniphier_sd_writel(priv, tmp, UNIPHIER_SD_DMA_MODE);
- }
-}
-
-static int uniphier_sd_bind(struct udevice *dev)
-{
- struct uniphier_sd_plat *plat = dev_get_platdata(dev);
-
- return mmc_bind(dev, &plat->mmc, &plat->cfg);
-}
-
-static int uniphier_sd_probe(struct udevice *dev)
-{
- struct uniphier_sd_plat *plat = dev_get_platdata(dev);
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- const u32 quirks = dev_get_driver_data(dev);
- fdt_addr_t base;
- struct clk clk;
- int ret;
-#ifdef CONFIG_DM_REGULATOR
- struct udevice *vqmmc_dev;
-#endif
-
- base = devfdt_get_addr(dev);
- if (base == FDT_ADDR_T_NONE)
- return -EINVAL;
-
- priv->regbase = devm_ioremap(dev, base, SZ_2K);
- if (!priv->regbase)
- return -ENOMEM;
-
-#ifdef CONFIG_DM_REGULATOR
- ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev);
- if (!ret) {
- /* Set the regulator to 3.3V until we support 1.8V modes */
- regulator_set_value(vqmmc_dev, 3300000);
- regulator_set_enable(vqmmc_dev, true);
- }
-#endif
-
- ret = clk_get_by_index(dev, 0, &clk);
- if (ret < 0) {
- dev_err(dev, "failed to get host clock\n");
- return ret;
- }
-
- /* set to max rate */
- priv->mclk = clk_set_rate(&clk, ULONG_MAX);
- if (IS_ERR_VALUE(priv->mclk)) {
- dev_err(dev, "failed to set rate for host clock\n");
- clk_free(&clk);
- return priv->mclk;
- }
-
- ret = clk_enable(&clk);
- clk_free(&clk);
- if (ret) {
- dev_err(dev, "failed to enable host clock\n");
- return ret;
- }
-
- plat->cfg.name = dev->name;
- plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
-
- switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
- 1)) {
- case 8:
- plat->cfg.host_caps |= MMC_MODE_8BIT;
- break;
- case 4:
- plat->cfg.host_caps |= MMC_MODE_4BIT;
- break;
- case 1:
- break;
- default:
- dev_err(dev, "Invalid \"bus-width\" value\n");
- return -EINVAL;
- }
-
- if (quirks) {
- priv->caps = quirks;
- } else {
- priv->version = uniphier_sd_readl(priv, UNIPHIER_SD_VERSION) &
- UNIPHIER_SD_VERSION_IP;
- dev_dbg(dev, "version %x\n", priv->version);
- if (priv->version >= 0x10) {
- priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL;
- priv->caps |= UNIPHIER_SD_CAP_DIV1024;
- }
- }
-
- if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",
- NULL))
- priv->caps |= UNIPHIER_SD_CAP_NONREMOVABLE;
-
- uniphier_sd_host_init(priv);
-
- plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
- plat->cfg.f_min = priv->mclk /
- (priv->caps & UNIPHIER_SD_CAP_DIV1024 ? 1024 : 512);
- plat->cfg.f_max = priv->mclk;
- plat->cfg.b_max = U32_MAX; /* max value of UNIPHIER_SD_SECCNT */
-
- upriv->mmc = &plat->mmc;
-
- return 0;
-}
-
static const struct udevice_id uniphier_sd_match[] = {
- { .compatible = "renesas,sdhi-r8a7790", .data = 0 },
- { .compatible = "renesas,sdhi-r8a7791", .data = 0 },
- { .compatible = "renesas,sdhi-r8a7792", .data = 0 },
- { .compatible = "renesas,sdhi-r8a7793", .data = 0 },
- { .compatible = "renesas,sdhi-r8a7794", .data = 0 },
- { .compatible = "renesas,sdhi-r8a7795", .data = UNIPHIER_SD_CAP_64BIT },
- { .compatible = "renesas,sdhi-r8a7796", .data = UNIPHIER_SD_CAP_64BIT },
- { .compatible = "renesas,sdhi-r8a77965", .data = UNIPHIER_SD_CAP_64BIT },
- { .compatible = "renesas,sdhi-r8a77970", .data = UNIPHIER_SD_CAP_64BIT },
- { .compatible = "renesas,sdhi-r8a77995", .data = UNIPHIER_SD_CAP_64BIT },
{ .compatible = "socionext,uniphier-sdhc", .data = 0 },
{ /* sentinel */ }
};
+static int uniphier_sd_probe(struct udevice *dev)
+{
+ return tmio_sd_probe(dev, 0);
+}
+
U_BOOT_DRIVER(uniphier_mmc) = {
.name = "uniphier-mmc",
.id = UCLASS_MMC,
.of_match = uniphier_sd_match,
- .bind = uniphier_sd_bind,
+ .bind = tmio_sd_bind,
.probe = uniphier_sd_probe,
- .priv_auto_alloc_size = sizeof(struct uniphier_sd_priv),
- .platdata_auto_alloc_size = sizeof(struct uniphier_sd_plat),
+ .priv_auto_alloc_size = sizeof(struct tmio_sd_priv),
+ .platdata_auto_alloc_size = sizeof(struct tmio_sd_plat),
.ops = &uniphier_sd_ops,
};
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 19579801d2..707359dca1 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -40,6 +40,13 @@ config FLASH_PIC32
This enables access to Microchip PIC32 internal non-CFI flash
chips through PIC32 Non-Volatile-Memory Controller.
+config RENESAS_RPC_HF
+ bool "Renesas RCar Gen3 RPC Hyperflash driver"
+ depends on RCAR_GEN3 && MTD
+ help
+ This enables access to Hyperflash memory through the Renesas
+ RCar Gen3 RPC controller.
+
endmenu
source "drivers/mtd/nand/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 20c0d0af44..e46cbd8837 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o
obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
obj-$(CONFIG_ST_SMI) += st_smi.o
obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
+obj-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a820af61ce..94fbf89e4b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -95,9 +95,11 @@ config NAND_PXA3XX
config NAND_SUNXI
bool "Support for NAND on Allwinner SoCs"
- depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
+ default ARCH_SUNXI
+ depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I
select SYS_NAND_SELF_INIT
select SYS_NAND_U_BOOT_LOCATIONS
+ select SPL_NAND_SUPPORT
imply CMD_NAND
---help---
Enable support for NAND. This option enables the standard and
@@ -166,6 +168,28 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
comment "Generic NAND options"
+config SYS_NAND_BLOCK_SIZE
+ hex "NAND chip eraseblock size"
+ depends on ARCH_SUNXI
+ help
+ Number of data bytes in one eraseblock for the NAND chip on the
+ board. This is the multiple of NAND_PAGE_SIZE and the number of
+ pages.
+
+config SYS_NAND_PAGE_SIZE
+ hex "NAND chip page size"
+ depends on ARCH_SUNXI
+ help
+ Number of data bytes in one page for the NAND chip on the
+ board, not including the OOB area.
+
+config SYS_NAND_OOBSIZE
+ hex "NAND chip OOB size"
+ depends on ARCH_SUNXI
+ help
+ Number of bytes in the Out-Of-Band area for the NAND chip on
+ the board.
+
# Enhance depends when converting drivers to Kconfig which use this config
# option (mxc_nand, ndfc, omap_gpmc).
config SYS_NAND_BUSWIDTH_16BIT
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 9f7d9d6ff7..332d905a3a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -57,7 +57,6 @@ obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o
obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_NAND_MXS) += mxs_nand.o
-obj-$(CONFIG_NAND_NDFC) += ndfc.o
obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o
obj-$(CONFIG_NAND_SPEAR) += spr_nand.o
obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
diff --git a/drivers/mtd/nand/arasan_nfc.c b/drivers/mtd/nand/arasan_nfc.c
index 3c9a0215c5..3be66efb73 100644
--- a/drivers/mtd/nand/arasan_nfc.c
+++ b/drivers/mtd/nand/arasan_nfc.c
@@ -795,10 +795,11 @@ static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd,
writel(reg_val, &arasan_nand_base->cmd_reg);
- page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
- ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
+ page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
+ ARASAN_NAND_MEM_ADDR1_COL_MASK;
column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK;
- writel(page | column, &arasan_nand_base->memadr_reg1);
+ writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT),
+ &arasan_nand_base->memadr_reg1);
reg_val = readl(&arasan_nand_base->memadr_reg2);
reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index 8b548b204d..13a6535bd5 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -29,11 +29,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand_ecc.h>
-/* The PPC4xx NDFC uses Smart Media (SMC) bytes order */
-#ifdef CONFIG_NAND_NDFC
-#define CONFIG_MTD_NAND_ECC_SMC
-#endif
-
/*
* NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(),
* only nand_correct_data() is needed
@@ -110,13 +105,8 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
/* Calculate final ECC code */
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- ecc_code[0] = ~tmp2;
- ecc_code[1] = ~tmp1;
-#else
ecc_code[0] = ~tmp1;
ecc_code[1] = ~tmp2;
-#endif
ecc_code[2] = ((~reg1) << 2) | 0x03;
return 0;
@@ -146,15 +136,9 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
{
uint8_t s0, s1, s2;
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- s0 = calc_ecc[0] ^ read_ecc[0];
- s1 = calc_ecc[1] ^ read_ecc[1];
- s2 = calc_ecc[2] ^ read_ecc[2];
-#else
s1 = calc_ecc[0] ^ read_ecc[0];
s0 = calc_ecc[1] ^ read_ecc[1];
s2 = calc_ecc[2] ^ read_ecc[2];
-#endif
if ((s0 | s1 | s2) == 0)
return 0;
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
deleted file mode 100644
index 0a9849e9bc..0000000000
--- a/drivers/mtd/nand/ndfc.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Overview:
- * Platform independent driver for NDFC (NanD Flash Controller)
- * integrated into IBM/AMCC PPC4xx cores
- *
- * (C) Copyright 2006-2009
- * Stefan Roese, DENX Software Engineering, sr@denx.de.
- *
- * Based on original work by
- * Thomas Gleixner
- * Copyright 2006 IBM
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <nand.h>
-#include <linux/mtd/ndfc.h>
-#include <linux/mtd/nand_ecc.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/ppc4xx.h>
-
-#ifndef CONFIG_SYS_NAND_BCR
-#define CONFIG_SYS_NAND_BCR 0x80002222
-#endif
-#ifndef CONFIG_SYS_NDFC_EBC0_CFG
-#define CONFIG_SYS_NDFC_EBC0_CFG 0xb8400000
-#endif
-
-/*
- * We need to store the info, which chip-select (CS) is used for the
- * chip number. For example on Sequoia NAND chip #0 uses
- * CS #3.
- */
-static int ndfc_cs[NDFC_MAX_BANKS];
-
-static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- struct nand_chip *this = mtd_to_nand(mtd);
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
-
- if (cmd == NAND_CMD_NONE)
- return;
-
- if (ctrl & NAND_CLE)
- out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF);
- else
- out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF);
-}
-
-static int ndfc_dev_ready(struct mtd_info *mtdinfo)
-{
- struct nand_chip *this = mtd_to_nand(mtdinfo);
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
-
- return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY);
-}
-
-static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode)
-{
- struct nand_chip *this = mtd_to_nand(mtdinfo);
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
- u32 ccr;
-
- ccr = in_be32((u32 *)(base + NDFC_CCR));
- ccr |= NDFC_CCR_RESET_ECC;
- out_be32((u32 *)(base + NDFC_CCR), ccr);
-}
-
-static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
- const u_char *dat, u_char *ecc_code)
-{
- struct nand_chip *this = mtd_to_nand(mtdinfo);
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
- u32 ecc;
- u8 *p = (u8 *)&ecc;
-
- ecc = in_be32((u32 *)(base + NDFC_ECC));
-
- /* The NDFC uses Smart Media (SMC) bytes order
- */
- ecc_code[0] = p[1];
- ecc_code[1] = p[2];
- ecc_code[2] = p[3];
-
- return 0;
-}
-
-/*
- * Speedups for buffer read/write/verify
- *
- * NDFC allows 32bit read/write of data. So we can speed up the buffer
- * functions. No further checking, as nand_base will always read/write
- * page aligned.
- */
-static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
-{
- struct nand_chip *this = mtd_to_nand(mtdinfo);
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
- uint32_t *p = (uint32_t *) buf;
-
- for (;len > 0; len -= 4)
- *p++ = in_be32((u32 *)(base + NDFC_DATA));
-}
-
-/*
- * Don't use these speedup functions in NAND boot image, since the image
- * has to fit into 4kByte.
- */
-static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
-{
- struct nand_chip *this = mtd_to_nand(mtdinfo);
- ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
- uint32_t *p = (uint32_t *) buf;
-
- for (; len > 0; len -= 4)
- out_be32((u32 *)(base + NDFC_DATA), *p++);
-}
-
-/*
- * Read a byte from the NDFC.
- */
-static uint8_t ndfc_read_byte(struct mtd_info *mtd)
-{
-
- struct nand_chip *chip = mtd_to_nand(mtd);
-
-#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
- return (uint8_t) readw(chip->IO_ADDR_R);
-#else
- return readb(chip->IO_ADDR_R);
-#endif
-
-}
-
-void board_nand_select_device(struct nand_chip *nand, int chip)
-{
- /*
- * Don't use "chip" to address the NAND device,
- * generate the cs from the address where it is encoded.
- */
- ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00;
- int cs = ndfc_cs[chip];
-
- /* Set NandFlash Core Configuration Register */
- /* 1 col x 2 rows */
- out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24));
- out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), CONFIG_SYS_NAND_BCR);
-}
-
-static void ndfc_select_chip(struct mtd_info *mtd, int chip)
-{
- /*
- * Nothing to do here!
- */
-}
-
-int board_nand_init(struct nand_chip *nand)
-{
- int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
- ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00;
- static int chip = 0;
-
- /*
- * Save chip-select for this chip #
- */
- ndfc_cs[chip] = cs;
-
- /*
- * Select required NAND chip in NDFC
- */
- board_nand_select_device(nand, chip);
-
- nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA);
- nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA);
- nand->cmd_ctrl = ndfc_hwcontrol;
- nand->chip_delay = 50;
- nand->read_buf = ndfc_read_buf;
- nand->dev_ready = ndfc_dev_ready;
- nand->ecc.correct = nand_correct_data;
- nand->ecc.hwctl = ndfc_enable_hwecc;
- nand->ecc.calculate = ndfc_calculate_ecc;
- nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.size = 256;
- nand->ecc.bytes = 3;
- nand->ecc.strength = 1;
- nand->select_chip = ndfc_select_chip;
-
-#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
- nand->options |= NAND_BUSWIDTH_16;
-#endif
-
- nand->write_buf = ndfc_write_buf;
- nand->read_byte = ndfc_read_byte;
-
- chip++;
-
- return 0;
-}
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 532e03cd84..37160aaec2 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1407,8 +1407,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
/* Add ECC info retrieval from DT */
for (i = 0; i < ARRAY_SIZE(strengths); i++) {
- if (ecc->strength <= strengths[i])
+ if (ecc->strength <= strengths[i]) {
+ /*
+ * Update ecc->strength value with the actual strength
+ * that will be used by the ECC engine.
+ */
+ ecc->strength = strengths[i];
break;
+ }
}
if (i >= ARRAY_SIZE(strengths)) {
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c
index eed4472bdc..7241e9a374 100644
--- a/drivers/mtd/nand/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/sunxi_nand_spl.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <config.h>
#include <nand.h>
+#include <linux/ctype.h>
/* registers */
#define NFC_CTL 0x00000000
@@ -55,7 +56,7 @@
#define NFC_ADDR_NUM_OFFSET 16
-#define NFC_SEND_ADR (1 << 19)
+#define NFC_SEND_ADDR (1 << 19)
#define NFC_ACCESS_DIR (1 << 20)
#define NFC_DATA_TRANS (1 << 21)
#define NFC_SEND_CMD1 (1 << 22)
@@ -67,10 +68,12 @@
#define NFC_SEND_CMD3 (1 << 28)
#define NFC_SEND_CMD4 (1 << 29)
#define NFC_RAW_CMD (0 << 30)
+#define NFC_ECC_CMD (1 << 30)
#define NFC_PAGE_CMD (2 << 30)
#define NFC_ST_CMD_INT_FLAG (1 << 1)
#define NFC_ST_DMA_INT_FLAG (1 << 2)
+#define NFC_ST_CMD_FIFO_STAT (1 << 3)
#define NFC_READ_CMD_OFFSET 0
#define NFC_RANDOM_READ_CMD0_OFFSET 8
@@ -80,22 +83,6 @@
#define NFC_CMD_RNDOUT 0x05
#define NFC_CMD_READSTART 0x30
-#define SUNXI_DMA_CFG_REG0 0x300
-#define SUNXI_DMA_SRC_START_ADDR_REG0 0x304
-#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308
-#define SUNXI_DMA_DDMA_BC_REG0 0x30C
-#define SUNXI_DMA_DDMA_PARA_REG0 0x318
-
-#define SUNXI_DMA_DDMA_CFG_REG_LOADING (1 << 31)
-#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25)
-#define SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM (1 << 16)
-#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9)
-#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5)
-#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0)
-
-#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0)
-#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8)
-
struct nfc_config {
int page_size;
int ecc_strength;
@@ -155,6 +142,42 @@ static inline int check_value_negated(int offset, int unexpected_bits,
return check_value_inner(offset, unexpected_bits, timeout_us, 1);
}
+static int nand_wait_cmd_fifo_empty(void)
+{
+ if (!check_value_negated(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_FIFO_STAT,
+ DEFAULT_TIMEOUT_US)) {
+ printf("nand: timeout waiting for empty cmd FIFO\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int nand_wait_int(void)
+{
+ if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
+ DEFAULT_TIMEOUT_US)) {
+ printf("nand: timeout waiting for interruption\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int nand_exec_cmd(u32 cmd)
+{
+ int ret;
+
+ ret = nand_wait_cmd_fifo_empty();
+ if (ret)
+ return ret;
+
+ writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
+ writel(cmd, SUNXI_NFC_BASE + NFC_CMD);
+
+ return nand_wait_int();
+}
+
void nand_init(void)
{
uint32_t val;
@@ -172,22 +195,15 @@ void nand_init(void)
}
/* reset NAND */
- writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
- writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET,
- SUNXI_NFC_BASE + NFC_CMD);
-
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
- DEFAULT_TIMEOUT_US)) {
- printf("Error timeout waiting for nand reset\n");
- return;
- }
- writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
+ nand_exec_cmd(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET);
}
static void nand_apply_config(const struct nfc_config *conf)
{
u32 val;
+ nand_wait_cmd_fifo_empty();
+
val = readl(SUNXI_NFC_BASE + NFC_CTL);
val &= ~NFC_CTL_PAGE_SIZE_MASK;
writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size),
@@ -206,128 +222,111 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs)
SUNXI_NFC_BASE + NFC_RCMD_SET);
writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW);
writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
- writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
- writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | NFC_WAIT_FLAG |
- ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR,
- SUNXI_NFC_BASE + NFC_CMD);
-
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
- DEFAULT_TIMEOUT_US)) {
- printf("Error while initializing dma interrupt\n");
- return -EIO;
- }
- return 0;
+ return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
+ NFC_SEND_ADDR | NFC_WAIT_FLAG |
+ ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET));
}
-static int nand_reset_column(void)
+static int nand_change_column(u16 column)
{
+ int ret;
+
writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
(NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
(NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET),
SUNXI_NFC_BASE + NFC_RCMD_SET);
- writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW);
- writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
- (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR | NFC_CMD_RNDOUT,
- SUNXI_NFC_BASE + NFC_CMD);
+ writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
- DEFAULT_TIMEOUT_US)) {
- printf("Error while initializing dma interrupt\n");
- return -1;
- }
+ ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
+ (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR |
+ NFC_CMD_RNDOUT);
+ if (ret)
+ return ret;
+
+ /* Ensure tCCS has passed before reading data */
+ udelay(1);
return 0;
}
+static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116};
+
static int nand_read_page(const struct nfc_config *conf, u32 offs,
void *dest, int len)
{
- dma_addr_t dst = (dma_addr_t)dest;
int nsectors = len / conf->ecc_size;
u16 rand_seed = 0;
- u32 val;
- int page;
-
- page = offs / conf->page_size;
+ int oob_chunk_sz = ecc_bytes[conf->ecc_strength];
+ int page = offs / conf->page_size;
+ u32 ecc_st;
+ int i;
if (offs % conf->page_size || len % conf->ecc_size ||
len > conf->page_size || len < 0)
return -EINVAL;
- /* clear ecc status */
- writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
-
/* Choose correct seed if randomized */
if (conf->randomize)
rand_seed = random_seed[page % conf->nseeds];
- writel((rand_seed << 16) | (conf->ecc_strength << 12) |
- (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
- (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
- NFC_ECC_EN | NFC_ECC_PIPELINE | NFC_ECC_EXCEPTION,
- SUNXI_NFC_BASE + NFC_ECC_CTL);
-
- flush_dcache_range(dst, ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
-
- /* SUNXI_DMA */
- writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
- /* read from REG_IO_DATA */
- writel(SUNXI_NFC_BASE + NFC_IO_DATA,
- SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
- /* read to RAM */
- writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
- writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC |
- SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
- SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
- writel(len, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0);
- writel(SUNXI_DMA_DDMA_CFG_REG_LOADING |
- SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 |
- SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM |
- SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 |
- SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO |
- SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
- SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
-
- writel(nsectors, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
- writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
- writel(NFC_DATA_TRANS | NFC_PAGE_CMD | NFC_DATA_SWAP_METHOD,
- SUNXI_NFC_BASE + NFC_CMD);
-
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_DMA_INT_FLAG,
- DEFAULT_TIMEOUT_US)) {
- printf("Error while initializing dma interrupt\n");
- return -EIO;
- }
- writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
+ /* Retrieve data from SRAM (PIO) */
+ for (i = 0; i < nsectors; i++) {
+ int data_off = i * conf->ecc_size;
+ int oob_off = conf->page_size + (i * oob_chunk_sz);
+ u8 *data = dest + data_off;
+
+ /* Clear ECC status and restart ECC engine */
+ writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
+ writel((rand_seed << 16) | (conf->ecc_strength << 12) |
+ (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
+ (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
+ NFC_ECC_EN | NFC_ECC_EXCEPTION,
+ SUNXI_NFC_BASE + NFC_ECC_CTL);
+
+ /* Move the data in SRAM */
+ nand_change_column(data_off);
+ writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
+ nand_exec_cmd(NFC_DATA_TRANS);
- if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
- SUNXI_DMA_DDMA_CFG_REG_LOADING,
- DEFAULT_TIMEOUT_US)) {
- printf("Error while waiting for dma transfer to finish\n");
- return -EIO;
- }
+ /*
+ * Let the ECC engine consume the ECC bytes and possibly correct
+ * the data.
+ */
+ nand_change_column(oob_off);
+ nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD);
+
+ /* Get the ECC status */
+ ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
+
+ /* ECC error detected. */
+ if (ecc_st & 0xffff)
+ return -EIO;
+
+ /*
+ * Return 1 if the first chunk is empty (needed for
+ * configuration detection).
+ */
+ if (!i && (ecc_st & 0x10000))
+ return 1;
- invalidate_dcache_range(dst,
- ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
+ /* Retrieve the data from SRAM */
+ memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE,
+ conf->ecc_size);
- val = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
+ /* Stop the ECC engine */
+ writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN,
+ SUNXI_NFC_BASE + NFC_ECC_CTL);
- /* ECC error detected. */
- if (val & 0xffff)
- return -EIO;
+ if (data_off + conf->ecc_size >= len)
+ break;
+ }
- /*
- * Return 1 if the page is empty.
- * We consider the page as empty if the first ECC block is marked
- * empty.
- */
- return (val & 0x10000) ? 1 : 0;
+ return 0;
}
static int nand_max_ecc_strength(struct nfc_config *conf)
{
- static const int ecc_bytes[] = { 32, 46, 54, 60, 74, 88, 102, 110, 116 };
int max_oobsize, max_ecc_bytes;
int nsectors = conf->page_size / conf->ecc_size;
int i;
@@ -393,7 +392,7 @@ static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs,
conf->ecc_strength >= 0;
conf->ecc_strength--) {
conf->randomize = false;
- if (nand_reset_column())
+ if (nand_change_column(0))
return -EIO;
/*
@@ -413,7 +412,7 @@ static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs,
conf->randomize = true;
conf->nseeds = ARRAY_SIZE(random_seed);
do {
- if (nand_reset_column())
+ if (nand_change_column(0))
return -EIO;
if (!nand_read_page(conf, offs, dest,
@@ -475,11 +474,12 @@ static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest)
static int nand_read_buffer(struct nfc_config *conf, uint32_t offs,
unsigned int size, void *dest)
{
- int first_seed, page, ret;
+ int first_seed = 0, page, ret;
size = ALIGN(size, conf->page_size);
page = offs / conf->page_size;
- first_seed = page % conf->nseeds;
+ if (conf->randomize)
+ first_seed = page % conf->nseeds;
for (; size; size -= conf->page_size) {
if (nand_load_page(conf, offs))
@@ -504,7 +504,7 @@ static int nand_read_buffer(struct nfc_config *conf, uint32_t offs,
/* Try to adjust ->nseeds and read the page again... */
conf->nseeds = cur_seed;
- if (nand_reset_column())
+ if (nand_change_column(0))
return -EIO;
/* ... it still fails => it's a real corruption. */
diff --git a/drivers/mtd/renesas_rpc_hf.c b/drivers/mtd/renesas_rpc_hf.c
new file mode 100644
index 0000000000..1ba6e354a0
--- /dev/null
+++ b/drivers/mtd/renesas_rpc_hf.c
@@ -0,0 +1,398 @@
+/*
+ * Renesas RCar Gen3 RPC Hyperflash driver
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016 Cogent Embedded, Inc.
+ * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <errno.h>
+#include <fdt_support.h>
+#include <flash.h>
+#include <mtd.h>
+#include <wait_bit.h>
+#include <mtd/cfi_flash.h>
+
+#define RPC_CMNCR 0x0000 /* R/W */
+#define RPC_CMNCR_MD BIT(31)
+#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
+#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
+#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
+#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
+#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
+#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
+#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
+#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+ RPC_CMNCR_IO3FV(3))
+#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+
+#define RPC_SSLDR 0x0004 /* R/W */
+#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+
+#define RPC_DRCR 0x000C /* R/W */
+#define RPC_DRCR_SSLN BIT(24)
+#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+#define RPC_DRCR_RCF BIT(9)
+#define RPC_DRCR_RBE BIT(8)
+#define RPC_DRCR_SSLE BIT(0)
+
+#define RPC_DRCMR 0x0010 /* R/W */
+#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_DREAR 0x0014 /* R/W */
+#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
+#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
+
+#define RPC_DROPR 0x0018 /* R/W */
+#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
+#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
+
+#define RPC_DRENR 0x001C /* R/W */
+#define RPC_DRENR_CDB(o) (u32)((((o) & 0x3) << 30))
+#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_DRENR_DME BIT(15)
+#define RPC_DRENR_CDE BIT(14)
+#define RPC_DRENR_OCDE BIT(12)
+#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
+
+#define RPC_SMCR 0x0020 /* R/W */
+#define RPC_SMCR_SSLKP BIT(8)
+#define RPC_SMCR_SPIRE BIT(2)
+#define RPC_SMCR_SPIWE BIT(1)
+#define RPC_SMCR_SPIE BIT(0)
+
+#define RPC_SMCMR 0x0024 /* R/W */
+#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_SMADR 0x0028 /* R/W */
+#define RPC_SMOPR 0x002C /* R/W */
+#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
+#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
+
+#define RPC_SMENR 0x0030 /* R/W */
+#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
+#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_SMENR_DME BIT(15)
+#define RPC_SMENR_CDE BIT(14)
+#define RPC_SMENR_OCDE BIT(12)
+#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
+#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
+
+#define RPC_SMRDR0 0x0038 /* R */
+#define RPC_SMRDR1 0x003C /* R */
+#define RPC_SMWDR0 0x0040 /* R/W */
+#define RPC_SMWDR1 0x0044 /* R/W */
+#define RPC_CMNSR 0x0048 /* R */
+#define RPC_CMNSR_SSLF BIT(1)
+#define RPC_CMNSR_TEND BIT(0)
+
+#define RPC_DRDMCR 0x0058 /* R/W */
+#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_DRDRENR 0x005C /* R/W */
+#define RPC_DRDRENR_HYPE (0x5 << 12)
+#define RPC_DRDRENR_ADDRE BIT(8)
+#define RPC_DRDRENR_OPDRE BIT(4)
+#define RPC_DRDRENR_DRDRE BIT(0)
+
+#define RPC_SMDMCR 0x0060 /* R/W */
+#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_SMDRENR 0x0064 /* R/W */
+#define RPC_SMDRENR_HYPE (0x5 << 12)
+#define RPC_SMDRENR_ADDRE BIT(8)
+#define RPC_SMDRENR_OPDRE BIT(4)
+#define RPC_SMDRENR_SPIDRE BIT(0)
+
+#define RPC_PHYCNT 0x007C /* R/W */
+#define RPC_PHYCNT_CAL BIT(31)
+#define PRC_PHYCNT_OCTA_AA BIT(22)
+#define PRC_PHYCNT_OCTA_SA BIT(23)
+#define PRC_PHYCNT_EXDS BIT(21)
+#define RPC_PHYCNT_OCT BIT(20)
+#define RPC_PHYCNT_WBUF2 BIT(4)
+#define RPC_PHYCNT_WBUF BIT(2)
+#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
+
+#define RPC_PHYINT 0x0088 /* R/W */
+#define RPC_PHYINT_RSTEN BIT(18)
+#define RPC_PHYINT_WPEN BIT(17)
+#define RPC_PHYINT_INTEN BIT(16)
+#define RPC_PHYINT_RST BIT(2)
+#define RPC_PHYINT_WP BIT(1)
+#define RPC_PHYINT_INT BIT(0)
+
+#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
+#define RPC_WBUF_SIZE 0x100
+
+static phys_addr_t rpc_base;
+
+enum rpc_hf_size {
+ RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8),
+ RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC),
+ RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF),
+};
+
+static int rpc_hf_wait_tend(void)
+{
+ void __iomem *reg = (void __iomem *)rpc_base + RPC_CMNSR;
+ return wait_for_bit_le32(reg, RPC_CMNSR_TEND, true, 1000, 0);
+}
+
+static int rpc_hf_mode(bool man)
+{
+ int ret;
+
+ ret = rpc_hf_wait_tend();
+ if (ret)
+ return ret;
+
+ clrsetbits_le32(rpc_base + RPC_PHYCNT,
+ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
+ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
+ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
+
+ clrsetbits_le32(rpc_base + RPC_CMNCR,
+ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+ (man ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1));
+
+ if (man)
+ return 0;
+
+ writel(RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE,
+ rpc_base + RPC_DRCR);
+
+ writel(RPC_DRCMR_CMD(0xA0), rpc_base + RPC_DRCMR);
+ writel(RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | RPC_DRENR_ADB(2) |
+ RPC_DRENR_SPIDB(2) | RPC_DRENR_CDE | RPC_DRENR_OCDE |
+ RPC_DRENR_ADE(4), rpc_base + RPC_DRENR);
+ writel(RPC_DRDMCR_DMCYC(0xE), rpc_base + RPC_DRDMCR);
+ writel(RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE,
+ rpc_base + RPC_DRDRENR);
+
+ /* Dummy read */
+ readl(rpc_base + RPC_DRCR);
+
+ return 0;
+}
+
+static int rpc_hf_xfer(void *addr, u64 wdata, u64 *rdata,
+ enum rpc_hf_size size, bool write)
+{
+ int ret;
+ u32 val;
+
+ ret = rpc_hf_mode(1);
+ if (ret)
+ return ret;
+
+ /* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */
+ writel(write ? 0 : RPC_SMCMR_CMD(0x80), rpc_base + RPC_SMCMR);
+ writel((uintptr_t)addr >> 1, rpc_base + RPC_SMADR);
+ writel(0x0, rpc_base + RPC_SMOPR);
+
+ writel(RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE,
+ rpc_base + RPC_SMDRENR);
+
+ val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
+ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
+ RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size;
+
+ if (write) {
+ writel(val, rpc_base + RPC_SMENR);
+
+ if (size == RPC_HF_SIZE_64BIT)
+ writeq(cpu_to_be64(wdata), rpc_base + RPC_SMWDR0);
+ else
+ writel(cpu_to_be32(wdata), rpc_base + RPC_SMWDR0);
+
+ writel(RPC_SMCR_SPIWE | RPC_SMCR_SPIE, rpc_base + RPC_SMCR);
+ } else {
+ val |= RPC_SMENR_DME;
+
+ writel(RPC_SMDMCR_DMCYC(0xE), rpc_base + RPC_SMDMCR);
+
+ writel(val, rpc_base + RPC_SMENR);
+
+ writel(RPC_SMCR_SPIRE | RPC_SMCR_SPIE, rpc_base + RPC_SMCR);
+
+ ret = rpc_hf_wait_tend();
+ if (ret)
+ return ret;
+
+ if (size == RPC_HF_SIZE_64BIT)
+ *rdata = be64_to_cpu(readq(rpc_base + RPC_SMRDR0));
+ else
+ *rdata = be32_to_cpu(readl(rpc_base + RPC_SMRDR0));
+ }
+
+ return rpc_hf_mode(0);
+}
+
+static void rpc_hf_write_cmd(void *addr, u64 wdata, enum rpc_hf_size size)
+{
+ int ret;
+
+ ret = rpc_hf_xfer(addr, wdata, NULL, size, 1);
+ if (ret)
+ printf("RPC: Write failed, ret=%i\n", ret);
+}
+
+static u64 rpc_hf_read_reg(void *addr, enum rpc_hf_size size)
+{
+ u64 rdata = 0;
+ int ret;
+
+ ret = rpc_hf_xfer(addr, 0, &rdata, size, 0);
+ if (ret)
+ printf("RPC: Read failed, ret=%i\n", ret);
+
+ return rdata;
+}
+
+void flash_write8(u8 value, void *addr)
+{
+ rpc_hf_write_cmd(addr, value, RPC_HF_SIZE_16BIT);
+}
+
+void flash_write16(u16 value, void *addr)
+{
+ rpc_hf_write_cmd(addr, value, RPC_HF_SIZE_16BIT);
+}
+
+void flash_write32(u32 value, void *addr)
+{
+ rpc_hf_write_cmd(addr, value, RPC_HF_SIZE_32BIT);
+}
+
+void flash_write64(u64 value, void *addr)
+{
+ rpc_hf_write_cmd(addr, value, RPC_HF_SIZE_64BIT);
+}
+
+u8 flash_read8(void *addr)
+{
+ return rpc_hf_read_reg(addr, RPC_HF_SIZE_16BIT);
+}
+
+u16 flash_read16(void *addr)
+{
+ return rpc_hf_read_reg(addr, RPC_HF_SIZE_16BIT);
+}
+
+u32 flash_read32(void *addr)
+{
+ return rpc_hf_read_reg(addr, RPC_HF_SIZE_32BIT);
+}
+
+u64 flash_read64(void *addr)
+{
+ return rpc_hf_read_reg(addr, RPC_HF_SIZE_64BIT);
+}
+
+static int rpc_hf_bind(struct udevice *parent)
+{
+ const void *fdt = gd->fdt_blob;
+ ofnode node;
+ int ret, off;
+
+ /*
+ * Check if there are any SPI NOR child nodes, if so, do NOT bind
+ * as this controller will be operated by the QSPI driver instead.
+ */
+ dev_for_each_subnode(node, parent) {
+ off = ofnode_to_offset(node);
+
+ ret = fdt_node_check_compatible(fdt, off, "spi-flash");
+ if (!ret)
+ return -ENODEV;
+
+ ret = fdt_node_check_compatible(fdt, off, "jedec,spi-nor");
+ if (!ret)
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int rpc_hf_probe(struct udevice *dev)
+{
+ void *blob = (void *)gd->fdt_blob;
+ const fdt32_t *cell;
+ int node = dev_of_offset(dev);
+ int parent, addrc, sizec, len, ret;
+ struct clk clk;
+ phys_addr_t flash_base;
+
+ parent = fdt_parent_offset(blob, node);
+ fdt_support_default_count_cells(blob, parent, &addrc, &sizec);
+ cell = fdt_getprop(blob, node, "reg", &len);
+ if (!cell)
+ return -ENOENT;
+
+ if (addrc != 2 || sizec != 2)
+ return -EINVAL;
+
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get RPC clock\n");
+ return ret;
+ }
+
+ ret = clk_enable(&clk);
+ clk_free(&clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable RPC clock\n");
+ return ret;
+ }
+
+ rpc_base = fdt_translate_address(blob, node, cell);
+ flash_base = fdt_translate_address(blob, node, cell + addrc + sizec);
+
+ flash_info[0].dev = dev;
+ flash_info[0].base = flash_base;
+ cfi_flash_num_flash_banks = 1;
+ gd->bd->bi_flashstart = flash_base;
+
+ return 0;
+}
+
+static const struct udevice_id rpc_hf_ids[] = {
+ { .compatible = "renesas,rpc" },
+ {}
+};
+
+U_BOOT_DRIVER(rpc_hf) = {
+ .name = "rpc_hf",
+ .id = UCLASS_MTD,
+ .of_match = rpc_hf_ids,
+ .bind = rpc_hf_bind,
+ .probe = rpc_hf_probe,
+};
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 6ba255d676..4484cf8195 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -135,17 +135,4 @@ config SPI_FLASH_MTD
If unsure, say N
-if SPL
-
-config SPL_SPI_SUNXI
- bool "Support for SPI Flash on Allwinner SoCs in SPL"
- depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I
- select SPL_SPI_FLASH_SUPPORT
- ---help---
- Enable support for SPI Flash. This option allows SPL to read from
- sunxi SPI Flash. It uses the same method as the boot ROM, so does
- not need any extra configuration.
-
-endif
-
endmenu # menu "SPI Flash Support"
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index fcda023412..4be6e9b15f 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
-obj-$(CONFIG_SPL_SPI_SUNXI) += sunxi_spi_spl.o
endif
obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o spi_flash_ids.o sf.o
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 294d9f9d79..2e61685d3e 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -320,7 +320,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
erase_size = flash->erase_size;
if (offset % erase_size || len % erase_size) {
- debug("SF: Erase offset/length not multiple of erase size\n");
+ printf("SF: Erase offset/length not multiple of erase size\n");
return -1;
}
diff --git a/drivers/mtd/spi/sunxi_spi_spl.c b/drivers/mtd/spi/sunxi_spi_spl.c
deleted file mode 100644
index fa22981316..0000000000
--- a/drivers/mtd/spi/sunxi_spi_spl.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <spl.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <linux/libfdt.h>
-
-#ifdef CONFIG_SPL_OS_BOOT
-#error CONFIG_SPL_OS_BOOT is not supported yet
-#endif
-
-/*
- * This is a very simple U-Boot image loading implementation, trying to
- * replicate what the boot ROM is doing when loading the SPL. Because we
- * know the exact pins where the SPI Flash is connected and also know
- * that the Read Data Bytes (03h) command is supported, the hardware
- * configuration is very simple and we don't need the extra flexibility
- * of the SPI framework. Moreover, we rely on the default settings of
- * the SPI controler hardware registers and only adjust what needs to
- * be changed. This is good for the code size and this implementation
- * adds less than 400 bytes to the SPL.
- *
- * There are two variants of the SPI controller in Allwinner SoCs:
- * A10/A13/A20 (sun4i variant) and everything else (sun6i variant).
- * Both of them are supported.
- *
- * The pin mixing part is SoC specific and only A10/A13/A20/H3/A64 are
- * supported at the moment.
- */
-
-/*****************************************************************************/
-/* SUN4I variant of the SPI controller */
-/*****************************************************************************/
-
-#define SUN4I_SPI0_CCTL (0x01C05000 + 0x1C)
-#define SUN4I_SPI0_CTL (0x01C05000 + 0x08)
-#define SUN4I_SPI0_RX (0x01C05000 + 0x00)
-#define SUN4I_SPI0_TX (0x01C05000 + 0x04)
-#define SUN4I_SPI0_FIFO_STA (0x01C05000 + 0x28)
-#define SUN4I_SPI0_BC (0x01C05000 + 0x20)
-#define SUN4I_SPI0_TC (0x01C05000 + 0x24)
-
-#define SUN4I_CTL_ENABLE BIT(0)
-#define SUN4I_CTL_MASTER BIT(1)
-#define SUN4I_CTL_TF_RST BIT(8)
-#define SUN4I_CTL_RF_RST BIT(9)
-#define SUN4I_CTL_XCH BIT(10)
-
-/*****************************************************************************/
-/* SUN6I variant of the SPI controller */
-/*****************************************************************************/
-
-#define SUN6I_SPI0_CCTL (0x01C68000 + 0x24)
-#define SUN6I_SPI0_GCR (0x01C68000 + 0x04)
-#define SUN6I_SPI0_TCR (0x01C68000 + 0x08)
-#define SUN6I_SPI0_FIFO_STA (0x01C68000 + 0x1C)
-#define SUN6I_SPI0_MBC (0x01C68000 + 0x30)
-#define SUN6I_SPI0_MTC (0x01C68000 + 0x34)
-#define SUN6I_SPI0_BCC (0x01C68000 + 0x38)
-#define SUN6I_SPI0_TXD (0x01C68000 + 0x200)
-#define SUN6I_SPI0_RXD (0x01C68000 + 0x300)
-
-#define SUN6I_CTL_ENABLE BIT(0)
-#define SUN6I_CTL_MASTER BIT(1)
-#define SUN6I_CTL_SRST BIT(31)
-#define SUN6I_TCR_XCH BIT(31)
-
-/*****************************************************************************/
-
-#define CCM_AHB_GATING0 (0x01C20000 + 0x60)
-#define CCM_SPI0_CLK (0x01C20000 + 0xA0)
-#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0)
-
-#define AHB_RESET_SPI0_SHIFT 20
-#define AHB_GATE_OFFSET_SPI0 20
-
-#define SPI0_CLK_DIV_BY_2 0x1000
-#define SPI0_CLK_DIV_BY_4 0x1001
-
-/*****************************************************************************/
-
-/*
- * Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting
- * from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3.
- */
-static void spi0_pinmux_setup(unsigned int pin_function)
-{
- unsigned int pin;
-
- for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(2); pin++)
- sunxi_gpio_set_cfgpin(pin, pin_function);
-
- if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I))
- sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function);
- else
- sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
-}
-
-/*
- * Setup 6 MHz from OSC24M (because the BROM is doing the same).
- */
-static void spi0_enable_clock(void)
-{
- /* Deassert SPI0 reset on SUN6I */
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
- setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
- (1 << AHB_RESET_SPI0_SHIFT));
-
- /* Open the SPI0 gate */
- setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
-
- /* Divide by 4 */
- writel(SPI0_CLK_DIV_BY_4, IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ?
- SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL);
- /* 24MHz from OSC24M */
- writel((1 << 31), CCM_SPI0_CLK);
-
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
- /* Enable SPI in the master mode and do a soft reset */
- setbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
- SUN6I_CTL_ENABLE |
- SUN6I_CTL_SRST);
- /* Wait for completion */
- while (readl(SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
- ;
- } else {
- /* Enable SPI in the master mode and reset FIFO */
- setbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
- SUN4I_CTL_ENABLE |
- SUN4I_CTL_TF_RST |
- SUN4I_CTL_RF_RST);
- }
-}
-
-static void spi0_disable_clock(void)
-{
- /* Disable the SPI0 controller */
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
- clrbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
- SUN6I_CTL_ENABLE);
- else
- clrbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
- SUN4I_CTL_ENABLE);
-
- /* Disable the SPI0 clock */
- writel(0, CCM_SPI0_CLK);
-
- /* Close the SPI0 gate */
- clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
-
- /* Assert SPI0 reset on SUN6I */
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
- clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
- (1 << AHB_RESET_SPI0_SHIFT));
-}
-
-static void spi0_init(void)
-{
- unsigned int pin_function = SUNXI_GPC_SPI0;
-
- if (IS_ENABLED(CONFIG_MACH_SUN50I))
- pin_function = SUN50I_GPC_SPI0;
-
- spi0_pinmux_setup(pin_function);
- spi0_enable_clock();
-}
-
-static void spi0_deinit(void)
-{
- /* New SoCs can disable pins, older could only set them as input */
- unsigned int pin_function = SUNXI_GPIO_INPUT;
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
- pin_function = SUNXI_GPIO_DISABLE;
-
- spi0_disable_clock();
- spi0_pinmux_setup(pin_function);
-}
-
-/*****************************************************************************/
-
-#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
-
-static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
- ulong spi_ctl_reg,
- ulong spi_ctl_xch_bitmask,
- ulong spi_fifo_reg,
- ulong spi_tx_reg,
- ulong spi_rx_reg,
- ulong spi_bc_reg,
- ulong spi_tc_reg,
- ulong spi_bcc_reg)
-{
- writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
- writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */
- if (spi_bcc_reg)
- writel(4, spi_bcc_reg); /* SUN6I also needs this */
-
- /* Send the Read Data Bytes (03h) command header */
- writeb(0x03, spi_tx_reg);
- writeb((u8)(addr >> 16), spi_tx_reg);
- writeb((u8)(addr >> 8), spi_tx_reg);
- writeb((u8)(addr), spi_tx_reg);
-
- /* Start the data transfer */
- setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
-
- /* Wait until everything is received in the RX FIFO */
- while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
- ;
-
- /* Skip 4 bytes */
- readl(spi_rx_reg);
-
- /* Read the data */
- while (bufsize-- > 0)
- *buf++ = readb(spi_rx_reg);
-
- /* tSHSL time is up to 100 ns in various SPI flash datasheets */
- udelay(1);
-}
-
-static void spi0_read_data(void *buf, u32 addr, u32 len)
-{
- u8 *buf8 = buf;
- u32 chunk_len;
-
- while (len > 0) {
- chunk_len = len;
- if (chunk_len > SPI_READ_MAX_SIZE)
- chunk_len = SPI_READ_MAX_SIZE;
-
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
- sunxi_spi0_read_data(buf8, addr, chunk_len,
- SUN6I_SPI0_TCR,
- SUN6I_TCR_XCH,
- SUN6I_SPI0_FIFO_STA,
- SUN6I_SPI0_TXD,
- SUN6I_SPI0_RXD,
- SUN6I_SPI0_MBC,
- SUN6I_SPI0_MTC,
- SUN6I_SPI0_BCC);
- } else {
- sunxi_spi0_read_data(buf8, addr, chunk_len,
- SUN4I_SPI0_CTL,
- SUN4I_CTL_XCH,
- SUN4I_SPI0_FIFO_STA,
- SUN4I_SPI0_TX,
- SUN4I_SPI0_RX,
- SUN4I_SPI0_BC,
- SUN4I_SPI0_TC,
- 0);
- }
-
- len -= chunk_len;
- buf8 += chunk_len;
- addr += chunk_len;
- }
-}
-
-static ulong spi_load_read(struct spl_load_info *load, ulong sector,
- ulong count, void *buf)
-{
- spi0_read_data(buf, sector, count);
-
- return count;
-}
-
-/*****************************************************************************/
-
-static int spl_spi_load_image(struct spl_image_info *spl_image,
- struct spl_boot_device *bootdev)
-{
- int ret = 0;
- struct image_header *header;
- header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
-
- spi0_init();
-
- spi0_read_data((void *)header, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40);
-
- if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
- image_get_magic(header) == FDT_MAGIC) {
- struct spl_load_info load;
-
- debug("Found FIT image\n");
- load.dev = NULL;
- load.priv = NULL;
- load.filename = NULL;
- load.bl_len = 1;
- load.read = spi_load_read;
- ret = spl_load_simple_fit(spl_image, &load,
- CONFIG_SYS_SPI_U_BOOT_OFFS, header);
- } else {
- ret = spl_parse_image_header(spl_image, header);
- if (ret)
- return ret;
-
- spi0_read_data((void *)spl_image->load_addr,
- CONFIG_SYS_SPI_U_BOOT_OFFS, spl_image->size);
- }
-
- spi0_deinit();
-
- return ret;
-}
-/* Use priorty 0 to override the default if it happens to be linked in */
-SPL_LOAD_IMAGE_METHOD("sunxi SPI", 0, BOOT_DEVICE_SPI, spl_spi_load_image);
diff --git a/drivers/mtd/stm32_flash.c b/drivers/mtd/stm32_flash.c
index 472499d83c..a82814272e 100644
--- a/drivers/mtd/stm32_flash.c
+++ b/drivers/mtd/stm32_flash.c
@@ -12,7 +12,7 @@
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
-#define STM32_FLASH ((struct stm32_flash_regs *)FLASH_CNTL_BASE)
+#define STM32_FLASH ((struct stm32_flash_regs *)STM32_FLASH_CNTL_BASE)
void stm32_flash_latency_cfg(int latency)
{
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index caa5197df5..cf84783356 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -1,5 +1,12 @@
menu "UBI support"
+config CONFIG_UBI_SILENCE_MSG
+ bool "UBI silence verbose messages"
+ default ENV_IS_IN_UBI
+ help
+ Make the verbose messages from UBI stop printing. This leaves
+ warnings and errors enabled.
+
config MTD_UBI
bool "Enable UBI - Unsorted block images"
select CRC32
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de1947ccc1..3a374d8871 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1,4 +1,5 @@
source "drivers/net/phy/Kconfig"
+source "drivers/net/pfe_eth/Kconfig"
config DM_ETH
bool "Enable Driver Model for Ethernet drivers"
@@ -10,6 +11,13 @@ config DM_ETH
This is currently implemented in net/eth.c
Look in include/net.h for details.
+config DRIVER_TI_CPSW
+ bool "TI Common Platform Ethernet Switch"
+ select PHYLIB
+ help
+ This driver supports the TI three port switch gigabit ethernet
+ subsystem found in the TI SoCs.
+
menuconfig NETDEVICES
bool "Network device support"
depends on NET
@@ -147,9 +155,20 @@ config ETHOC
help
This MAC is present in OpenRISC and Xtensa XTFPGA boards.
+config FEC_MXC_SHARE_MDIO
+ bool "Share the MDIO bus for FEC controller"
+ depends on FEC_MXC
+
+config FEC_MXC_MDIO_BASE
+ hex "MDIO base address for the FEC controller"
+ depends on FEC_MXC_SHARE_MDIO
+ help
+ This specifies the MDIO registers base address. It is used when
+ two FEC controllers share MDIO bus.
+
config FEC_MXC
bool "FEC Ethernet controller"
- depends on MX5 || MX6
+ depends on MX5 || MX6 || MX7
help
This driver supports the 10/100 Fast Ethernet controller for
NXP i.MX processors.
@@ -330,7 +349,7 @@ config RENESAS_RAVB
config MPC8XX_FEC
bool "Fast Ethernet Controller on MPC8XX"
- depends on 8xx
+ depends on MPC8xx
select MII
help
This driver implements support for the Fast Ethernet Controller
@@ -410,4 +429,11 @@ config SYS_DPAA_QBMAN
help
QBman fixups to allow deep sleep in DPAA 1 SOCs
+config TSEC_ENET
+ select PHYLIB
+ bool "Enable Three-Speed Ethernet Controller"
+ help
+ This driver implements support for the (Enhanced) Three-Speed
+ Ethernet Controller found on Freescale SoCs.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4a16c62bac..2687fbbdb2 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -23,7 +23,6 @@ obj-$(CONFIG_E1000_SPI) += e1000_spi.o
obj-$(CONFIG_EEPRO100) += eepro100.o
obj-$(CONFIG_SUN4I_EMAC) += sunxi_emac.o
obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o
-obj-$(CONFIG_ENC28J60) += enc28j60.o
obj-$(CONFIG_EP93XX) += ep93xx_eth.o
obj-$(CONFIG_ETHOC) += ethoc.o
obj-$(CONFIG_FEC_MXC) += fec_mxc.o
@@ -73,3 +72,4 @@ obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
obj-$(CONFIG_VSC9953) += vsc9953.o
obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
+obj-$(CONFIG_FSL_PFE) += pfe_eth/
diff --git a/drivers/net/cpsw-common.c b/drivers/net/cpsw-common.c
index 0dc83ab820..7bd312a6c0 100644
--- a/drivers/net/cpsw-common.c
+++ b/drivers/net/cpsw-common.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <dm.h>
+#include <environment.h>
#include <fdt_support.h>
#include <asm/io.h>
#include <cpsw.h>
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index b72258f83b..e2395dbeb9 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -949,7 +949,7 @@ static int _cpsw_recv(struct cpsw_priv *priv, uchar **pkt)
{
void *buffer;
int len;
- int ret = -EAGAIN;
+ int ret;
ret = cpdma_process(priv, &priv->rx_chan, &buffer, &len);
if (ret < 0)
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
deleted file mode 100644
index 588a84d7a9..0000000000
--- a/drivers/net/enc28j60.c
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * (C) Copyright 2010
- * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
- * Martin Krause, Martin.Krause@tqs.de
- * reworked original enc28j60.c
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <net.h>
-#include <spi.h>
-#include <malloc.h>
-#include <netdev.h>
-#include <miiphy.h>
-#include "enc28j60.h"
-
-/*
- * IMPORTANT: spi_claim_bus() and spi_release_bus()
- * are called at begin and end of each of the following functions:
- * enc_miiphy_read(), enc_miiphy_write(), enc_write_hwaddr(),
- * enc_init(), enc_recv(), enc_send(), enc_halt()
- * ALL other functions assume that the bus has already been claimed!
- * Since net_process_received_packet() might call enc_send() in return, the bus
- * must be released, net_process_received_packet() called and claimed again.
- */
-
-/*
- * Controller memory layout.
- * We only allow 1 frame for transmission and reserve the rest
- * for reception to handle as many broadcast packets as possible.
- * Also use the memory from 0x0000 for receiver buffer. See errata pt. 5
- * 0x0000 - 0x19ff 6656 bytes receive buffer
- * 0x1a00 - 0x1fff 1536 bytes transmit buffer =
- * control(1)+frame(1518)+status(7)+reserve(10).
- */
-#define ENC_RX_BUF_START 0x0000
-#define ENC_RX_BUF_END 0x19ff
-#define ENC_TX_BUF_START 0x1a00
-#define ENC_TX_BUF_END 0x1fff
-#define ENC_MAX_FRM_LEN 1518
-#define RX_RESET_COUNTER 1000
-
-/*
- * For non data transfer functions, like phy read/write, set hwaddr, init
- * we do not need a full, time consuming init including link ready wait.
- * This enum helps to bring the chip through the minimum necessary inits.
- */
-enum enc_initstate {none=0, setupdone, linkready};
-typedef struct enc_device {
- struct eth_device *dev; /* back pointer */
- struct spi_slave *slave;
- int rx_reset_counter;
- u16 next_pointer;
- u8 bank; /* current bank in enc28j60 */
- enum enc_initstate initstate;
-} enc_dev_t;
-
-/*
- * enc_bset: set bits in a common register
- * enc_bclr: clear bits in a common register
- *
- * making the reg parameter u8 will give a compile time warning if the
- * functions are called with a register not accessible in all Banks
- */
-static void enc_bset(enc_dev_t *enc, const u8 reg, const u8 data)
-{
- u8 dout[2];
-
- dout[0] = CMD_BFS(reg);
- dout[1] = data;
- spi_xfer(enc->slave, 2 * 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
-}
-
-static void enc_bclr(enc_dev_t *enc, const u8 reg, const u8 data)
-{
- u8 dout[2];
-
- dout[0] = CMD_BFC(reg);
- dout[1] = data;
- spi_xfer(enc->slave, 2 * 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
-}
-
-/*
- * high byte of the register contains bank number:
- * 0: no bank switch necessary
- * 1: switch to bank 0
- * 2: switch to bank 1
- * 3: switch to bank 2
- * 4: switch to bank 3
- */
-static void enc_set_bank(enc_dev_t *enc, const u16 reg)
-{
- u8 newbank = reg >> 8;
-
- if (newbank == 0 || newbank == enc->bank)
- return;
- switch (newbank) {
- case 1:
- enc_bclr(enc, CTL_REG_ECON1,
- ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
- break;
- case 2:
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
- enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
- break;
- case 3:
- enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
- break;
- case 4:
- enc_bset(enc, CTL_REG_ECON1,
- ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
- break;
- }
- enc->bank = newbank;
-}
-
-/*
- * local functions to access SPI
- *
- * reg: register inside ENC28J60
- * data: 8/16 bits to write
- * c: number of retries
- *
- * enc_r8: read 8 bits
- * enc_r16: read 16 bits
- * enc_w8: write 8 bits
- * enc_w16: write 16 bits
- * enc_w8_retry: write 8 bits, verify and retry
- * enc_rbuf: read from ENC28J60 into buffer
- * enc_wbuf: write from buffer into ENC28J60
- */
-
-/*
- * MAC and MII registers need a 3 byte SPI transfer to read,
- * all other registers need a 2 byte SPI transfer.
- */
-static int enc_reg2nbytes(const u16 reg)
-{
- /* check if MAC or MII register */
- return ((reg >= CTL_REG_MACON1 && reg <= CTL_REG_MIRDH) ||
- (reg >= CTL_REG_MAADR1 && reg <= CTL_REG_MAADR4) ||
- (reg == CTL_REG_MISTAT)) ? 3 : 2;
-}
-
-/*
- * Read a byte register
- */
-static u8 enc_r8(enc_dev_t *enc, const u16 reg)
-{
- u8 dout[3];
- u8 din[3];
- int nbytes = enc_reg2nbytes(reg);
-
- enc_set_bank(enc, reg);
- dout[0] = CMD_RCR(reg);
- spi_xfer(enc->slave, nbytes * 8, dout, din,
- SPI_XFER_BEGIN | SPI_XFER_END);
- return din[nbytes-1];
-}
-
-/*
- * Read a L/H register pair and return a word.
- * Must be called with the L register's address.
- */
-static u16 enc_r16(enc_dev_t *enc, const u16 reg)
-{
- u8 dout[3];
- u8 din[3];
- u16 result;
- int nbytes = enc_reg2nbytes(reg);
-
- enc_set_bank(enc, reg);
- dout[0] = CMD_RCR(reg);
- spi_xfer(enc->slave, nbytes * 8, dout, din,
- SPI_XFER_BEGIN | SPI_XFER_END);
- result = din[nbytes-1];
- dout[0]++; /* next register */
- spi_xfer(enc->slave, nbytes * 8, dout, din,
- SPI_XFER_BEGIN | SPI_XFER_END);
- result |= din[nbytes-1] << 8;
- return result;
-}
-
-/*
- * Write a byte register
- */
-static void enc_w8(enc_dev_t *enc, const u16 reg, const u8 data)
-{
- u8 dout[2];
-
- enc_set_bank(enc, reg);
- dout[0] = CMD_WCR(reg);
- dout[1] = data;
- spi_xfer(enc->slave, 2 * 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
-}
-
-/*
- * Write a L/H register pair.
- * Must be called with the L register's address.
- */
-static void enc_w16(enc_dev_t *enc, const u16 reg, const u16 data)
-{
- u8 dout[2];
-
- enc_set_bank(enc, reg);
- dout[0] = CMD_WCR(reg);
- dout[1] = data;
- spi_xfer(enc->slave, 2 * 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
- dout[0]++; /* next register */
- dout[1] = data >> 8;
- spi_xfer(enc->slave, 2 * 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
-}
-
-/*
- * Write a byte register, verify and retry
- */
-static void enc_w8_retry(enc_dev_t *enc, const u16 reg, const u8 data, const int c)
-{
- u8 dout[2];
- u8 readback;
- int i;
-
- enc_set_bank(enc, reg);
- for (i = 0; i < c; i++) {
- dout[0] = CMD_WCR(reg);
- dout[1] = data;
- spi_xfer(enc->slave, 2 * 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
- readback = enc_r8(enc, reg);
- if (readback == data)
- break;
- /* wait 1ms */
- udelay(1000);
- }
- if (i == c) {
- printf("%s: write reg 0x%03x failed\n", enc->dev->name, reg);
- }
-}
-
-/*
- * Read ENC RAM into buffer
- */
-static void enc_rbuf(enc_dev_t *enc, const u16 length, u8 *buf)
-{
- u8 dout[1];
-
- dout[0] = CMD_RBM;
- spi_xfer(enc->slave, 8, dout, NULL, SPI_XFER_BEGIN);
- spi_xfer(enc->slave, length * 8, NULL, buf, SPI_XFER_END);
-#ifdef DEBUG
- puts("Rx:\n");
- print_buffer(0, buf, 1, length, 0);
-#endif
-}
-
-/*
- * Write buffer into ENC RAM
- */
-static void enc_wbuf(enc_dev_t *enc, const u16 length, const u8 *buf, const u8 control)
-{
- u8 dout[2];
- dout[0] = CMD_WBM;
- dout[1] = control;
- spi_xfer(enc->slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN);
- spi_xfer(enc->slave, length * 8, buf, NULL, SPI_XFER_END);
-#ifdef DEBUG
- puts("Tx:\n");
- print_buffer(0, buf, 1, length, 0);
-#endif
-}
-
-/*
- * Try to claim the SPI bus.
- * Print error message on failure.
- */
-static int enc_claim_bus(enc_dev_t *enc)
-{
- int rc = spi_claim_bus(enc->slave);
- if (rc)
- printf("%s: failed to claim SPI bus\n", enc->dev->name);
- return rc;
-}
-
-/*
- * Release previously claimed SPI bus.
- * This function is mainly for symmetry to enc_claim_bus().
- * Let the toolchain decide to inline it...
- */
-static void enc_release_bus(enc_dev_t *enc)
-{
- spi_release_bus(enc->slave);
-}
-
-/*
- * Read PHY register
- */
-static u16 enc_phy_read(enc_dev_t *enc, const u8 addr)
-{
- uint64_t etime;
- u8 status;
-
- enc_w8(enc, CTL_REG_MIREGADR, addr);
- enc_w8(enc, CTL_REG_MICMD, ENC_MICMD_MIIRD);
- /* 1 second timeout - only happens on hardware problem */
- etime = get_ticks() + get_tbclk();
- /* poll MISTAT.BUSY bit until operation is complete */
- do
- {
- status = enc_r8(enc, CTL_REG_MISTAT);
- } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
- if (status & ENC_MISTAT_BUSY) {
- printf("%s: timeout reading phy\n", enc->dev->name);
- return 0;
- }
- enc_w8(enc, CTL_REG_MICMD, 0);
- return enc_r16(enc, CTL_REG_MIRDL);
-}
-
-/*
- * Write PHY register
- */
-static void enc_phy_write(enc_dev_t *enc, const u8 addr, const u16 data)
-{
- uint64_t etime;
- u8 status;
-
- enc_w8(enc, CTL_REG_MIREGADR, addr);
- enc_w16(enc, CTL_REG_MIWRL, data);
- /* 1 second timeout - only happens on hardware problem */
- etime = get_ticks() + get_tbclk();
- /* poll MISTAT.BUSY bit until operation is complete */
- do
- {
- status = enc_r8(enc, CTL_REG_MISTAT);
- } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
- if (status & ENC_MISTAT_BUSY) {
- printf("%s: timeout writing phy\n", enc->dev->name);
- return;
- }
-}
-
-/*
- * Verify link status, wait if necessary
- *
- * Note: with a 10 MBit/s only PHY there is no autonegotiation possible,
- * half/full duplex is a pure setup matter. For the time being, this driver
- * will setup in half duplex mode only.
- */
-static int enc_phy_link_wait(enc_dev_t *enc)
-{
- u16 status;
- int duplex;
- uint64_t etime;
-
-#ifdef CONFIG_ENC_SILENTLINK
- /* check if we have a link, then just return */
- status = enc_phy_read(enc, PHY_REG_PHSTAT1);
- if (status & ENC_PHSTAT1_LLSTAT)
- return 0;
-#endif
-
- /* wait for link with 1 second timeout */
- etime = get_ticks() + get_tbclk();
- while (get_ticks() <= etime) {
- status = enc_phy_read(enc, PHY_REG_PHSTAT1);
- if (status & ENC_PHSTAT1_LLSTAT) {
- /* now we have a link */
- status = enc_phy_read(enc, PHY_REG_PHSTAT2);
- duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0;
- printf("%s: link up, 10Mbps %s-duplex\n",
- enc->dev->name, duplex ? "full" : "half");
- return 0;
- }
- udelay(1000);
- }
-
- /* timeout occurred */
- printf("%s: link down\n", enc->dev->name);
- return 1;
-}
-
-/*
- * This function resets the receiver only.
- */
-static void enc_reset_rx(enc_dev_t *enc)
-{
- u8 econ1;
-
- econ1 = enc_r8(enc, CTL_REG_ECON1);
- if ((econ1 & ENC_ECON1_RXRST) == 0) {
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
- enc->rx_reset_counter = RX_RESET_COUNTER;
- }
-}
-
-/*
- * Reset receiver and reenable it.
- */
-static void enc_reset_rx_call(enc_dev_t *enc)
-{
- enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
-}
-
-/*
- * Copy a packet from the receive ring and forward it to
- * the protocol stack.
- */
-static void enc_receive(enc_dev_t *enc)
-{
- u8 *packet = (u8 *)net_rx_packets[0];
- u16 pkt_len;
- u16 copy_len;
- u16 status;
- u8 pkt_cnt = 0;
- u16 rxbuf_rdpt;
- u8 hbuf[6];
-
- enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
- do {
- enc_rbuf(enc, 6, hbuf);
- enc->next_pointer = hbuf[0] | (hbuf[1] << 8);
- pkt_len = hbuf[2] | (hbuf[3] << 8);
- status = hbuf[4] | (hbuf[5] << 8);
- debug("next_pointer=$%04x pkt_len=%u status=$%04x\n",
- enc->next_pointer, pkt_len, status);
- if (pkt_len <= ENC_MAX_FRM_LEN)
- copy_len = pkt_len;
- else
- copy_len = 0;
- if ((status & (1L << 7)) == 0) /* check Received Ok bit */
- copy_len = 0;
- /* check if next pointer is resonable */
- if (enc->next_pointer >= ENC_TX_BUF_START)
- copy_len = 0;
- if (copy_len > 0) {
- enc_rbuf(enc, copy_len, packet);
- }
- /* advance read pointer to next pointer */
- enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
- /* decrease packet counter */
- enc_bset(enc, CTL_REG_ECON2, ENC_ECON2_PKTDEC);
- /*
- * Only odd values should be written to ERXRDPTL,
- * see errata B4 pt.13
- */
- rxbuf_rdpt = enc->next_pointer - 1;
- if ((rxbuf_rdpt < enc_r16(enc, CTL_REG_ERXSTL)) ||
- (rxbuf_rdpt > enc_r16(enc, CTL_REG_ERXNDL))) {
- enc_w16(enc, CTL_REG_ERXRDPTL,
- enc_r16(enc, CTL_REG_ERXNDL));
- } else {
- enc_w16(enc, CTL_REG_ERXRDPTL, rxbuf_rdpt);
- }
- /* read pktcnt */
- pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
- if (copy_len == 0) {
- (void)enc_r8(enc, CTL_REG_EIR);
- enc_reset_rx(enc);
- printf("%s: receive copy_len=0\n", enc->dev->name);
- continue;
- }
- /*
- * Because net_process_received_packet() might call enc_send(),
- * we need to release the SPI bus, call
- * net_process_received_packet(), reclaim the bus.
- */
- enc_release_bus(enc);
- net_process_received_packet(packet, pkt_len);
- if (enc_claim_bus(enc))
- return;
- (void)enc_r8(enc, CTL_REG_EIR);
- } while (pkt_cnt);
- /* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
-}
-
-/*
- * Poll for completely received packets.
- */
-static void enc_poll(enc_dev_t *enc)
-{
- u8 eir_reg;
- u8 pkt_cnt;
-
- (void)enc_r8(enc, CTL_REG_ESTAT);
- eir_reg = enc_r8(enc, CTL_REG_EIR);
- if (eir_reg & ENC_EIR_TXIF) {
- /* clear TXIF bit in EIR */
- enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXIF);
- }
- /* We have to use pktcnt and not pktif bit, see errata pt. 6 */
- pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
- if (pkt_cnt > 0) {
- if ((eir_reg & ENC_EIR_PKTIF) == 0) {
- debug("enc_poll: pkt cnt > 0, but pktif not set\n");
- }
- enc_receive(enc);
- /*
- * clear PKTIF bit in EIR, this should not need to be done
- * but it seems like we get problems if we do not
- */
- enc_bclr(enc, CTL_REG_EIR, ENC_EIR_PKTIF);
- }
- if (eir_reg & ENC_EIR_RXERIF) {
- printf("%s: rx error\n", enc->dev->name);
- enc_bclr(enc, CTL_REG_EIR, ENC_EIR_RXERIF);
- }
- if (eir_reg & ENC_EIR_TXERIF) {
- printf("%s: tx error\n", enc->dev->name);
- enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXERIF);
- }
-}
-
-/*
- * Completely Reset the ENC
- */
-static void enc_reset(enc_dev_t *enc)
-{
- u8 dout[1];
-
- dout[0] = CMD_SRC;
- spi_xfer(enc->slave, 8, dout, NULL,
- SPI_XFER_BEGIN | SPI_XFER_END);
- /* sleep 1 ms. See errata pt. 2 */
- udelay(1000);
-}
-
-/*
- * Initialisation data for most of the ENC registers
- */
-static const u16 enc_initdata[] = {
- /*
- * Setup the buffer space. The reset values are valid for the
- * other pointers.
- *
- * We shall not write to ERXST, see errata pt. 5. Instead we
- * have to make sure that ENC_RX_BUS_START is 0.
- */
- CTL_REG_ERXSTL, ENC_RX_BUF_START,
- CTL_REG_ERXSTH, ENC_RX_BUF_START >> 8,
- CTL_REG_ERXNDL, ENC_RX_BUF_END,
- CTL_REG_ERXNDH, ENC_RX_BUF_END >> 8,
- CTL_REG_ERDPTL, ENC_RX_BUF_START,
- CTL_REG_ERDPTH, ENC_RX_BUF_START >> 8,
- /*
- * Set the filter to receive only good-CRC, unicast and broadcast
- * frames.
- * Note: some DHCP servers return their answers as broadcasts!
- * So its unwise to remove broadcast from this. This driver
- * might incur receiver overruns with packet loss on a broadcast
- * flooded network.
- */
- CTL_REG_ERXFCON, ENC_RFR_BCEN | ENC_RFR_UCEN | ENC_RFR_CRCEN,
-
- /* enable MAC to receive frames */
- CTL_REG_MACON1,
- ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS,
-
- /* configure pad, tx-crc and duplex */
- CTL_REG_MACON3,
- ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN |
- ENC_MACON3_FRMLNEN,
-
- /* Allow infinite deferals if the medium is continously busy */
- CTL_REG_MACON4, ENC_MACON4_DEFER,
-
- /* Late collisions occur beyond 63 bytes */
- CTL_REG_MACLCON2, 63,
-
- /*
- * Set (low byte) Non-Back-to_Back Inter-Packet Gap.
- * Recommended 0x12
- */
- CTL_REG_MAIPGL, 0x12,
-
- /*
- * Set (high byte) Non-Back-to_Back Inter-Packet Gap.
- * Recommended 0x0c for half-duplex. Nothing for full-duplex
- */
- CTL_REG_MAIPGH, 0x0C,
-
- /* set maximum frame length */
- CTL_REG_MAMXFLL, ENC_MAX_FRM_LEN,
- CTL_REG_MAMXFLH, ENC_MAX_FRM_LEN >> 8,
-
- /*
- * Set MAC back-to-back inter-packet gap.
- * Recommended 0x12 for half duplex
- * and 0x15 for full duplex.
- */
- CTL_REG_MABBIPG, 0x12,
-
- /* end of table */
- 0xffff
-};
-
-/*
- * Wait for the XTAL oscillator to become ready
- */
-static int enc_clock_wait(enc_dev_t *enc)
-{
- uint64_t etime;
-
- /* one second timeout */
- etime = get_ticks() + get_tbclk();
-
- /*
- * Wait for CLKRDY to become set (i.e., check that we can
- * communicate with the ENC)
- */
- do
- {
- if (enc_r8(enc, CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY)
- return 0;
- } while (get_ticks() <= etime);
-
- printf("%s: timeout waiting for CLKRDY\n", enc->dev->name);
- return -1;
-}
-
-/*
- * Write the MAC address into the ENC
- */
-static int enc_write_macaddr(enc_dev_t *enc)
-{
- unsigned char *p = enc->dev->enetaddr;
-
- enc_w8_retry(enc, CTL_REG_MAADR5, *p++, 5);
- enc_w8_retry(enc, CTL_REG_MAADR4, *p++, 5);
- enc_w8_retry(enc, CTL_REG_MAADR3, *p++, 5);
- enc_w8_retry(enc, CTL_REG_MAADR2, *p++, 5);
- enc_w8_retry(enc, CTL_REG_MAADR1, *p++, 5);
- enc_w8_retry(enc, CTL_REG_MAADR0, *p, 5);
- return 0;
-}
-
-/*
- * Setup most of the ENC registers
- */
-static int enc_setup(enc_dev_t *enc)
-{
- u16 phid1 = 0;
- u16 phid2 = 0;
- const u16 *tp;
-
- /* reset enc struct values */
- enc->next_pointer = ENC_RX_BUF_START;
- enc->rx_reset_counter = RX_RESET_COUNTER;
- enc->bank = 0xff; /* invalidate current bank in enc28j60 */
-
- /* verify PHY identification */
- phid1 = enc_phy_read(enc, PHY_REG_PHID1);
- phid2 = enc_phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK;
- if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) {
- printf("%s: failed to identify PHY. Found %04x:%04x\n",
- enc->dev->name, phid1, phid2);
- return -1;
- }
-
- /* now program registers */
- for (tp = enc_initdata; *tp != 0xffff; tp += 2)
- enc_w8_retry(enc, tp[0], tp[1], 10);
-
- /*
- * Prevent automatic loopback of data beeing transmitted by setting
- * ENC_PHCON2_HDLDIS
- */
- enc_phy_write(enc, PHY_REG_PHCON2, (1<<8));
-
- /*
- * LEDs configuration
- * LEDA: LACFG = 0100 -> display link status
- * LEDB: LBCFG = 0111 -> display TX & RX activity
- * STRCH = 1 -> LED pulses
- */
- enc_phy_write(enc, PHY_REG_PHLCON, 0x0472);
-
- /* Reset PDPXMD-bit => half duplex */
- enc_phy_write(enc, PHY_REG_PHCON1, 0);
-
- return 0;
-}
-
-/*
- * Check if ENC has been initialized.
- * If not, try to initialize it.
- * Remember initialized state in struct.
- */
-static int enc_initcheck(enc_dev_t *enc, const enum enc_initstate requiredstate)
-{
- if (enc->initstate >= requiredstate)
- return 0;
-
- if (enc->initstate < setupdone) {
- /* Initialize the ENC only */
- enc_reset(enc);
- /* if any of functions fails, skip the rest and return an error */
- if (enc_clock_wait(enc) || enc_setup(enc) || enc_write_macaddr(enc)) {
- return -1;
- }
- enc->initstate = setupdone;
- }
- /* if that's all we need, return here */
- if (enc->initstate >= requiredstate)
- return 0;
-
- /* now wait for link ready condition */
- if (enc_phy_link_wait(enc)) {
- return -1;
- }
- enc->initstate = linkready;
- return 0;
-}
-
-#if defined(CONFIG_CMD_MII)
-/*
- * Read a PHY register.
- *
- * This function is registered with miiphy_register().
- */
-int enc_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg)
-{
- u16 value = 0;
- struct eth_device *dev = eth_get_dev_by_name(bus->name);
- enc_dev_t *enc;
-
- if (!dev || phy_adr != 0)
- return -1;
-
- enc = dev->priv;
- if (enc_claim_bus(enc))
- return -1;
- if (enc_initcheck(enc, setupdone)) {
- enc_release_bus(enc);
- return -1;
- }
- value = enc_phy_read(enc, reg);
- enc_release_bus(enc);
- return value;
-}
-
-/*
- * Write a PHY register.
- *
- * This function is registered with miiphy_register().
- */
-int enc_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg,
- u16 value)
-{
- struct eth_device *dev = eth_get_dev_by_name(bus->name);
- enc_dev_t *enc;
-
- if (!dev || phy_adr != 0)
- return -1;
-
- enc = dev->priv;
- if (enc_claim_bus(enc))
- return -1;
- if (enc_initcheck(enc, setupdone)) {
- enc_release_bus(enc);
- return -1;
- }
- enc_phy_write(enc, reg, value);
- enc_release_bus(enc);
- return 0;
-}
-#endif
-
-/*
- * Write hardware (MAC) address.
- *
- * This function entered into eth_device structure.
- */
-static int enc_write_hwaddr(struct eth_device *dev)
-{
- enc_dev_t *enc = dev->priv;
-
- if (enc_claim_bus(enc))
- return -1;
- if (enc_initcheck(enc, setupdone)) {
- enc_release_bus(enc);
- return -1;
- }
- enc_release_bus(enc);
- return 0;
-}
-
-/*
- * Initialize ENC28J60 for use.
- *
- * This function entered into eth_device structure.
- */
-static int enc_init(struct eth_device *dev, bd_t *bis)
-{
- enc_dev_t *enc = dev->priv;
-
- if (enc_claim_bus(enc))
- return -1;
- if (enc_initcheck(enc, linkready)) {
- enc_release_bus(enc);
- return -1;
- }
- /* enable receive */
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
- enc_release_bus(enc);
- return 0;
-}
-
-/*
- * Check for received packets.
- *
- * This function entered into eth_device structure.
- */
-static int enc_recv(struct eth_device *dev)
-{
- enc_dev_t *enc = dev->priv;
-
- if (enc_claim_bus(enc))
- return -1;
- if (enc_initcheck(enc, linkready)) {
- enc_release_bus(enc);
- return -1;
- }
- /* Check for dead receiver */
- if (enc->rx_reset_counter > 0)
- enc->rx_reset_counter--;
- else
- enc_reset_rx_call(enc);
- enc_poll(enc);
- enc_release_bus(enc);
- return 0;
-}
-
-/*
- * Send a packet.
- *
- * This function entered into eth_device structure.
- *
- * Should we wait here until we have a Link? Or shall we leave that to
- * protocol retries?
- */
-static int enc_send(
- struct eth_device *dev,
- void *packet,
- int length)
-{
- enc_dev_t *enc = dev->priv;
-
- if (enc_claim_bus(enc))
- return -1;
- if (enc_initcheck(enc, linkready)) {
- enc_release_bus(enc);
- return -1;
- }
- /* setup transmit pointers */
- enc_w16(enc, CTL_REG_EWRPTL, ENC_TX_BUF_START);
- enc_w16(enc, CTL_REG_ETXNDL, length + ENC_TX_BUF_START);
- enc_w16(enc, CTL_REG_ETXSTL, ENC_TX_BUF_START);
- /* write packet to ENC */
- enc_wbuf(enc, length, (u8 *) packet, 0x00);
- /*
- * Check that the internal transmit logic has not been altered
- * by excessive collisions. Reset transmitter if so.
- * See Errata B4 12 and 14.
- */
- if (enc_r8(enc, CTL_REG_EIR) & ENC_EIR_TXERIF) {
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
- enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
- }
- enc_bclr(enc, CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
- /* start transmitting */
- enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRTS);
- enc_release_bus(enc);
- return 0;
-}
-
-/*
- * Finish use of ENC.
- *
- * This function entered into eth_device structure.
- */
-static void enc_halt(struct eth_device *dev)
-{
- enc_dev_t *enc = dev->priv;
-
- if (enc_claim_bus(enc))
- return;
- /* Just disable receiver */
- enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
- enc_release_bus(enc);
-}
-
-/*
- * This is the only exported function.
- *
- * It may be called several times with different bus:cs combinations.
- */
-int enc28j60_initialize(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct eth_device *dev;
- enc_dev_t *enc;
-
- /* try to allocate, check and clear eth_device object */
- dev = malloc(sizeof(*dev));
- if (!dev) {
- return -1;
- }
- memset(dev, 0, sizeof(*dev));
-
- /* try to allocate, check and clear enc_dev_t object */
- enc = malloc(sizeof(*enc));
- if (!enc) {
- free(dev);
- return -1;
- }
- memset(enc, 0, sizeof(*enc));
-
- /* try to setup the SPI slave */
- enc->slave = spi_setup_slave(bus, cs, max_hz, mode);
- if (!enc->slave) {
- printf("enc28j60: invalid SPI device %i:%i\n", bus, cs);
- free(enc);
- free(dev);
- return -1;
- }
-
- enc->dev = dev;
- /* now fill the eth_device object */
- dev->priv = enc;
- dev->init = enc_init;
- dev->halt = enc_halt;
- dev->send = enc_send;
- dev->recv = enc_recv;
- dev->write_hwaddr = enc_write_hwaddr;
- sprintf(dev->name, "enc%i.%i", bus, cs);
- eth_register(dev);
-#if defined(CONFIG_CMD_MII)
- int retval;
- struct mii_dev *mdiodev = mdio_alloc();
- if (!mdiodev)
- return -ENOMEM;
- strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
- mdiodev->read = enc_miiphy_read;
- mdiodev->write = enc_miiphy_write;
-
- retval = mdio_register(mdiodev);
- if (retval < 0)
- return retval;
-#endif
- return 0;
-}
diff --git a/drivers/net/enc28j60.h b/drivers/net/enc28j60.h
deleted file mode 100644
index 289e41288e..0000000000
--- a/drivers/net/enc28j60.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * (X) extracted from enc28j60.c
- * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#ifndef _enc28j60_h
-#define _enc28j60_h
-
-/*
- * SPI Commands
- *
- * Bits 7-5: Command
- * Bits 4-0: Register
- */
-#define CMD_RCR(x) (0x00+((x)&0x1f)) /* Read Control Register */
-#define CMD_RBM 0x3a /* Read Buffer Memory */
-#define CMD_WCR(x) (0x40+((x)&0x1f)) /* Write Control Register */
-#define CMD_WBM 0x7a /* Write Buffer Memory */
-#define CMD_BFS(x) (0x80+((x)&0x1f)) /* Bit Field Set */
-#define CMD_BFC(x) (0xa0+((x)&0x1f)) /* Bit Field Clear */
-#define CMD_SRC 0xff /* System Reset Command */
-
-/* NEW: encode (bank number+1) in upper byte */
-
-/* Common Control Registers accessible in all Banks */
-#define CTL_REG_EIE 0x01B
-#define CTL_REG_EIR 0x01C
-#define CTL_REG_ESTAT 0x01D
-#define CTL_REG_ECON2 0x01E
-#define CTL_REG_ECON1 0x01F
-
-/* Control Registers accessible in Bank 0 */
-#define CTL_REG_ERDPTL 0x100
-#define CTL_REG_ERDPTH 0x101
-#define CTL_REG_EWRPTL 0x102
-#define CTL_REG_EWRPTH 0x103
-#define CTL_REG_ETXSTL 0x104
-#define CTL_REG_ETXSTH 0x105
-#define CTL_REG_ETXNDL 0x106
-#define CTL_REG_ETXNDH 0x107
-#define CTL_REG_ERXSTL 0x108
-#define CTL_REG_ERXSTH 0x109
-#define CTL_REG_ERXNDL 0x10A
-#define CTL_REG_ERXNDH 0x10B
-#define CTL_REG_ERXRDPTL 0x10C
-#define CTL_REG_ERXRDPTH 0x10D
-#define CTL_REG_ERXWRPTL 0x10E
-#define CTL_REG_ERXWRPTH 0x10F
-#define CTL_REG_EDMASTL 0x110
-#define CTL_REG_EDMASTH 0x111
-#define CTL_REG_EDMANDL 0x112
-#define CTL_REG_EDMANDH 0x113
-#define CTL_REG_EDMADSTL 0x114
-#define CTL_REG_EDMADSTH 0x115
-#define CTL_REG_EDMACSL 0x116
-#define CTL_REG_EDMACSH 0x117
-
-/* Control Registers accessible in Bank 1 */
-#define CTL_REG_EHT0 0x200
-#define CTL_REG_EHT1 0x201
-#define CTL_REG_EHT2 0x202
-#define CTL_REG_EHT3 0x203
-#define CTL_REG_EHT4 0x204
-#define CTL_REG_EHT5 0x205
-#define CTL_REG_EHT6 0x206
-#define CTL_REG_EHT7 0x207
-#define CTL_REG_EPMM0 0x208
-#define CTL_REG_EPMM1 0x209
-#define CTL_REG_EPMM2 0x20A
-#define CTL_REG_EPMM3 0x20B
-#define CTL_REG_EPMM4 0x20C
-#define CTL_REG_EPMM5 0x20D
-#define CTL_REG_EPMM6 0x20E
-#define CTL_REG_EPMM7 0x20F
-#define CTL_REG_EPMCSL 0x210
-#define CTL_REG_EPMCSH 0x211
-#define CTL_REG_EPMOL 0x214
-#define CTL_REG_EPMOH 0x215
-#define CTL_REG_EWOLIE 0x216
-#define CTL_REG_EWOLIR 0x217
-#define CTL_REG_ERXFCON 0x218
-#define CTL_REG_EPKTCNT 0x219
-
-/* Control Registers accessible in Bank 2 */
-#define CTL_REG_MACON1 0x300
-#define CTL_REG_MACON2 0x301
-#define CTL_REG_MACON3 0x302
-#define CTL_REG_MACON4 0x303
-#define CTL_REG_MABBIPG 0x304
-#define CTL_REG_MAIPGL 0x306
-#define CTL_REG_MAIPGH 0x307
-#define CTL_REG_MACLCON1 0x308
-#define CTL_REG_MACLCON2 0x309
-#define CTL_REG_MAMXFLL 0x30A
-#define CTL_REG_MAMXFLH 0x30B
-#define CTL_REG_MAPHSUP 0x30D
-#define CTL_REG_MICON 0x311
-#define CTL_REG_MICMD 0x312
-#define CTL_REG_MIREGADR 0x314
-#define CTL_REG_MIWRL 0x316
-#define CTL_REG_MIWRH 0x317
-#define CTL_REG_MIRDL 0x318
-#define CTL_REG_MIRDH 0x319
-
-/* Control Registers accessible in Bank 3 */
-#define CTL_REG_MAADR1 0x400
-#define CTL_REG_MAADR0 0x401
-#define CTL_REG_MAADR3 0x402
-#define CTL_REG_MAADR2 0x403
-#define CTL_REG_MAADR5 0x404
-#define CTL_REG_MAADR4 0x405
-#define CTL_REG_EBSTSD 0x406
-#define CTL_REG_EBSTCON 0x407
-#define CTL_REG_EBSTCSL 0x408
-#define CTL_REG_EBSTCSH 0x409
-#define CTL_REG_MISTAT 0x40A
-#define CTL_REG_EREVID 0x412
-#define CTL_REG_ECOCON 0x415
-#define CTL_REG_EFLOCON 0x417
-#define CTL_REG_EPAUSL 0x418
-#define CTL_REG_EPAUSH 0x419
-
-/* PHY Register */
-#define PHY_REG_PHCON1 0x00
-#define PHY_REG_PHSTAT1 0x01
-#define PHY_REG_PHID1 0x02
-#define PHY_REG_PHID2 0x03
-#define PHY_REG_PHCON2 0x10
-#define PHY_REG_PHSTAT2 0x11
-#define PHY_REG_PHLCON 0x14
-
-/* Receive Filter Register (ERXFCON) bits */
-#define ENC_RFR_UCEN 0x80
-#define ENC_RFR_ANDOR 0x40
-#define ENC_RFR_CRCEN 0x20
-#define ENC_RFR_PMEN 0x10
-#define ENC_RFR_MPEN 0x08
-#define ENC_RFR_HTEN 0x04
-#define ENC_RFR_MCEN 0x02
-#define ENC_RFR_BCEN 0x01
-
-/* ECON1 Register Bits */
-#define ENC_ECON1_TXRST 0x80
-#define ENC_ECON1_RXRST 0x40
-#define ENC_ECON1_DMAST 0x20
-#define ENC_ECON1_CSUMEN 0x10
-#define ENC_ECON1_TXRTS 0x08
-#define ENC_ECON1_RXEN 0x04
-#define ENC_ECON1_BSEL1 0x02
-#define ENC_ECON1_BSEL0 0x01
-
-/* ECON2 Register Bits */
-#define ENC_ECON2_AUTOINC 0x80
-#define ENC_ECON2_PKTDEC 0x40
-#define ENC_ECON2_PWRSV 0x20
-#define ENC_ECON2_VRPS 0x08
-
-/* EIR Register Bits */
-#define ENC_EIR_PKTIF 0x40
-#define ENC_EIR_DMAIF 0x20
-#define ENC_EIR_LINKIF 0x10
-#define ENC_EIR_TXIF 0x08
-#define ENC_EIR_WOLIF 0x04
-#define ENC_EIR_TXERIF 0x02
-#define ENC_EIR_RXERIF 0x01
-
-/* ESTAT Register Bits */
-#define ENC_ESTAT_INT 0x80
-#define ENC_ESTAT_LATECOL 0x10
-#define ENC_ESTAT_RXBUSY 0x04
-#define ENC_ESTAT_TXABRT 0x02
-#define ENC_ESTAT_CLKRDY 0x01
-
-/* EIE Register Bits */
-#define ENC_EIE_INTIE 0x80
-#define ENC_EIE_PKTIE 0x40
-#define ENC_EIE_DMAIE 0x20
-#define ENC_EIE_LINKIE 0x10
-#define ENC_EIE_TXIE 0x08
-#define ENC_EIE_WOLIE 0x04
-#define ENC_EIE_TXERIE 0x02
-#define ENC_EIE_RXERIE 0x01
-
-/* MACON1 Register Bits */
-#define ENC_MACON1_LOOPBK 0x10
-#define ENC_MACON1_TXPAUS 0x08
-#define ENC_MACON1_RXPAUS 0x04
-#define ENC_MACON1_PASSALL 0x02
-#define ENC_MACON1_MARXEN 0x01
-
-/* MACON2 Register Bits */
-#define ENC_MACON2_MARST 0x80
-#define ENC_MACON2_RNDRST 0x40
-#define ENC_MACON2_MARXRST 0x08
-#define ENC_MACON2_RFUNRST 0x04
-#define ENC_MACON2_MATXRST 0x02
-#define ENC_MACON2_TFUNRST 0x01
-
-/* MACON3 Register Bits */
-#define ENC_MACON3_PADCFG2 0x80
-#define ENC_MACON3_PADCFG1 0x40
-#define ENC_MACON3_PADCFG0 0x20
-#define ENC_MACON3_TXCRCEN 0x10
-#define ENC_MACON3_PHDRLEN 0x08
-#define ENC_MACON3_HFRMEN 0x04
-#define ENC_MACON3_FRMLNEN 0x02
-#define ENC_MACON3_FULDPX 0x01
-
-/* MACON4 Register Bits */
-#define ENC_MACON4_DEFER 0x40
-
-/* MICMD Register Bits */
-#define ENC_MICMD_MIISCAN 0x02
-#define ENC_MICMD_MIIRD 0x01
-
-/* MISTAT Register Bits */
-#define ENC_MISTAT_NVALID 0x04
-#define ENC_MISTAT_SCAN 0x02
-#define ENC_MISTAT_BUSY 0x01
-
-/* PHID1 and PHID2 values */
-#define ENC_PHID1_VALUE 0x0083
-#define ENC_PHID2_VALUE 0x1400
-#define ENC_PHID2_MASK 0xFC00
-
-/* PHCON1 values */
-#define ENC_PHCON1_PDPXMD 0x0100
-
-/* PHSTAT1 values */
-#define ENC_PHSTAT1_LLSTAT 0x0004
-
-/* PHSTAT2 values */
-#define ENC_PHSTAT2_LSTAT 0x0400
-#define ENC_PHSTAT2_DPXSTAT 0x0200
-
-#endif
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index ff7ad91116..0076d6323e 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <dm.h>
+#include <environment.h>
#include <malloc.h>
#include <memalign.h>
#include <miiphy.h>
@@ -806,7 +807,16 @@ static int fec_recv(struct eth_device *dev)
uint16_t bd_status;
ulong addr, size, end;
int i;
+
+#ifdef CONFIG_DM_ETH
+ *packetp = memalign(ARCH_DMA_MINALIGN, FEC_MAX_PKT_SIZE);
+ if (*packetp == 0) {
+ printf("%s: error allocating packetp\n", __func__);
+ return -ENOMEM;
+ }
+#else
ALLOC_CACHE_ALIGN_BUFFER(uchar, buff, FEC_MAX_PKT_SIZE);
+#endif
/* Check if any critical events have happened */
ievent = readl(&fec->eth->ievent);
@@ -882,8 +892,13 @@ static int fec_recv(struct eth_device *dev)
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
swap_packet((uint32_t *)addr, frame_length);
#endif
+
+#ifdef CONFIG_DM_ETH
+ memcpy(*packetp, (char *)addr, frame_length);
+#else
memcpy(buff, (char *)addr, frame_length);
net_process_received_packet(buff, frame_length);
+#endif
len = frame_length;
} else {
if (bd_status & FEC_RBD_ERR)
@@ -997,18 +1012,9 @@ static void fec_free_descs(struct fec_priv *fec)
free(fec->tbd_base);
}
-#ifdef CONFIG_DM_ETH
-struct mii_dev *fec_get_miibus(struct udevice *dev, int dev_id)
-#else
-struct mii_dev *fec_get_miibus(uint32_t base_addr, int dev_id)
-#endif
+struct mii_dev *fec_get_miibus(ulong base_addr, int dev_id)
{
-#ifdef CONFIG_DM_ETH
- struct fec_priv *priv = dev_get_priv(dev);
- struct ethernet_regs *eth = priv->eth;
-#else
- struct ethernet_regs *eth = (struct ethernet_regs *)(ulong)base_addr;
-#endif
+ struct ethernet_regs *eth = (struct ethernet_regs *)base_addr;
struct mii_dev *bus;
int ret;
@@ -1140,12 +1146,12 @@ int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr)
#endif
int ret;
-#ifdef CONFIG_MX28
+#ifdef CONFIG_FEC_MXC_MDIO_BASE
/*
* The i.MX28 has two ethernet interfaces, but they are not equal.
* Only the first one can access the MDIO bus.
*/
- base_mii = MXS_ENET0_BASE;
+ base_mii = CONFIG_FEC_MXC_MDIO_BASE;
#else
base_mii = addr;
#endif
@@ -1201,10 +1207,19 @@ static int fecmxc_read_rom_hwaddr(struct udevice *dev)
return fec_get_hwaddr(priv->dev_id, pdata->enetaddr);
}
+static int fecmxc_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ if (packet)
+ free(packet);
+
+ return 0;
+}
+
static const struct eth_ops fecmxc_ops = {
.start = fecmxc_init,
.send = fecmxc_send,
.recv = fecmxc_recv,
+ .free_pkt = fecmxc_free_pkt,
.stop = fecmxc_halt,
.write_hwaddr = fecmxc_set_hwaddr,
.read_rom_hwaddr = fecmxc_read_rom_hwaddr,
@@ -1236,7 +1251,6 @@ static int fecmxc_probe(struct udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev);
struct fec_priv *priv = dev_get_priv(dev);
struct mii_dev *bus = NULL;
- int dev_id = -1;
uint32_t start;
int ret;
@@ -1257,9 +1271,13 @@ static int fecmxc_probe(struct udevice *dev)
}
fec_reg_setup(priv);
- priv->dev_id = (dev_id == -1) ? 0 : dev_id;
- bus = fec_get_miibus(dev, dev_id);
+ priv->dev_id = dev->seq;
+#ifdef CONFIG_FEC_MXC_MDIO_BASE
+ bus = fec_get_miibus((ulong)CONFIG_FEC_MXC_MDIO_BASE, dev->seq);
+#else
+ bus = fec_get_miibus((ulong)priv->eth, dev->seq);
+#endif
if (!bus) {
ret = -ENOMEM;
goto err_mii;
@@ -1274,12 +1292,11 @@ static int fecmxc_probe(struct udevice *dev)
return 0;
-err_timeout:
- free(priv->phydev);
err_phy:
mdio_unregister(bus);
free(bus);
err_mii:
+err_timeout:
fec_free_descs(priv);
return ret;
}
@@ -1325,6 +1342,9 @@ static int fecmxc_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id fecmxc_ids[] = {
{ .compatible = "fsl,imx6q-fec" },
+ { .compatible = "fsl,imx6sl-fec" },
+ { .compatible = "fsl,imx6sx-fec" },
+ { .compatible = "fsl,imx6ul-fec" },
{ }
};
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
index 2d89cea4a3..00d905c299 100644
--- a/drivers/net/fsl_mcdmafec.c
+++ b/drivers/net/fsl_mcdmafec.c
@@ -9,6 +9,7 @@
*/
#include <common.h>
+#include <environment.h>
#include <malloc.h>
#include <command.h>
#include <config.h>
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index e62aefcd0d..fe370bf728 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -915,7 +915,7 @@ static int macb_recv(struct eth_device *netdev)
if (length >= 0) {
net_process_received_packet(packet, length);
reclaim_rx_buffers(macb, macb->next_rx_tail);
- } else if (length < 0) {
+ } else {
return length;
}
}
diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c
index ebcbed941a..505a2d1bee 100644
--- a/drivers/net/mcffec.c
+++ b/drivers/net/mcffec.c
@@ -9,6 +9,7 @@
*/
#include <common.h>
+#include <environment.h>
#include <malloc.h>
#include <command.h>
diff --git a/drivers/net/mpc8xx_fec.c b/drivers/net/mpc8xx_fec.c
index 71fe984a5d..1dd41df18b 100644
--- a/drivers/net/mpc8xx_fec.c
+++ b/drivers/net/mpc8xx_fec.c
@@ -7,10 +7,10 @@
#include <common.h>
#include <command.h>
-#include <commproc.h>
#include <malloc.h>
#include <net.h>
#include <netdev.h>
+#include <asm/cpm_8xx.h>
#include <asm/io.h>
#include <phy.h>
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index 83e3153768..f2e9acfd1f 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -890,6 +890,15 @@ static void mvneta_mac_addr_set(struct mvneta_port *pp, unsigned char *addr,
mvneta_set_ucast_addr(pp, addr[5], queue);
}
+static int mvneta_write_hwaddr(struct udevice *dev)
+{
+ mvneta_mac_addr_set(dev_get_priv(dev),
+ ((struct eth_pdata *)dev_get_platdata(dev))->enetaddr,
+ rxq_def);
+
+ return 0;
+}
+
/* Handle rx descriptor fill by setting buf_cookie and buf_phys_addr */
static void mvneta_rx_desc_fill(struct mvneta_rx_desc *rx_desc,
u32 phys_addr, u32 cookie)
@@ -1753,6 +1762,7 @@ static const struct eth_ops mvneta_ops = {
.send = mvneta_send,
.recv = mvneta_recv,
.stop = mvneta_stop,
+ .write_hwaddr = mvneta_write_hwaddr,
};
static int mvneta_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index e3d31a560d..62c0c2be06 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -5598,6 +5598,10 @@ static int mvpp2_base_bind(struct udevice *parent)
id += base_id_add;
name = calloc(1, 16);
+ if (!name) {
+ free(plat);
+ return -ENOMEM;
+ }
sprintf(name, "mvpp2-%d", id);
/* Create child device UCLASS_ETH and bind it */
diff --git a/drivers/net/ne2000_base.c b/drivers/net/ne2000_base.c
index fb088e06a4..421aa20ea6 100644
--- a/drivers/net/ne2000_base.c
+++ b/drivers/net/ne2000_base.c
@@ -74,6 +74,7 @@ Add SNMP
#include <common.h>
#include <command.h>
+#include <environment.h>
#include <net.h>
#include <malloc.h>
#include <linux/compiler.h>
diff --git a/drivers/net/pfe_eth/Kconfig b/drivers/net/pfe_eth/Kconfig
new file mode 100644
index 0000000000..a13b331a50
--- /dev/null
+++ b/drivers/net/pfe_eth/Kconfig
@@ -0,0 +1,12 @@
+menuconfig FSL_PFE
+ bool "NXP PFE Ethernet driver"
+ help
+ This driver provides support for NXP's Packet Forwarding Engine.
+
+if FSL_PFE
+
+config SYS_FSL_PFE_ADDR
+ hex "PFE base address"
+ default 0x04000000
+
+endif
diff --git a/drivers/net/pfe_eth/Makefile b/drivers/net/pfe_eth/Makefile
new file mode 100644
index 0000000000..6b5248f659
--- /dev/null
+++ b/drivers/net/pfe_eth/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2015-2016 Freescale Semiconductor, Inc.
+# Copyright 2017 NXP
+#
+# SPDX-License-Identifier:GPL-2.0+
+
+# Layerscape PFE driver
+obj-y += pfe_cmd.o \
+ pfe_driver.o \
+ pfe_eth.o \
+ pfe_firmware.o \
+ pfe_hw.o \
+ pfe_mdio.o
diff --git a/drivers/net/pfe_eth/pfe_cmd.c b/drivers/net/pfe_eth/pfe_cmd.c
new file mode 100644
index 0000000000..822dc0f141
--- /dev/null
+++ b/drivers/net/pfe_eth/pfe_cmd.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * @file
+ * @brief PFE utility commands
+ */
+
+#include <net/pfe_eth/pfe_eth.h>
+
+static inline void pfe_command_help(void)
+{
+ printf("Usage: pfe [pe | status | expt ] <options>\n");
+}
+
+static void pfe_command_pe(int argc, char * const argv[])
+{
+ if (argc >= 3 && strcmp(argv[2], "pmem") == 0) {
+ if (argc >= 4 && strcmp(argv[3], "read") == 0) {
+ int i;
+ int num;
+ int id;
+ u32 addr;
+ u32 size;
+ u32 val;
+
+ if (argc == 7) {
+ num = simple_strtoul(argv[6], NULL, 0);
+ } else if (argc == 6) {
+ num = 1;
+ } else {
+ printf("Usage: pfe pe pmem read <id> <addr> [<num>]\n");
+ return;
+ }
+
+ id = simple_strtoul(argv[4], NULL, 0);
+ addr = simple_strtoul(argv[5], NULL, 16);
+ size = 4;
+
+ for (i = 0; i < num; i++, addr += 4) {
+ val = pe_pmem_read(id, addr, size);
+ val = be32_to_cpu(val);
+ if (!(i & 3))
+ printf("%08x: ", addr);
+ printf("%08x%s", val, i == num - 1 || (i & 3)
+ == 3 ? "\n" : " ");
+ }
+
+ } else {
+ printf("Usage: pfe pe pmem read <parameters>\n");
+ }
+ } else if (argc >= 3 && strcmp(argv[2], "dmem") == 0) {
+ if (argc >= 4 && strcmp(argv[3], "read") == 0) {
+ int i;
+ int num;
+ int id;
+ u32 addr;
+ u32 size;
+ u32 val;
+
+ if (argc == 7) {
+ num = simple_strtoul(argv[6], NULL, 0);
+ } else if (argc == 6) {
+ num = 1;
+ } else {
+ printf("Usage: pfe pe dmem read <id> <addr> [<num>]\n");
+ return;
+ }
+
+ id = simple_strtoul(argv[4], NULL, 0);
+ addr = simple_strtoul(argv[5], NULL, 16);
+ size = 4;
+
+ for (i = 0; i < num; i++, addr += 4) {
+ val = pe_dmem_read(id, addr, size);
+ val = be32_to_cpu(val);
+ if (!(i & 3))
+ printf("%08x: ", addr);
+ printf("%08x%s", val, i == num - 1 || (i & 3)
+ == 3 ? "\n" : " ");
+ }
+
+ } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
+ int id;
+ u32 val;
+ u32 addr;
+ u32 size;
+
+ if (argc != 7) {
+ printf("Usage: pfe pe dmem write <id> <val> <addr>\n");
+ return;
+ }
+
+ id = simple_strtoul(argv[4], NULL, 0);
+ val = simple_strtoul(argv[5], NULL, 16);
+ val = cpu_to_be32(val);
+ addr = simple_strtoul(argv[6], NULL, 16);
+ size = 4;
+ pe_dmem_write(id, val, addr, size);
+ } else {
+ printf("Usage: pfe pe dmem [read | write] <parameters>\n");
+ }
+ } else if (argc >= 3 && strcmp(argv[2], "lmem") == 0) {
+ if (argc >= 4 && strcmp(argv[3], "read") == 0) {
+ int i;
+ int num;
+ u32 val;
+ u32 offset;
+
+ if (argc == 6) {
+ num = simple_strtoul(argv[5], NULL, 0);
+ } else if (argc == 5) {
+ num = 1;
+ } else {
+ printf("Usage: pfe pe lmem read <offset> [<num>]\n");
+ return;
+ }
+
+ offset = simple_strtoul(argv[4], NULL, 16);
+
+ for (i = 0; i < num; i++, offset += 4) {
+ pe_lmem_read(&val, 4, offset);
+ val = be32_to_cpu(val);
+ printf("%08x%s", val, i == num - 1 || (i & 7)
+ == 7 ? "\n" : " ");
+ }
+
+ } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
+ u32 val;
+ u32 offset;
+
+ if (argc != 6) {
+ printf("Usage: pfe pe lmem write <val> <offset>\n");
+ return;
+ }
+
+ val = simple_strtoul(argv[4], NULL, 16);
+ val = cpu_to_be32(val);
+ offset = simple_strtoul(argv[5], NULL, 16);
+ pe_lmem_write(&val, 4, offset);
+ } else {
+ printf("Usage: pfe pe lmem [read | write] <parameters>\n");
+ }
+ } else {
+ if (strcmp(argv[2], "help") != 0)
+ printf("Unknown option: %s\n", argv[2]);
+
+ printf("Usage: pfe pe <parameters>\n");
+ }
+}
+
+#define NUM_QUEUES 16
+
+/*
+ * qm_read_drop_stat
+ * This function is used to read the drop statistics from the TMU
+ * hw drop counter. Since the hw counter is always cleared afer
+ * reading, this function maintains the previous drop count, and
+ * adds the new value to it. That value can be retrieved by
+ * passing a pointer to it with the total_drops arg.
+ *
+ * @param tmu TMU number (0 - 3)
+ * @param queue queue number (0 - 15)
+ * @param total_drops pointer to location to store total drops (or NULL)
+ * @param do_reset if TRUE, clear total drops after updating
+ *
+ */
+u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset)
+{
+ static u32 qtotal[TMU_MAX_ID + 1][NUM_QUEUES];
+ u32 val;
+
+ writel((tmu << 8) | queue, TMU_TEQ_CTRL);
+ writel((tmu << 8) | queue, TMU_LLM_CTRL);
+ val = readl(TMU_TEQ_DROP_STAT);
+ qtotal[tmu][queue] += val;
+ if (total_drops)
+ *total_drops = qtotal[tmu][queue];
+ if (do_reset)
+ qtotal[tmu][queue] = 0;
+ return val;
+}
+
+static ssize_t tmu_queue_stats(char *buf, int tmu, int queue)
+{
+ ssize_t len = 0;
+ u32 drops;
+
+ printf("%d-%02d, ", tmu, queue);
+
+ drops = qm_read_drop_stat(tmu, queue, NULL, 0);
+
+ /* Select queue */
+ writel((tmu << 8) | queue, TMU_TEQ_CTRL);
+ writel((tmu << 8) | queue, TMU_LLM_CTRL);
+
+ printf("(teq) drop: %10u, tx: %10u (llm) head: %08x, tail: %08x, drop: %10u\n",
+ drops, readl(TMU_TEQ_TRANS_STAT),
+ readl(TMU_LLM_QUE_HEADPTR), readl(TMU_LLM_QUE_TAILPTR),
+ readl(TMU_LLM_QUE_DROPCNT));
+
+ return len;
+}
+
+static ssize_t tmu_queues(char *buf, int tmu)
+{
+ ssize_t len = 0;
+ int queue;
+
+ for (queue = 0; queue < 16; queue++)
+ len += tmu_queue_stats(buf + len, tmu, queue);
+
+ return len;
+}
+
+static inline void hif_status(void)
+{
+ printf("hif:\n");
+
+ printf(" tx curr bd: %x\n", readl(HIF_TX_CURR_BD_ADDR));
+ printf(" tx status: %x\n", readl(HIF_TX_STATUS));
+ printf(" tx dma status: %x\n", readl(HIF_TX_DMA_STATUS));
+
+ printf(" rx curr bd: %x\n", readl(HIF_RX_CURR_BD_ADDR));
+ printf(" rx status: %x\n", readl(HIF_RX_STATUS));
+ printf(" rx dma status: %x\n", readl(HIF_RX_DMA_STATUS));
+
+ printf("hif nocopy:\n");
+
+ printf(" tx curr bd: %x\n", readl(HIF_NOCPY_TX_CURR_BD_ADDR));
+ printf(" tx status: %x\n", readl(HIF_NOCPY_TX_STATUS));
+ printf(" tx dma status: %x\n", readl(HIF_NOCPY_TX_DMA_STATUS));
+
+ printf(" rx curr bd: %x\n", readl(HIF_NOCPY_RX_CURR_BD_ADDR));
+ printf(" rx status: %x\n", readl(HIF_NOCPY_RX_STATUS));
+ printf(" rx dma status: %x\n", readl(HIF_NOCPY_RX_DMA_STATUS));
+}
+
+static void gpi(int id, void *base)
+{
+ u32 val;
+
+ printf("%s%d:\n", __func__, id);
+
+ printf(" tx under stick: %x\n", readl(base + GPI_FIFO_STATUS));
+ val = readl(base + GPI_FIFO_DEBUG);
+ printf(" tx pkts: %x\n", (val >> 23) & 0x3f);
+ printf(" rx pkts: %x\n", (val >> 18) & 0x3f);
+ printf(" tx bytes: %x\n", (val >> 9) & 0x1ff);
+ printf(" rx bytes: %x\n", (val >> 0) & 0x1ff);
+ printf(" overrun: %x\n", readl(base + GPI_OVERRUN_DROPCNT));
+}
+
+static void bmu(int id, void *base)
+{
+ printf("%s%d:\n", __func__, id);
+
+ printf(" buf size: %x\n", (1 << readl(base + BMU_BUF_SIZE)));
+ printf(" buf count: %x\n", readl(base + BMU_BUF_CNT));
+ printf(" buf rem: %x\n", readl(base + BMU_REM_BUF_CNT));
+ printf(" buf curr: %x\n", readl(base + BMU_CURR_BUF_CNT));
+ printf(" free err: %x\n", readl(base + BMU_FREE_ERR_ADDR));
+}
+
+#define PESTATUS_ADDR_CLASS 0x800
+#define PEMBOX_ADDR_CLASS 0x890
+#define PESTATUS_ADDR_TMU 0x80
+#define PEMBOX_ADDR_TMU 0x290
+#define PESTATUS_ADDR_UTIL 0x0
+
+static void pfe_pe_status(int argc, char * const argv[])
+{
+ int do_clear = 0;
+ u32 id;
+ u32 dmem_addr;
+ u32 cpu_state;
+ u32 activity_counter;
+ u32 rx;
+ u32 tx;
+ u32 drop;
+ char statebuf[5];
+ u32 class_debug_reg = 0;
+
+ if (argc == 4 && strcmp(argv[3], "clear") == 0)
+ do_clear = 1;
+
+ for (id = CLASS0_ID; id < MAX_PE; id++) {
+ if (id >= TMU0_ID) {
+ if (id == TMU2_ID)
+ continue;
+ if (id == TMU0_ID)
+ printf("tmu:\n");
+ dmem_addr = PESTATUS_ADDR_TMU;
+ } else {
+ if (id == CLASS0_ID)
+ printf("class:\n");
+ dmem_addr = PESTATUS_ADDR_CLASS;
+ class_debug_reg = readl(CLASS_PE0_DEBUG + id * 4);
+ }
+
+ cpu_state = pe_dmem_read(id, dmem_addr, 4);
+ dmem_addr += 4;
+ memcpy(statebuf, (char *)&cpu_state, 4);
+ statebuf[4] = '\0';
+ activity_counter = pe_dmem_read(id, dmem_addr, 4);
+ dmem_addr += 4;
+ rx = pe_dmem_read(id, dmem_addr, 4);
+ if (do_clear)
+ pe_dmem_write(id, 0, dmem_addr, 4);
+ dmem_addr += 4;
+ tx = pe_dmem_read(id, dmem_addr, 4);
+ if (do_clear)
+ pe_dmem_write(id, 0, dmem_addr, 4);
+ dmem_addr += 4;
+ drop = pe_dmem_read(id, dmem_addr, 4);
+ if (do_clear)
+ pe_dmem_write(id, 0, dmem_addr, 4);
+ dmem_addr += 4;
+
+ if (id >= TMU0_ID) {
+ printf("%d: state=%4s ctr=%08x rx=%x qstatus=%x\n",
+ id - TMU0_ID, statebuf,
+ cpu_to_be32(activity_counter),
+ cpu_to_be32(rx), cpu_to_be32(tx));
+ } else {
+ printf("%d: pc=1%04x ldst=%04x state=%4s ctr=%08x rx=%x tx=%x drop=%x\n",
+ id - CLASS0_ID, class_debug_reg & 0xFFFF,
+ class_debug_reg >> 16,
+ statebuf, cpu_to_be32(activity_counter),
+ cpu_to_be32(rx), cpu_to_be32(tx),
+ cpu_to_be32(drop));
+ }
+ }
+}
+
+static void pfe_command_status(int argc, char * const argv[])
+{
+ if (argc >= 3 && strcmp(argv[2], "pe") == 0) {
+ pfe_pe_status(argc, argv);
+ } else if (argc == 3 && strcmp(argv[2], "bmu") == 0) {
+ bmu(1, BMU1_BASE_ADDR);
+ bmu(2, BMU2_BASE_ADDR);
+ } else if (argc == 3 && strcmp(argv[2], "hif") == 0) {
+ hif_status();
+ } else if (argc == 3 && strcmp(argv[2], "gpi") == 0) {
+ gpi(0, EGPI1_BASE_ADDR);
+ gpi(1, EGPI2_BASE_ADDR);
+ gpi(3, HGPI_BASE_ADDR);
+ } else if (argc == 3 && strcmp(argv[2], "tmu0_queues") == 0) {
+ tmu_queues(NULL, 0);
+ } else if (argc == 3 && strcmp(argv[2], "tmu1_queues") == 0) {
+ tmu_queues(NULL, 1);
+ } else if (argc == 3 && strcmp(argv[2], "tmu3_queues") == 0) {
+ tmu_queues(NULL, 3);
+ } else {
+ printf("Usage: pfe status [pe <clear> | bmu | gpi | hif | tmuX_queues ]\n");
+ }
+}
+
+#define EXPT_DUMP_ADDR 0x1fa8
+#define EXPT_REG_COUNT 20
+static const char *register_names[EXPT_REG_COUNT] = {
+ " pc", "ECAS", " EID", " ED",
+ " sp", " r1", " r2", " r3",
+ " r4", " r5", " r6", " r7",
+ " r8", " r9", " r10", " r11",
+ " r12", " r13", " r14", " r15"
+};
+
+static void pfe_command_expt(int argc, char * const argv[])
+{
+ unsigned int id, i, val, addr;
+
+ if (argc == 3) {
+ id = simple_strtoul(argv[2], NULL, 0);
+ addr = EXPT_DUMP_ADDR;
+ printf("Exception information for PE %d:\n", id);
+ for (i = 0; i < EXPT_REG_COUNT; i++) {
+ val = pe_dmem_read(id, addr, 4);
+ val = be32_to_cpu(val);
+ printf("%s:%08x%s", register_names[i], val,
+ (i & 3) == 3 ? "\n" : " ");
+ addr += 4;
+ }
+ } else {
+ printf("Usage: pfe expt <id>\n");
+ }
+}
+
+#ifdef PFE_RESET_WA
+/*This function sends a dummy packet to HIF through TMU3 */
+static void send_dummy_pkt_to_hif(void)
+{
+ u32 buf;
+ static u32 dummy_pkt[] = {
+ 0x4200800a, 0x01000003, 0x00018100, 0x00000000,
+ 0x33221100, 0x2b785544, 0xd73093cb, 0x01000608,
+ 0x04060008, 0x2b780200, 0xd73093cb, 0x0a01a8c0,
+ 0x33221100, 0xa8c05544, 0x00000301, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xbe86c51f };
+
+ /*Allocate BMU2 buffer */
+ buf = readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL);
+
+ debug("Sending a dummy pkt to HIF %x\n", buf);
+ buf += 0x80;
+ memcpy((void *)DDR_PFE_TO_VIRT(buf), dummy_pkt, sizeof(dummy_pkt));
+
+ /*Write length and pkt to TMU*/
+ writel(0x03000042, TMU_PHY_INQ_PKTPTR);
+ writel(buf, TMU_PHY_INQ_PKTINFO);
+}
+
+static void pfe_command_stop(int argc, char * const argv[])
+{
+ int pfe_pe_id, hif_stop_loop = 10;
+ u32 rx_status;
+
+ printf("Stopping PFE...\n");
+
+ /*Mark all descriptors as LAST_BD */
+ hif_rx_desc_disable();
+
+ /*If HIF Rx BDP is busy send a dummy packet */
+ do {
+ rx_status = readl(HIF_RX_STATUS);
+ if (rx_status & BDP_CSR_RX_DMA_ACTV)
+ send_dummy_pkt_to_hif();
+ udelay(10);
+ } while (hif_stop_loop--);
+
+ if (readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)
+ printf("Unable to stop HIF\n");
+
+ /*Disable Class PEs */
+ for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
+ /*Inform PE to stop */
+ pe_dmem_write(pfe_pe_id, cpu_to_be32(1), PEMBOX_ADDR_CLASS, 4);
+ udelay(10);
+
+ /*Read status */
+ if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_CLASS + 4, 4))
+ printf("Failed to stop PE%d\n", pfe_pe_id);
+ }
+
+ /*Disable TMU PEs */
+ for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
+ if (pfe_pe_id == TMU2_ID)
+ continue;
+
+ /*Inform PE to stop */
+ pe_dmem_write(pfe_pe_id, 1, PEMBOX_ADDR_TMU, 4);
+ udelay(10);
+
+ /*Read status */
+ if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_TMU + 4, 4))
+ printf("Failed to stop PE%d\n", pfe_pe_id);
+ }
+}
+#endif
+
+static int pfe_command(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ if (argc == 1 || strcmp(argv[1], "help") == 0) {
+ pfe_command_help();
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(argv[1], "pe") == 0) {
+ pfe_command_pe(argc, argv);
+ } else if (strcmp(argv[1], "status") == 0) {
+ pfe_command_status(argc, argv);
+ } else if (strcmp(argv[1], "expt") == 0) {
+ pfe_command_expt(argc, argv);
+#ifdef PFE_RESET_WA
+ } else if (strcmp(argv[1], "stop") == 0) {
+ pfe_command_stop(argc, argv);
+#endif
+ } else {
+ printf("Unknown option: %s\n", argv[1]);
+ pfe_command_help();
+ return CMD_RET_FAILURE;
+ }
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ pfe, 7, 1, pfe_command,
+ "Performs PFE lib utility functions",
+ "Usage:\n"
+ "pfe <options>"
+);
diff --git a/drivers/net/pfe_eth/pfe_driver.c b/drivers/net/pfe_eth/pfe_driver.c
new file mode 100644
index 0000000000..a9991f5c2b
--- /dev/null
+++ b/drivers/net/pfe_eth/pfe_driver.c
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe_firmware.h>
+
+static struct tx_desc_s *g_tx_desc;
+static struct rx_desc_s *g_rx_desc;
+
+/*
+ * HIF Rx interface function
+ * Reads the rx descriptor from the current location (rx_to_read).
+ * - If the descriptor has a valid data/pkt, then get the data pointer
+ * - check for the input rx phy number
+ * - increment the rx data pointer by pkt_head_room_size
+ * - decrement the data length by pkt_head_room_size
+ * - handover the packet to caller.
+ *
+ * @param[out] pkt_ptr - Pointer to store rx packet
+ * @param[out] phy_port - Pointer to store recv phy port
+ *
+ * @return -1 if no packet, else return length of packet.
+ */
+int pfe_recv(uchar **pkt_ptr, int *phy_port)
+{
+ struct rx_desc_s *rx_desc = g_rx_desc;
+ struct buf_desc *bd;
+ int len = 0;
+
+ struct hif_header_s *hif_header;
+
+ bd = rx_desc->rx_base + rx_desc->rx_to_read;
+
+ if (readl(&bd->ctrl) & BD_CTRL_DESC_EN)
+ return len; /* No pending Rx packet */
+
+ /* this len include hif_header(8 bytes) */
+ len = readl(&bd->ctrl) & 0xFFFF;
+
+ hif_header = (struct hif_header_s *)DDR_PFE_TO_VIRT(readl(&bd->data));
+
+ /* Get the receive port info from the packet */
+ debug("Pkt received:");
+ debug(" Pkt ptr(%p), len(%d), gemac_port(%d) status(%08x)\n",
+ hif_header, len, hif_header->port_no, readl(&bd->status));
+#ifdef DEBUG
+ {
+ int i;
+ unsigned char *p = (unsigned char *)hif_header;
+
+ for (i = 0; i < len; i++) {
+ if (!(i % 16))
+ printf("\n");
+ printf(" %02x", p[i]);
+ }
+ printf("\n");
+ }
+#endif
+
+ *pkt_ptr = (uchar *)(hif_header + 1);
+ *phy_port = hif_header->port_no;
+ len -= sizeof(struct hif_header_s);
+
+ return len;
+}
+
+/*
+ * HIF function to check the Rx done
+ * This function will check the rx done indication of the current rx_to_read
+ * locations
+ * if success, moves the rx_to_read to next location.
+ */
+int pfe_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct rx_desc_s *rx_desc = g_rx_desc;
+ struct buf_desc *bd;
+
+ debug("%s:rx_base: %p, rx_to_read: %d\n", __func__, rx_desc->rx_base,
+ rx_desc->rx_to_read);
+
+ bd = rx_desc->rx_base + rx_desc->rx_to_read;
+
+ /* reset the control field */
+ writel((MAX_FRAME_SIZE | BD_CTRL_LIFM | BD_CTRL_DESC_EN
+ | BD_CTRL_DIR), &bd->ctrl);
+ writel(0, &bd->status);
+
+ debug("Rx Done : status: %08x, ctrl: %08x\n", readl(&bd->status),
+ readl(&bd->ctrl));
+
+ /* Give START_STROBE to BDP to fetch the descriptor __NOW__,
+ * BDP need not wait for rx_poll_cycle time to fetch the descriptor,
+ * In idle state (ie., no rx pkt), BDP will not fetch
+ * the descriptor even if strobe is given.
+ */
+ writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+
+ /* increment the rx_to_read index to next location */
+ rx_desc->rx_to_read = (rx_desc->rx_to_read + 1)
+ & (rx_desc->rx_ring_size - 1);
+
+ debug("Rx next pkt location: %d\n", rx_desc->rx_to_read);
+
+ return 0;
+}
+
+/*
+ * HIF Tx interface function
+ * This function sends a single packet to PFE from HIF interface.
+ * - No interrupt indication on tx completion.
+ * - Data is copied to tx buffers before tx descriptor is updated
+ * and TX DMA is enabled.
+ *
+ * @param[in] phy_port Phy port number to send out this packet
+ * @param[in] data Pointer to the data
+ * @param[in] length Length of the ethernet packet to be transferred.
+ *
+ * @return -1 if tx Q is full, else returns the tx location where the pkt is
+ * placed.
+ */
+int pfe_send(int phy_port, void *data, int length)
+{
+ struct tx_desc_s *tx_desc = g_tx_desc;
+ struct buf_desc *bd;
+ struct hif_header_s hif_header;
+ u8 *tx_buf_va;
+
+ debug("%s:pkt: %p, len: %d, tx_base: %p, tx_to_send: %d\n", __func__,
+ data, length, tx_desc->tx_base, tx_desc->tx_to_send);
+
+ bd = tx_desc->tx_base + tx_desc->tx_to_send;
+
+ /* check queue-full condition */
+ if (readl(&bd->ctrl) & BD_CTRL_DESC_EN)
+ return -1;
+
+ /* PFE checks for min pkt size */
+ if (length < MIN_PKT_SIZE)
+ length = MIN_PKT_SIZE;
+
+ tx_buf_va = (void *)DDR_PFE_TO_VIRT(readl(&bd->data));
+ debug("%s: tx_buf_va: %p, tx_buf_pa: %08x\n", __func__, tx_buf_va,
+ readl(&bd->data));
+
+ /* Fill the gemac/phy port number to send this packet out */
+ memset(&hif_header, 0, sizeof(struct hif_header_s));
+ hif_header.port_no = phy_port;
+
+ memcpy(tx_buf_va, (u8 *)&hif_header, sizeof(struct hif_header_s));
+ memcpy(tx_buf_va + sizeof(struct hif_header_s), data, length);
+ length += sizeof(struct hif_header_s);
+
+#ifdef DEBUG
+ {
+ int i;
+ unsigned char *p = (unsigned char *)tx_buf_va;
+
+ for (i = 0; i < length; i++) {
+ if (!(i % 16))
+ printf("\n");
+ printf("%02x ", p[i]);
+ }
+ }
+#endif
+
+ debug("Tx Done: status: %08x, ctrl: %08x\n", readl(&bd->status),
+ readl(&bd->ctrl));
+
+ /* fill the tx desc */
+ writel((u32)(BD_CTRL_DESC_EN | BD_CTRL_LIFM | (length & 0xFFFF)),
+ &bd->ctrl);
+ writel(0, &bd->status);
+
+ writel((HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB), HIF_TX_CTRL);
+
+ udelay(100);
+
+ return tx_desc->tx_to_send;
+}
+
+/*
+ * HIF function to check the Tx done
+ * This function will check the tx done indication of the current tx_to_send
+ * locations
+ * if success, moves the tx_to_send to next location.
+ *
+ * @return -1 if TX ownership bit is not cleared by hw.
+ * else on success (tx done completion) return zero.
+ */
+int pfe_tx_done(void)
+{
+ struct tx_desc_s *tx_desc = g_tx_desc;
+ struct buf_desc *bd;
+
+ debug("%s:tx_base: %p, tx_to_send: %d\n", __func__, tx_desc->tx_base,
+ tx_desc->tx_to_send);
+
+ bd = tx_desc->tx_base + tx_desc->tx_to_send;
+
+ /* check queue-full condition */
+ if (readl(&bd->ctrl) & BD_CTRL_DESC_EN)
+ return -1;
+
+ /* reset the control field */
+ writel(0, &bd->ctrl);
+ writel(0, &bd->status);
+
+ debug("Tx Done : status: %08x, ctrl: %08x\n", readl(&bd->status),
+ readl(&bd->ctrl));
+
+ /* increment the txtosend index to next location */
+ tx_desc->tx_to_send = (tx_desc->tx_to_send + 1)
+ & (tx_desc->tx_ring_size - 1);
+
+ debug("Tx next pkt location: %d\n", tx_desc->tx_to_send);
+
+ return 0;
+}
+
+/*
+ * Helper function to dump Rx descriptors.
+ */
+static inline void hif_rx_desc_dump(void)
+{
+ struct buf_desc *bd_va;
+ int i;
+ struct rx_desc_s *rx_desc;
+
+ if (!g_rx_desc) {
+ printf("%s: HIF Rx desc no init\n", __func__);
+ return;
+ }
+
+ rx_desc = g_rx_desc;
+ bd_va = rx_desc->rx_base;
+
+ debug("HIF rx desc: base_va: %p, base_pa: %08x\n", rx_desc->rx_base,
+ rx_desc->rx_base_pa);
+ for (i = 0; i < rx_desc->rx_ring_size; i++) {
+ debug("status: %08x, ctrl: %08x, data: %08x, next: 0x%08x\n",
+ readl(&bd_va->status),
+ readl(&bd_va->ctrl),
+ readl(&bd_va->data),
+ readl(&bd_va->next));
+ bd_va++;
+ }
+}
+
+/*
+ * This function mark all Rx descriptors as LAST_BD.
+ */
+void hif_rx_desc_disable(void)
+{
+ int i;
+ struct rx_desc_s *rx_desc;
+ struct buf_desc *bd_va;
+
+ if (!g_rx_desc) {
+ printf("%s: HIF Rx desc not initialized\n", __func__);
+ return;
+ }
+
+ rx_desc = g_rx_desc;
+ bd_va = rx_desc->rx_base;
+
+ for (i = 0; i < rx_desc->rx_ring_size; i++) {
+ writel(readl(&bd_va->ctrl) | BD_CTRL_LAST_BD, &bd_va->ctrl);
+ bd_va++;
+ }
+}
+
+/*
+ * HIF Rx Desc initialization function.
+ */
+static int hif_rx_desc_init(struct pfe_ddr_address *pfe_addr)
+{
+ u32 ctrl;
+ struct buf_desc *bd_va;
+ struct buf_desc *bd_pa;
+ struct rx_desc_s *rx_desc;
+ u32 rx_buf_pa;
+ int i;
+
+ /* sanity check */
+ if (g_rx_desc) {
+ printf("%s: HIF Rx desc re-init request\n", __func__);
+ return 0;
+ }
+
+ rx_desc = (struct rx_desc_s *)malloc(sizeof(struct rx_desc_s));
+ if (!rx_desc) {
+ printf("%s: Memory allocation failure\n", __func__);
+ return -ENOMEM;
+ }
+ memset(rx_desc, 0, sizeof(struct rx_desc_s));
+
+ /* init: Rx ring buffer */
+ rx_desc->rx_ring_size = HIF_RX_DESC_NT;
+
+ /* NOTE: must be 64bit aligned */
+ bd_va = (struct buf_desc *)(pfe_addr->ddr_pfe_baseaddr
+ + RX_BD_BASEADDR);
+ bd_pa = (struct buf_desc *)(pfe_addr->ddr_pfe_phys_baseaddr
+ + RX_BD_BASEADDR);
+
+ rx_desc->rx_base = bd_va;
+ rx_desc->rx_base_pa = (unsigned long)bd_pa;
+
+ rx_buf_pa = pfe_addr->ddr_pfe_phys_baseaddr + HIF_RX_PKT_DDR_BASEADDR;
+
+ debug("%s: Rx desc base: %p, base_pa: %08x, desc_count: %d\n",
+ __func__, rx_desc->rx_base, rx_desc->rx_base_pa,
+ rx_desc->rx_ring_size);
+
+ memset(bd_va, 0, sizeof(struct buf_desc) * rx_desc->rx_ring_size);
+
+ ctrl = (MAX_FRAME_SIZE | BD_CTRL_DESC_EN | BD_CTRL_DIR | BD_CTRL_LIFM);
+
+ for (i = 0; i < rx_desc->rx_ring_size; i++) {
+ writel((unsigned long)(bd_pa + 1), &bd_va->next);
+ writel(ctrl, &bd_va->ctrl);
+ writel(rx_buf_pa + (i * MAX_FRAME_SIZE), &bd_va->data);
+ bd_va++;
+ bd_pa++;
+ }
+ --bd_va;
+ writel((u32)rx_desc->rx_base_pa, &bd_va->next);
+
+ writel(rx_desc->rx_base_pa, HIF_RX_BDP_ADDR);
+ writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+
+ g_rx_desc = rx_desc;
+
+ return 0;
+}
+
+/*
+ * Helper function to dump Tx Descriptors.
+ */
+static inline void hif_tx_desc_dump(void)
+{
+ struct tx_desc_s *tx_desc;
+ int i;
+ struct buf_desc *bd_va;
+
+ if (!g_tx_desc) {
+ printf("%s: HIF Tx desc no init\n", __func__);
+ return;
+ }
+
+ tx_desc = g_tx_desc;
+ bd_va = tx_desc->tx_base;
+
+ debug("HIF tx desc: base_va: %p, base_pa: %08x\n", tx_desc->tx_base,
+ tx_desc->tx_base_pa);
+
+ for (i = 0; i < tx_desc->tx_ring_size; i++)
+ bd_va++;
+}
+
+/*
+ * HIF Tx descriptor initialization function.
+ */
+static int hif_tx_desc_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct buf_desc *bd_va;
+ struct buf_desc *bd_pa;
+ int i;
+ struct tx_desc_s *tx_desc;
+ u32 tx_buf_pa;
+
+ /* sanity check */
+ if (g_tx_desc) {
+ printf("%s: HIF Tx desc re-init request\n", __func__);
+ return 0;
+ }
+
+ tx_desc = (struct tx_desc_s *)malloc(sizeof(struct tx_desc_s));
+ if (!tx_desc) {
+ printf("%s:%d:Memory allocation failure\n", __func__,
+ __LINE__);
+ return -ENOMEM;
+ }
+ memset(tx_desc, 0, sizeof(struct tx_desc_s));
+
+ /* init: Tx ring buffer */
+ tx_desc->tx_ring_size = HIF_TX_DESC_NT;
+
+ /* NOTE: must be 64bit aligned */
+ bd_va = (struct buf_desc *)(pfe_addr->ddr_pfe_baseaddr
+ + TX_BD_BASEADDR);
+ bd_pa = (struct buf_desc *)(pfe_addr->ddr_pfe_phys_baseaddr
+ + TX_BD_BASEADDR);
+
+ tx_desc->tx_base_pa = (unsigned long)bd_pa;
+ tx_desc->tx_base = bd_va;
+
+ debug("%s: Tx desc_base: %p, base_pa: %08x, desc_count: %d\n",
+ __func__, tx_desc->tx_base, tx_desc->tx_base_pa,
+ tx_desc->tx_ring_size);
+
+ memset(bd_va, 0, sizeof(struct buf_desc) * tx_desc->tx_ring_size);
+
+ tx_buf_pa = pfe_addr->ddr_pfe_phys_baseaddr + HIF_TX_PKT_DDR_BASEADDR;
+
+ for (i = 0; i < tx_desc->tx_ring_size; i++) {
+ writel((unsigned long)(bd_pa + 1), &bd_va->next);
+ writel(tx_buf_pa + (i * MAX_FRAME_SIZE), &bd_va->data);
+ bd_va++;
+ bd_pa++;
+ }
+ --bd_va;
+ writel((u32)tx_desc->tx_base_pa, &bd_va->next);
+
+ writel(tx_desc->tx_base_pa, HIF_TX_BDP_ADDR);
+
+ g_tx_desc = tx_desc;
+
+ return 0;
+}
+
+/*
+ * PFE/Class initialization.
+ */
+static void pfe_class_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct class_cfg class_cfg = {
+ .route_table_baseaddr = pfe_addr->ddr_pfe_phys_baseaddr +
+ ROUTE_TABLE_BASEADDR,
+ .route_table_hash_bits = ROUTE_TABLE_HASH_BITS,
+ };
+
+ class_init(&class_cfg);
+
+ debug("class init complete\n");
+}
+
+/*
+ * PFE/TMU initialization.
+ */
+static void pfe_tmu_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct tmu_cfg tmu_cfg = {
+ .llm_base_addr = pfe_addr->ddr_pfe_phys_baseaddr
+ + TMU_LLM_BASEADDR,
+ .llm_queue_len = TMU_LLM_QUEUE_LEN,
+ };
+
+ tmu_init(&tmu_cfg);
+
+ debug("tmu init complete\n");
+}
+
+/*
+ * PFE/BMU (both BMU1 & BMU2) initialization.
+ */
+static void pfe_bmu_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct bmu_cfg bmu1_cfg = {
+ .baseaddr = CBUS_VIRT_TO_PFE(LMEM_BASE_ADDR +
+ BMU1_LMEM_BASEADDR),
+ .count = BMU1_BUF_COUNT,
+ .size = BMU1_BUF_SIZE,
+ };
+
+ struct bmu_cfg bmu2_cfg = {
+ .baseaddr = pfe_addr->ddr_pfe_phys_baseaddr + BMU2_DDR_BASEADDR,
+ .count = BMU2_BUF_COUNT,
+ .size = BMU2_BUF_SIZE,
+ };
+
+ bmu_init(BMU1_BASE_ADDR, &bmu1_cfg);
+ debug("bmu1 init: done\n");
+
+ bmu_init(BMU2_BASE_ADDR, &bmu2_cfg);
+ debug("bmu2 init: done\n");
+}
+
+/*
+ * PFE/GPI initialization function.
+ * - egpi1, egpi2, egpi3, hgpi
+ */
+static void pfe_gpi_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct gpi_cfg egpi1_cfg = {
+ .lmem_rtry_cnt = EGPI1_LMEM_RTRY_CNT,
+ .tmlf_txthres = EGPI1_TMLF_TXTHRES,
+ .aseq_len = EGPI1_ASEQ_LEN,
+ };
+
+ struct gpi_cfg egpi2_cfg = {
+ .lmem_rtry_cnt = EGPI2_LMEM_RTRY_CNT,
+ .tmlf_txthres = EGPI2_TMLF_TXTHRES,
+ .aseq_len = EGPI2_ASEQ_LEN,
+ };
+
+ struct gpi_cfg hgpi_cfg = {
+ .lmem_rtry_cnt = HGPI_LMEM_RTRY_CNT,
+ .tmlf_txthres = HGPI_TMLF_TXTHRES,
+ .aseq_len = HGPI_ASEQ_LEN,
+ };
+
+ gpi_init(EGPI1_BASE_ADDR, &egpi1_cfg);
+ debug("GPI1 init complete\n");
+
+ gpi_init(EGPI2_BASE_ADDR, &egpi2_cfg);
+ debug("GPI2 init complete\n");
+
+ gpi_init(HGPI_BASE_ADDR, &hgpi_cfg);
+ debug("HGPI init complete\n");
+}
+
+/*
+ * PFE/HIF initialization function.
+ */
+static int pfe_hif_init(struct pfe_ddr_address *pfe_addr)
+{
+ int ret = 0;
+
+ hif_tx_disable();
+ hif_rx_disable();
+
+ ret = hif_tx_desc_init(pfe_addr);
+ if (ret)
+ return ret;
+ ret = hif_rx_desc_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ hif_init();
+
+ hif_tx_enable();
+ hif_rx_enable();
+
+ hif_rx_desc_dump();
+ hif_tx_desc_dump();
+
+ debug("HIF init complete\n");
+ return ret;
+}
+
+/*
+ * PFE initialization
+ * - Firmware loading (CLASS-PE and TMU-PE)
+ * - BMU1 and BMU2 init
+ * - GEMAC init
+ * - GPI init
+ * - CLASS-PE init
+ * - TMU-PE init
+ * - HIF tx and rx descriptors init
+ *
+ * @param[in] edev Pointer to eth device structure.
+ *
+ * @return 0, on success.
+ */
+static int pfe_hw_init(struct pfe_ddr_address *pfe_addr)
+{
+ int ret = 0;
+
+ debug("%s: start\n", __func__);
+
+ writel(0x3, CLASS_PE_SYS_CLK_RATIO);
+ writel(0x3, TMU_PE_SYS_CLK_RATIO);
+ writel(0x3, UTIL_PE_SYS_CLK_RATIO);
+ udelay(10);
+
+ pfe_class_init(pfe_addr);
+
+ pfe_tmu_init(pfe_addr);
+
+ pfe_bmu_init(pfe_addr);
+
+ pfe_gpi_init(pfe_addr);
+
+ ret = pfe_hif_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ bmu_enable(BMU1_BASE_ADDR);
+ debug("bmu1 enabled\n");
+
+ bmu_enable(BMU2_BASE_ADDR);
+ debug("bmu2 enabled\n");
+
+ debug("%s: done\n", __func__);
+
+ return ret;
+}
+
+/*
+ * PFE driver init function.
+ * - Initializes pfe_lib
+ * - pfe hw init
+ * - fw loading and enables PEs
+ * - should be executed once.
+ *
+ * @param[in] pfe Pointer the pfe control block
+ */
+int pfe_drv_init(struct pfe_ddr_address *pfe_addr)
+{
+ int ret = 0;
+
+ pfe_lib_init();
+
+ ret = pfe_hw_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ /* Load the class,TM, Util fw.
+ * By now pfe is:
+ * - out of reset + disabled + configured.
+ * Fw loading should be done after pfe_hw_init()
+ */
+ /* It loads default inbuilt sbl firmware */
+ pfe_firmware_init();
+
+ return ret;
+}
+
+/*
+ * PFE remove function
+ * - stops PEs
+ * - frees tx/rx descriptor resources
+ * - should be called once.
+ *
+ * @param[in] pfe Pointer to pfe control block.
+ */
+int pfe_eth_remove(struct udevice *dev)
+{
+ if (g_tx_desc)
+ free(g_tx_desc);
+
+ if (g_rx_desc)
+ free(g_rx_desc);
+
+ pfe_firmware_exit();
+
+ return 0;
+}
diff --git a/drivers/net/pfe_eth/pfe_eth.c b/drivers/net/pfe_eth/pfe_eth.c
new file mode 100644
index 0000000000..e6c6c8c9ab
--- /dev/null
+++ b/drivers/net/pfe_eth/pfe_eth.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/platform_data/pfe_dm_eth.h>
+#include <net.h>
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe_mdio.h>
+
+struct gemac_s gem_info[] = {
+ /* PORT_0 configuration */
+ {
+ /* GEMAC config */
+ .gemac_speed = PFE_MAC_SPEED_1000M,
+ .gemac_duplex = DUPLEX_FULL,
+
+ /* phy iface */
+ .phy_address = CONFIG_PFE_EMAC1_PHY_ADDR,
+ .phy_mode = PHY_INTERFACE_MODE_SGMII,
+ },
+ /* PORT_1 configuration */
+ {
+ /* GEMAC config */
+ .gemac_speed = PFE_MAC_SPEED_1000M,
+ .gemac_duplex = DUPLEX_FULL,
+
+ /* phy iface */
+ .phy_address = CONFIG_PFE_EMAC2_PHY_ADDR,
+ .phy_mode = PHY_INTERFACE_MODE_RGMII_TXID,
+ },
+};
+
+static inline void pfe_gemac_enable(void *gemac_base)
+{
+ writel(readl(gemac_base + EMAC_ECNTRL_REG) |
+ EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
+}
+
+static inline void pfe_gemac_disable(void *gemac_base)
+{
+ writel(readl(gemac_base + EMAC_ECNTRL_REG) &
+ ~EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
+}
+
+static inline void pfe_gemac_set_speed(void *gemac_base, u32 speed)
+{
+ struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
+ u32 ecr = readl(gemac_base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_SPEED;
+ u32 rcr = readl(gemac_base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_RMII_10T;
+ u32 rgmii_pcr = in_be32(&scfg->rgmiipcr) &
+ ~(SCFG_RGMIIPCR_SETSP_1000M | SCFG_RGMIIPCR_SETSP_10M);
+
+ if (speed == _1000BASET) {
+ ecr |= EMAC_ECNTRL_SPEED;
+ rgmii_pcr |= SCFG_RGMIIPCR_SETSP_1000M;
+ } else if (speed != _100BASET) {
+ rcr |= EMAC_RCNTRL_RMII_10T;
+ rgmii_pcr |= SCFG_RGMIIPCR_SETSP_10M;
+ }
+
+ writel(ecr, gemac_base + EMAC_ECNTRL_REG);
+ out_be32(&scfg->rgmiipcr, rgmii_pcr | SCFG_RGMIIPCR_SETFD);
+
+ /* remove loop back */
+ rcr &= ~EMAC_RCNTRL_LOOP;
+ /* enable flow control */
+ rcr |= EMAC_RCNTRL_FCE;
+
+ /* Enable MII mode */
+ rcr |= EMAC_RCNTRL_MII_MODE;
+
+ writel(rcr, gemac_base + EMAC_RCNTRL_REG);
+
+ /* Enable Tx full duplex */
+ writel(readl(gemac_base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_FDEN,
+ gemac_base + EMAC_TCNTRL_REG);
+}
+
+static int pfe_eth_write_hwaddr(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ struct gemac_s *gem = priv->gem;
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ uchar *mac = pdata->enetaddr;
+
+ writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
+ gem->gemac_base + EMAC_PHY_ADDR_LOW);
+ writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, gem->gemac_base +
+ EMAC_PHY_ADDR_HIGH);
+ return 0;
+}
+
+/** Stops or Disables GEMAC pointing to this eth iface.
+ *
+ * @param[in] edev Pointer to eth device structure.
+ *
+ * @return none
+ */
+static inline void pfe_eth_stop(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+
+ pfe_gemac_disable(priv->gem->gemac_base);
+
+ gpi_disable(priv->gem->egpi_base);
+}
+
+static int pfe_eth_start(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ struct gemac_s *gem = priv->gem;
+ int speed;
+
+ /* set ethernet mac address */
+ pfe_eth_write_hwaddr(dev);
+
+ writel(EMAC_TFWR, gem->gemac_base + EMAC_TFWR_STR_FWD);
+ writel(EMAC_RX_SECTION_FULL_32, gem->gemac_base + EMAC_RX_SECTIOM_FULL);
+ writel(EMAC_TRUNC_FL_16K, gem->gemac_base + EMAC_TRUNC_FL);
+ writel(EMAC_TX_SECTION_EMPTY_30, gem->gemac_base
+ + EMAC_TX_SECTION_EMPTY);
+ writel(EMAC_MIBC_NO_CLR_NO_DIS, gem->gemac_base
+ + EMAC_MIB_CTRL_STS_REG);
+
+#ifdef CONFIG_PHYLIB
+ /* Start up the PHY */
+ if (phy_startup(priv->phydev)) {
+ printf("Could not initialize PHY %s\n",
+ priv->phydev->dev->name);
+ return -1;
+ }
+ speed = priv->phydev->speed;
+ printf("Speed detected %x\n", speed);
+ if (priv->phydev->duplex == DUPLEX_HALF) {
+ printf("Half duplex not supported\n");
+ return -1;
+ }
+#endif
+
+ pfe_gemac_set_speed(gem->gemac_base, speed);
+
+ /* Enable GPI */
+ gpi_enable(gem->egpi_base);
+
+ /* Enable GEMAC */
+ pfe_gemac_enable(gem->gemac_base);
+
+ return 0;
+}
+
+static int pfe_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct pfe_eth_dev *priv = (struct pfe_eth_dev *)dev->priv;
+
+ int rc;
+ int i = 0;
+
+ rc = pfe_send(priv->gemac_port, packet, length);
+
+ if (rc < 0) {
+ printf("Tx Queue full\n");
+ return rc;
+ }
+
+ while (1) {
+ rc = pfe_tx_done();
+ if (rc == 0)
+ break;
+
+ udelay(100);
+ i++;
+ if (i == 30000)
+ printf("Tx timeout, send failed\n");
+ break;
+ }
+
+ return 0;
+}
+
+static int pfe_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ uchar *pkt_buf;
+ int len;
+ int phy_port;
+
+ len = pfe_recv(&pkt_buf, &phy_port);
+
+ if (len == 0)
+ return -EAGAIN; /* no packet in rx */
+ else if (len < 0)
+ return -EAGAIN;
+
+ debug("Rx pkt: pkt_buf(0x%p), phy_port(%d), len(%d)\n", pkt_buf,
+ phy_port, len);
+ if (phy_port != priv->gemac_port) {
+ printf("Rx pkt not on expected port\n");
+ return -EAGAIN;
+ }
+
+ *packetp = pkt_buf;
+
+ return len;
+}
+
+static int pfe_eth_probe(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ struct pfe_ddr_address *pfe_addr;
+ struct pfe_eth_pdata *pdata = dev_get_platdata(dev);
+ int ret = 0;
+ static int init_done;
+
+ if (!init_done) {
+ pfe_addr = (struct pfe_ddr_address *)malloc(sizeof
+ (struct pfe_ddr_address));
+ if (!pfe_addr)
+ return -ENOMEM;
+
+ pfe_addr->ddr_pfe_baseaddr =
+ (void *)pdata->pfe_ddr_addr.ddr_pfe_baseaddr;
+ pfe_addr->ddr_pfe_phys_baseaddr =
+ (unsigned long)pdata->pfe_ddr_addr.ddr_pfe_phys_baseaddr;
+
+ debug("ddr_pfe_baseaddr: %p, ddr_pfe_phys_baseaddr: %08x\n",
+ pfe_addr->ddr_pfe_baseaddr,
+ (u32)pfe_addr->ddr_pfe_phys_baseaddr);
+
+ ret = pfe_drv_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ init_pfe_scfg_dcfg_regs();
+ init_done = 1;
+ }
+
+ priv->gemac_port = pdata->pfe_eth_pdata_mac.phy_interface;
+ priv->gem = &gem_info[priv->gemac_port];
+ priv->dev = dev;
+
+ switch (priv->gemac_port) {
+ case EMAC_PORT_0:
+ default:
+ priv->gem->gemac_base = EMAC1_BASE_ADDR;
+ priv->gem->egpi_base = EGPI1_BASE_ADDR;
+ break;
+ case EMAC_PORT_1:
+ priv->gem->gemac_base = EMAC2_BASE_ADDR;
+ priv->gem->egpi_base = EGPI2_BASE_ADDR;
+ break;
+ }
+
+ ret = pfe_eth_board_init(dev);
+ if (ret)
+ return ret;
+
+#if defined(CONFIG_PHYLIB)
+ ret = pfe_phy_configure(priv, pdata->pfe_eth_pdata_mac.phy_interface,
+ gem_info[priv->gemac_port].phy_address);
+#endif
+ return ret;
+}
+
+static int pfe_eth_bind(struct udevice *dev)
+{
+ struct pfe_eth_pdata *pdata = dev_get_platdata(dev);
+ char name[20];
+
+ sprintf(name, "pfe_eth%u", pdata->pfe_eth_pdata_mac.phy_interface);
+
+ return device_set_name(dev, name);
+}
+
+static const struct eth_ops pfe_eth_ops = {
+ .start = pfe_eth_start,
+ .send = pfe_eth_send,
+ .recv = pfe_eth_recv,
+ .free_pkt = pfe_eth_free_pkt,
+ .stop = pfe_eth_stop,
+ .write_hwaddr = pfe_eth_write_hwaddr,
+};
+
+U_BOOT_DRIVER(pfe_eth) = {
+ .name = "pfe_eth",
+ .id = UCLASS_ETH,
+ .bind = pfe_eth_bind,
+ .probe = pfe_eth_probe,
+ .remove = pfe_eth_remove,
+ .ops = &pfe_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct pfe_eth_dev),
+ .platdata_auto_alloc_size = sizeof(struct pfe_eth_pdata)
+};
diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c
new file mode 100644
index 0000000000..9dc063dc75
--- /dev/null
+++ b/drivers/net/pfe_eth/pfe_firmware.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * @file
+ * Contains all the functions to handle parsing and loading of PE firmware
+ * files.
+ */
+
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe_firmware.h>
+
+#define PFE_FIRMEWARE_FIT_CNF_NAME "config@1"
+
+static const void *pfe_fit_addr = (void *)CONFIG_SYS_LS_PFE_FW_ADDR;
+
+/*
+ * PFE elf firmware loader.
+ * Loads an elf firmware image into a list of PE's (specified using a bitmask)
+ *
+ * @param pe_mask Mask of PE id's to load firmware to
+ * @param pfe_firmware Pointer to the firmware image
+ *
+ * @return 0 on success, a negative value on error
+ */
+static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
+{
+ Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
+ Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
+ Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
+ be32_to_cpu(elf_hdr->e_shoff));
+ int id, section;
+ int ret;
+
+ debug("%s: no of sections: %d\n", __func__, sections);
+
+ /* Some sanity checks */
+ if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
+ printf("%s: incorrect elf magic number\n", __func__);
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
+ printf("%s: incorrect elf class(%x)\n", __func__,
+ elf_hdr->e_ident[EI_CLASS]);
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+ printf("%s: incorrect elf data(%x)\n", __func__,
+ elf_hdr->e_ident[EI_DATA]);
+ return -1;
+ }
+
+ if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
+ printf("%s: incorrect elf file type(%x)\n", __func__,
+ be16_to_cpu(elf_hdr->e_type));
+ return -1;
+ }
+
+ for (section = 0; section < sections; section++, shdr++) {
+ if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
+ SHF_EXECINSTR)))
+ continue;
+ for (id = 0; id < MAX_PE; id++)
+ if (pe_mask & BIT(id)) {
+ ret = pe_load_elf_section(id,
+ pfe_firmware, shdr);
+ if (ret < 0)
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ return ret;
+}
+
+/*
+ * Get PFE firmware from FIT image
+ *
+ * @param data pointer to PFE firmware
+ * @param size pointer to size of the firmware
+ * @param fw_name pfe firmware name, either class or tmu
+ *
+ * @return 0 on success, a negative value on error
+ */
+static int pfe_get_fw(const void **data,
+ size_t *size, char *fw_name)
+{
+ int conf_node_off, fw_node_off;
+ char *conf_node_name = NULL;
+ char *desc;
+ int ret = 0;
+
+ conf_node_name = PFE_FIRMEWARE_FIT_CNF_NAME;
+
+ conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name);
+ if (conf_node_off < 0) {
+ printf("PFE Firmware: %s: no such config\n", conf_node_name);
+ return -ENOENT;
+ }
+
+ fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off,
+ fw_name);
+ if (fw_node_off < 0) {
+ printf("PFE Firmware: No '%s' in config\n",
+ fw_name);
+ return -ENOLINK;
+ }
+
+ if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) {
+ printf("PFE Firmware: Bad firmware image (bad CRC)\n");
+ return -EINVAL;
+ }
+
+ if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) {
+ printf("PFE Firmware: Can't get %s subimage data/size",
+ fw_name);
+ return -ENOENT;
+ }
+
+ ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc);
+ if (ret)
+ printf("PFE Firmware: Can't get description\n");
+ else
+ printf("%s\n", desc);
+
+ return ret;
+}
+
+/*
+ * Check PFE FIT image
+ *
+ * @return 0 on success, a negative value on error
+ */
+static int pfe_fit_check(void)
+{
+ int ret = 0;
+
+ ret = fdt_check_header(pfe_fit_addr);
+ if (ret) {
+ printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
+ return ret;
+ }
+
+ if (!fit_check_format(pfe_fit_addr)) {
+ printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
+ ret = -1;
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * PFE firmware initialization.
+ * Loads different firmware files from FIT image.
+ * Initializes PE IMEM/DMEM and UTIL-PE DDR
+ * Initializes control path symbol addresses (by looking them up in the elf
+ * firmware files
+ * Takes PE's out of reset
+ *
+ * @return 0 on success, a negative value on error
+ */
+int pfe_firmware_init(void)
+{
+ char *pfe_firmware_name;
+ const void *raw_image_addr;
+ size_t raw_image_size = 0;
+ u8 *pfe_firmware;
+ int ret = 0;
+ int fw_count;
+
+ ret = pfe_fit_check();
+ if (ret)
+ goto err;
+
+ for (fw_count = 0; fw_count < 2; fw_count++) {
+ if (fw_count == 0)
+ pfe_firmware_name = "class";
+ else if (fw_count == 1)
+ pfe_firmware_name = "tmu";
+
+ pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
+ pfe_firmware = malloc(raw_image_size);
+ if (!pfe_firmware)
+ return -ENOMEM;
+ memcpy((void *)pfe_firmware, (void *)raw_image_addr,
+ raw_image_size);
+
+ if (fw_count == 0)
+ ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
+ else if (fw_count == 1)
+ ret = pfe_load_elf(TMU_MASK, pfe_firmware);
+
+ if (ret < 0) {
+ printf("%s: %s firmware load failed\n", __func__,
+ pfe_firmware_name);
+ goto err;
+ }
+ debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
+ free(pfe_firmware);
+ }
+
+ tmu_enable(0xb);
+ class_enable();
+ gpi_enable(HGPI_BASE_ADDR);
+
+err:
+ return ret;
+}
+
+/*
+ * PFE firmware cleanup
+ * Puts PE's in reset
+ */
+void pfe_firmware_exit(void)
+{
+ debug("%s\n", __func__);
+
+ class_disable();
+ tmu_disable(0xf);
+ hif_tx_disable();
+ hif_rx_disable();
+}
diff --git a/drivers/net/pfe_eth/pfe_hw.c b/drivers/net/pfe_eth/pfe_hw.c
new file mode 100644
index 0000000000..12bb0da9b9
--- /dev/null
+++ b/drivers/net/pfe_eth/pfe_hw.c
@@ -0,0 +1,999 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:GPL-2.0+
+ */
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe/pfe_hw.h>
+
+static struct pe_info pe[MAX_PE];
+
+/*
+ * Initializes the PFE library.
+ * Must be called before using any of the library functions.
+ */
+void pfe_lib_init(void)
+{
+ int pfe_pe_id;
+
+ for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
+ pe[pfe_pe_id].dmem_base_addr =
+ (u32)CLASS_DMEM_BASE_ADDR(pfe_pe_id);
+ pe[pfe_pe_id].pmem_base_addr =
+ (u32)CLASS_IMEM_BASE_ADDR(pfe_pe_id);
+ pe[pfe_pe_id].pmem_size = (u32)CLASS_IMEM_SIZE;
+ pe[pfe_pe_id].mem_access_wdata =
+ (void *)CLASS_MEM_ACCESS_WDATA;
+ pe[pfe_pe_id].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
+ pe[pfe_pe_id].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
+ }
+
+ for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
+ if (pfe_pe_id == TMU2_ID)
+ continue;
+ pe[pfe_pe_id].dmem_base_addr =
+ (u32)TMU_DMEM_BASE_ADDR(pfe_pe_id - TMU0_ID);
+ pe[pfe_pe_id].pmem_base_addr =
+ (u32)TMU_IMEM_BASE_ADDR(pfe_pe_id - TMU0_ID);
+ pe[pfe_pe_id].pmem_size = (u32)TMU_IMEM_SIZE;
+ pe[pfe_pe_id].mem_access_wdata = (void *)TMU_MEM_ACCESS_WDATA;
+ pe[pfe_pe_id].mem_access_addr = (void *)TMU_MEM_ACCESS_ADDR;
+ pe[pfe_pe_id].mem_access_rdata = (void *)TMU_MEM_ACCESS_RDATA;
+ }
+}
+
+/*
+ * Writes a buffer to PE internal memory from the host
+ * through indirect access registers.
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] mem_access_addr DMEM destination address (must be 32bit
+ * aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void pe_mem_memcpy_to32(int id, u32 mem_access_addr, const void *src,
+ unsigned int len)
+{
+ u32 offset = 0, val, addr;
+ unsigned int len32 = len >> 2;
+ int i;
+
+ addr = mem_access_addr | PE_MEM_ACCESS_WRITE |
+ PE_MEM_ACCESS_BYTE_ENABLE(0, 4);
+
+ for (i = 0; i < len32; i++, offset += 4, src += 4) {
+ val = *(u32 *)src;
+ writel(cpu_to_be32(val), pe[id].mem_access_wdata);
+ writel(addr + offset, pe[id].mem_access_addr);
+ }
+
+ len = (len & 0x3);
+ if (len) {
+ val = 0;
+
+ addr = (mem_access_addr | PE_MEM_ACCESS_WRITE |
+ PE_MEM_ACCESS_BYTE_ENABLE(0, len)) + offset;
+
+ for (i = 0; i < len; i++, src++)
+ val |= (*(u8 *)src) << (8 * i);
+
+ writel(cpu_to_be32(val), pe[id].mem_access_wdata);
+ writel(addr, pe[id].mem_access_addr);
+ }
+}
+
+/*
+ * Writes a buffer to PE internal data memory (DMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] dst DMEM destination address (must be 32bit
+ * aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void pe_dmem_memcpy_to32(int id, u32 dst, const void *src,
+ unsigned int len)
+{
+ pe_mem_memcpy_to32(id, pe[id].dmem_base_addr | dst | PE_MEM_ACCESS_DMEM,
+ src, len);
+}
+
+/*
+ * Writes a buffer to PE internal program memory (PMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., TMU3_ID)
+ * @param[in] dst PMEM destination address (must be 32bit
+ * aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void pe_pmem_memcpy_to32(int id, u32 dst, const void *src,
+ unsigned int len)
+{
+ pe_mem_memcpy_to32(id, pe[id].pmem_base_addr | (dst & (pe[id].pmem_size
+ - 1)) | PE_MEM_ACCESS_IMEM, src, len);
+}
+
+/*
+ * Reads PE internal program memory (IMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., TMU3_ID)
+ * @param[in] addr PMEM read address (must be aligned on size)
+ * @param[in] size Number of bytes to read (maximum 4, must not
+ * cross 32bit boundaries)
+ * @return the data read (in PE endianness, i.e BE).
+ */
+u32 pe_pmem_read(int id, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+ u32 mask = 0xffffffff >> ((4 - size) << 3);
+ u32 val;
+
+ addr = pe[id].pmem_base_addr | ((addr & ~0x3) & (pe[id].pmem_size - 1))
+ | PE_MEM_ACCESS_READ | PE_MEM_ACCESS_IMEM |
+ PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
+
+ writel(addr, pe[id].mem_access_addr);
+ val = be32_to_cpu(readl(pe[id].mem_access_rdata));
+
+ return (val >> (offset << 3)) & mask;
+}
+
+/*
+ * Writes PE internal data memory (DMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] val Value to write (in PE endianness, i.e BE)
+ * @param[in] addr DMEM write address (must be aligned on size)
+ * @param[in] size Number of bytes to write (maximum 4, must not
+ * cross 32bit boundaries)
+ */
+void pe_dmem_write(int id, u32 val, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+
+ addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_WRITE |
+ PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
+
+ /* Indirect access interface is byte swapping data being written */
+ writel(cpu_to_be32(val << (offset << 3)), pe[id].mem_access_wdata);
+ writel(addr, pe[id].mem_access_addr);
+}
+
+/*
+ * Reads PE internal data memory (DMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] addr DMEM read address (must be aligned on size)
+ * @param[in] size Number of bytes to read (maximum 4, must not
+ * cross 32bit boundaries)
+ * @return the data read (in PE endianness, i.e BE).
+ */
+u32 pe_dmem_read(int id, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+ u32 mask = 0xffffffff >> ((4 - size) << 3);
+ u32 val;
+
+ addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_READ |
+ PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
+
+ writel(addr, pe[id].mem_access_addr);
+
+ /* Indirect access interface is byte swapping data being read */
+ val = be32_to_cpu(readl(pe[id].mem_access_rdata));
+
+ return (val >> (offset << 3)) & mask;
+}
+
+/*
+ * This function is used to write to CLASS internal bus peripherals (ccu,
+ * pe-lem) from the host
+ * through indirect access registers.
+ * @param[in] val value to write
+ * @param[in] addr Address to write to (must be aligned on size)
+ * @param[in] size Number of bytes to write (1, 2 or 4)
+ *
+ */
+static void class_bus_write(u32 val, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+
+ writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
+
+ addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | PE_MEM_ACCESS_WRITE |
+ (size << 24);
+
+ writel(cpu_to_be32(val << (offset << 3)), CLASS_BUS_ACCESS_WDATA);
+ writel(addr, CLASS_BUS_ACCESS_ADDR);
+}
+
+/*
+ * Reads from CLASS internal bus peripherals (ccu, pe-lem) from the host
+ * through indirect access registers.
+ * @param[in] addr Address to read from (must be aligned on size)
+ * @param[in] size Number of bytes to read (1, 2 or 4)
+ * @return the read data
+ */
+static u32 class_bus_read(u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+ u32 mask = 0xffffffff >> ((4 - size) << 3);
+ u32 val;
+
+ writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
+
+ addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | (size << 24);
+
+ writel(addr, CLASS_BUS_ACCESS_ADDR);
+ val = be32_to_cpu(readl(CLASS_BUS_ACCESS_RDATA));
+
+ return (val >> (offset << 3)) & mask;
+}
+
+/*
+ * Writes data to the cluster memory (PE_LMEM)
+ * @param[in] dst PE LMEM destination address (must be 32bit aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void class_pe_lmem_memcpy_to32(u32 dst, const void *src,
+ unsigned int len)
+{
+ u32 len32 = len >> 2;
+ int i;
+
+ for (i = 0; i < len32; i++, src += 4, dst += 4)
+ class_bus_write(*(u32 *)src, dst, 4);
+
+ if (len & 0x2) {
+ class_bus_write(*(u16 *)src, dst, 2);
+ src += 2;
+ dst += 2;
+ }
+
+ if (len & 0x1) {
+ class_bus_write(*(u8 *)src, dst, 1);
+ src++;
+ dst++;
+ }
+}
+
+/*
+ * Writes value to the cluster memory (PE_LMEM)
+ * @param[in] dst PE LMEM destination address (must be 32bit aligned)
+ * @param[in] val Value to write
+ * @param[in] len Number of bytes to write
+ */
+static void class_pe_lmem_memset(u32 dst, int val, unsigned int len)
+{
+ u32 len32 = len >> 2;
+ int i;
+
+ val = val | (val << 8) | (val << 16) | (val << 24);
+
+ for (i = 0; i < len32; i++, dst += 4)
+ class_bus_write(val, dst, 4);
+
+ if (len & 0x2) {
+ class_bus_write(val, dst, 2);
+ dst += 2;
+ }
+
+ if (len & 0x1) {
+ class_bus_write(val, dst, 1);
+ dst++;
+ }
+}
+
+/*
+ * Reads data from the cluster memory (PE_LMEM)
+ * @param[out] dst pointer to the source buffer data are copied to
+ * @param[in] len length in bytes of the amount of data to read
+ * from cluster memory
+ * @param[in] offset offset in bytes in the cluster memory where data are
+ * read from
+ */
+void pe_lmem_read(u32 *dst, u32 len, u32 offset)
+{
+ u32 len32 = len >> 2;
+ int i = 0;
+
+ for (i = 0; i < len32; dst++, i++, offset += 4)
+ *dst = class_bus_read(PE_LMEM_BASE_ADDR + offset, 4);
+
+ if (len & 0x03)
+ *dst = class_bus_read(PE_LMEM_BASE_ADDR + offset, (len & 0x03));
+}
+
+/*
+ * Writes data to the cluster memory (PE_LMEM)
+ * @param[in] src pointer to the source buffer data are copied from
+ * @param[in] len length in bytes of the amount of data to write to the
+ * cluster memory
+ * @param[in] offset offset in bytes in the cluster memory where data are
+ * written to
+ */
+void pe_lmem_write(u32 *src, u32 len, u32 offset)
+{
+ u32 len32 = len >> 2;
+ int i = 0;
+
+ for (i = 0; i < len32; src++, i++, offset += 4)
+ class_bus_write(*src, PE_LMEM_BASE_ADDR + offset, 4);
+
+ if (len & 0x03)
+ class_bus_write(*src, PE_LMEM_BASE_ADDR + offset, (len &
+ 0x03));
+}
+
+/*
+ * Loads an elf section into pmem
+ * Code needs to be at least 16bit aligned and only PROGBITS sections are
+ * supported
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID, ...,
+ * TMU3_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_pmem_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+
+ if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr, (unsigned long)data + offset);
+
+ return -1;
+ }
+
+ if (addr & 0x1) {
+ printf("%s: load address(%x) is not 16bit aligned\n",
+ __func__, addr);
+ return -1;
+ }
+
+ if (size & 0x1) {
+ printf("%s: load size(%x) is not 16bit aligned\n", __func__,
+ size);
+ return -1;
+ }
+
+ debug("pmem pe%d @%x len %d\n", id, addr, size);
+ switch (type) {
+ case SHT_PROGBITS:
+ pe_pmem_memcpy_to32(id, addr, data + offset, size);
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into dmem
+ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
+ * initialized to 0
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_dmem_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+ u32 size32 = size >> 2;
+ int i;
+
+ if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr, (unsigned long)data + offset);
+
+ return -1;
+ }
+
+ if (addr & 0x3) {
+ printf("%s: load address(%x) is not 32bit aligned\n",
+ __func__, addr);
+ return -1;
+ }
+
+ switch (type) {
+ case SHT_PROGBITS:
+ debug("dmem pe%d @%x len %d\n", id, addr, size);
+ pe_dmem_memcpy_to32(id, addr, data + offset, size);
+ break;
+
+ case SHT_NOBITS:
+ debug("dmem zero pe%d @%x len %d\n", id, addr, size);
+ for (i = 0; i < size32; i++, addr += 4)
+ pe_dmem_write(id, 0, addr, 4);
+
+ if (size & 0x3)
+ pe_dmem_write(id, 0, addr, size & 0x3);
+
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into DDR
+ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
+ * initialized to 0
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_ddr_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+ u32 flags = be32_to_cpu(shdr->sh_flags);
+
+ switch (type) {
+ case SHT_PROGBITS:
+ debug("ddr pe%d @%x len %d\n", id, addr, size);
+ if (flags & SHF_EXECINSTR) {
+ if (id <= CLASS_MAX_ID) {
+ /* DO the loading only once in DDR */
+ if (id == CLASS0_ID) {
+ debug(
+ "%s: load address(%x) and elf file address(%lx) rcvd\n"
+ , __func__, addr,
+ (unsigned long)data + offset);
+ if (((unsigned long)(data + offset)
+ & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr,
+ (unsigned long)data +
+ offset);
+
+ return -1;
+ }
+
+ if (addr & 0x1) {
+ printf(
+ "%s: load address(%x) is not 16bit aligned\n"
+ , __func__, addr);
+ return -1;
+ }
+
+ if (size & 0x1) {
+ printf(
+ "%s: load length(%x) is not 16bit aligned\n"
+ , __func__, size);
+ return -1;
+ }
+
+ memcpy((void *)DDR_PFE_TO_VIRT(addr),
+ data + offset, size);
+ }
+ } else {
+ printf(
+ "%s: unsupported ddr section type(%x) for PE(%d)\n"
+ , __func__, type, id);
+ return -1;
+ }
+
+ } else {
+ memcpy((void *)DDR_PFE_TO_VIRT(addr), data + offset,
+ size);
+ }
+
+ break;
+
+ case SHT_NOBITS:
+ debug("ddr zero pe%d @%x len %d\n", id, addr, size);
+ memset((void *)DDR_PFE_TO_VIRT(addr), 0, size);
+
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into pe lmem
+ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
+ * initialized to 0
+ *
+ * @param[in] id PE identification (CLASS0_ID,..., CLASS5_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_pe_lmem_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+
+ if (id > CLASS_MAX_ID) {
+ printf("%s: unsupported pe-lmem section type(%x) for PE(%d)\n",
+ __func__, type, id);
+ return -1;
+ }
+
+ if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr, (unsigned long)data + offset);
+
+ return -1;
+ }
+
+ if (addr & 0x3) {
+ printf("%s: load address(%x) is not 32bit aligned\n",
+ __func__, addr);
+ return -1;
+ }
+
+ debug("lmem pe%d @%x len %d\n", id, addr, size);
+
+ switch (type) {
+ case SHT_PROGBITS:
+ class_pe_lmem_memcpy_to32(addr, data + offset, size);
+ break;
+
+ case SHT_NOBITS:
+ class_pe_lmem_memset(addr, 0, size);
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into a PE
+ * For now only supports loading a section to dmem (all PE's), pmem (class and
+ * tmu PE's), DDDR (util PE code)
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+int pe_load_elf_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+
+ if (IS_DMEM(addr, size))
+ return pe_load_dmem_section(id, data, shdr);
+ else if (IS_PMEM(addr, size))
+ return pe_load_pmem_section(id, data, shdr);
+ else if (IS_PFE_LMEM(addr, size))
+ return 0;
+ else if (IS_PHYS_DDR(addr, size))
+ return pe_load_ddr_section(id, data, shdr);
+ else if (IS_PE_LMEM(addr, size))
+ return pe_load_pe_lmem_section(id, data, shdr);
+
+ printf("%s: unsupported memory range(%x)\n", __func__, addr);
+
+ return 0;
+}
+
+/**************************** BMU ***************************/
+/*
+ * Resets a BMU block.
+ * @param[in] base BMU block base address
+ */
+static inline void bmu_reset(void *base)
+{
+ writel(CORE_SW_RESET, base + BMU_CTRL);
+
+ /* Wait for self clear */
+ while (readl(base + BMU_CTRL) & CORE_SW_RESET)
+ ;
+}
+
+/*
+ * Enabled a BMU block.
+ * @param[in] base BMU block base address
+ */
+void bmu_enable(void *base)
+{
+ writel(CORE_ENABLE, base + BMU_CTRL);
+}
+
+/*
+ * Disables a BMU block.
+ * @param[in] base BMU block base address
+ */
+static inline void bmu_disable(void *base)
+{
+ writel(CORE_DISABLE, base + BMU_CTRL);
+}
+
+/*
+ * Sets the configuration of a BMU block.
+ * @param[in] base BMU block base address
+ * @param[in] cfg BMU configuration
+ */
+static inline void bmu_set_config(void *base, struct bmu_cfg *cfg)
+{
+ writel(cfg->baseaddr, base + BMU_UCAST_BASE_ADDR);
+ writel(cfg->count & 0xffff, base + BMU_UCAST_CONFIG);
+ writel(cfg->size & 0xffff, base + BMU_BUF_SIZE);
+
+ /* Interrupts are never used */
+ writel(0x0, base + BMU_INT_ENABLE);
+}
+
+/*
+ * Initializes a BMU block.
+ * @param[in] base BMU block base address
+ * @param[in] cfg BMU configuration
+ */
+void bmu_init(void *base, struct bmu_cfg *cfg)
+{
+ bmu_disable(base);
+
+ bmu_set_config(base, cfg);
+
+ bmu_reset(base);
+}
+
+/**************************** GPI ***************************/
+/*
+ * Resets a GPI block.
+ * @param[in] base GPI base address
+ */
+static inline void gpi_reset(void *base)
+{
+ writel(CORE_SW_RESET, base + GPI_CTRL);
+}
+
+/*
+ * Enables a GPI block.
+ * @param[in] base GPI base address
+ */
+void gpi_enable(void *base)
+{
+ writel(CORE_ENABLE, base + GPI_CTRL);
+}
+
+/*
+ * Disables a GPI block.
+ * @param[in] base GPI base address
+ */
+void gpi_disable(void *base)
+{
+ writel(CORE_DISABLE, base + GPI_CTRL);
+}
+
+/*
+ * Sets the configuration of a GPI block.
+ * @param[in] base GPI base address
+ * @param[in] cfg GPI configuration
+ */
+static inline void gpi_set_config(void *base, struct gpi_cfg *cfg)
+{
+ writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_ALLOC_CTRL), base
+ + GPI_LMEM_ALLOC_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_FREE_CTRL), base
+ + GPI_LMEM_FREE_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_ALLOC_CTRL), base
+ + GPI_DDR_ALLOC_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL), base
+ + GPI_DDR_FREE_ADDR);
+ writel(CBUS_VIRT_TO_PFE(CLASS_INQ_PKTPTR), base + GPI_CLASS_ADDR);
+ writel(DDR_HDR_SIZE, base + GPI_DDR_DATA_OFFSET);
+ writel(LMEM_HDR_SIZE, base + GPI_LMEM_DATA_OFFSET);
+ writel(0, base + GPI_LMEM_SEC_BUF_DATA_OFFSET);
+ writel(0, base + GPI_DDR_SEC_BUF_DATA_OFFSET);
+ writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, base + GPI_HDR_SIZE);
+ writel((DDR_BUF_SIZE << 16) | LMEM_BUF_SIZE, base + GPI_BUF_SIZE);
+
+ writel(((cfg->lmem_rtry_cnt << 16) | (GPI_DDR_BUF_EN << 1) |
+ GPI_LMEM_BUF_EN), base + GPI_RX_CONFIG);
+ writel(cfg->tmlf_txthres, base + GPI_TMLF_TX);
+ writel(cfg->aseq_len, base + GPI_DTX_ASEQ);
+
+ /*Make GPI AXI transactions non-bufferable */
+ writel(0x1, base + GPI_AXI_CTRL);
+}
+
+/*
+ * Initializes a GPI block.
+ * @param[in] base GPI base address
+ * @param[in] cfg GPI configuration
+ */
+void gpi_init(void *base, struct gpi_cfg *cfg)
+{
+ gpi_reset(base);
+
+ gpi_disable(base);
+
+ gpi_set_config(base, cfg);
+}
+
+/**************************** CLASSIFIER ***************************/
+/*
+ * Resets CLASSIFIER block.
+ */
+static inline void class_reset(void)
+{
+ writel(CORE_SW_RESET, CLASS_TX_CTRL);
+}
+
+/*
+ * Enables all CLASS-PE's cores.
+ */
+void class_enable(void)
+{
+ writel(CORE_ENABLE, CLASS_TX_CTRL);
+}
+
+/*
+ * Disables all CLASS-PE's cores.
+ */
+void class_disable(void)
+{
+ writel(CORE_DISABLE, CLASS_TX_CTRL);
+}
+
+/*
+ * Sets the configuration of the CLASSIFIER block.
+ * @param[in] cfg CLASSIFIER configuration
+ */
+static inline void class_set_config(struct class_cfg *cfg)
+{
+ if (PLL_CLK_EN == 0) {
+ /* Clock ratio: for 1:1 the value is 0 */
+ writel(0x0, CLASS_PE_SYS_CLK_RATIO);
+ } else {
+ /* Clock ratio: for 1:2 the value is 1 */
+ writel(0x1, CLASS_PE_SYS_CLK_RATIO);
+ }
+ writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, CLASS_HDR_SIZE);
+ writel(LMEM_BUF_SIZE, CLASS_LMEM_BUF_SIZE);
+ writel(CLASS_ROUTE_ENTRY_SIZE(CLASS_ROUTE_SIZE) |
+ CLASS_ROUTE_HASH_SIZE(cfg->route_table_hash_bits),
+ CLASS_ROUTE_HASH_ENTRY_SIZE);
+ writel(HASH_CRC_PORT_IP | QB2BUS_LE, CLASS_ROUTE_MULTI);
+
+ writel(cfg->route_table_baseaddr, CLASS_ROUTE_TABLE_BASE);
+ memset((void *)DDR_PFE_TO_VIRT(cfg->route_table_baseaddr), 0,
+ ROUTE_TABLE_SIZE);
+
+ writel(CLASS_PE0_RO_DM_ADDR0_VAL, CLASS_PE0_RO_DM_ADDR0);
+ writel(CLASS_PE0_RO_DM_ADDR1_VAL, CLASS_PE0_RO_DM_ADDR1);
+ writel(CLASS_PE0_QB_DM_ADDR0_VAL, CLASS_PE0_QB_DM_ADDR0);
+ writel(CLASS_PE0_QB_DM_ADDR1_VAL, CLASS_PE0_QB_DM_ADDR1);
+ writel(CBUS_VIRT_TO_PFE(TMU_PHY_INQ_PKTPTR), CLASS_TM_INQ_ADDR);
+
+ writel(23, CLASS_AFULL_THRES);
+ writel(23, CLASS_TSQ_FIFO_THRES);
+
+ writel(24, CLASS_MAX_BUF_CNT);
+ writel(24, CLASS_TSQ_MAX_CNT);
+
+ /*Make Class AXI transactions non-bufferable */
+ writel(0x1, CLASS_AXI_CTRL);
+
+ /*Make Util AXI transactions non-bufferable */
+ /*Util is disabled in U-boot, do it from here */
+ writel(0x1, UTIL_AXI_CTRL);
+}
+
+/*
+ * Initializes CLASSIFIER block.
+ * @param[in] cfg CLASSIFIER configuration
+ */
+void class_init(struct class_cfg *cfg)
+{
+ class_reset();
+
+ class_disable();
+
+ class_set_config(cfg);
+}
+
+/**************************** TMU ***************************/
+/*
+ * Enables TMU-PE cores.
+ * @param[in] pe_mask TMU PE mask
+ */
+void tmu_enable(u32 pe_mask)
+{
+ writel(readl(TMU_TX_CTRL) | (pe_mask & 0xF), TMU_TX_CTRL);
+}
+
+/*
+ * Disables TMU cores.
+ * @param[in] pe_mask TMU PE mask
+ */
+void tmu_disable(u32 pe_mask)
+{
+ writel(readl(TMU_TX_CTRL) & ~(pe_mask & 0xF), TMU_TX_CTRL);
+}
+
+/*
+ * Initializes TMU block.
+ * @param[in] cfg TMU configuration
+ */
+void tmu_init(struct tmu_cfg *cfg)
+{
+ int q, phyno;
+
+ /* keep in soft reset */
+ writel(SW_RESET, TMU_CTRL);
+
+ /*Make Class AXI transactions non-bufferable */
+ writel(0x1, TMU_AXI_CTRL);
+
+ /* enable EMAC PHY ports */
+ writel(0x3, TMU_SYS_GENERIC_CONTROL);
+
+ writel(750, TMU_INQ_WATERMARK);
+
+ writel(CBUS_VIRT_TO_PFE(EGPI1_BASE_ADDR + GPI_INQ_PKTPTR),
+ TMU_PHY0_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(EGPI2_BASE_ADDR + GPI_INQ_PKTPTR),
+ TMU_PHY1_INQ_ADDR);
+
+ writel(CBUS_VIRT_TO_PFE(HGPI_BASE_ADDR + GPI_INQ_PKTPTR),
+ TMU_PHY3_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(HIF_NOCPY_RX_INQ0_PKTPTR), TMU_PHY4_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(UTIL_INQ_PKTPTR), TMU_PHY5_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL),
+ TMU_BMU_INQ_ADDR);
+
+ /* enabling all 10 schedulers [9:0] of each TDQ */
+ writel(0x3FF, TMU_TDQ0_SCH_CTRL);
+ writel(0x3FF, TMU_TDQ1_SCH_CTRL);
+ writel(0x3FF, TMU_TDQ3_SCH_CTRL);
+
+ if (PLL_CLK_EN == 0) {
+ /* Clock ratio: for 1:1 the value is 0 */
+ writel(0x0, TMU_PE_SYS_CLK_RATIO);
+ } else {
+ /* Clock ratio: for 1:2 the value is 1 */
+ writel(0x1, TMU_PE_SYS_CLK_RATIO);
+ }
+
+ /* Extra packet pointers will be stored from this address onwards */
+ debug("TMU_LLM_BASE_ADDR %x\n", cfg->llm_base_addr);
+ writel(cfg->llm_base_addr, TMU_LLM_BASE_ADDR);
+
+ debug("TMU_LLM_QUE_LEN %x\n", cfg->llm_queue_len);
+ writel(cfg->llm_queue_len, TMU_LLM_QUE_LEN);
+
+ writel(5, TMU_TDQ_IIFG_CFG);
+ writel(DDR_BUF_SIZE, TMU_BMU_BUF_SIZE);
+
+ writel(0x0, TMU_CTRL);
+
+ /* MEM init */
+ writel(MEM_INIT, TMU_CTRL);
+
+ while (!(readl(TMU_CTRL) & MEM_INIT_DONE))
+ ;
+
+ /* LLM init */
+ writel(LLM_INIT, TMU_CTRL);
+
+ while (!(readl(TMU_CTRL) & LLM_INIT_DONE))
+ ;
+
+ /* set up each queue for tail drop */
+ for (phyno = 0; phyno < 4; phyno++) {
+ if (phyno == 2)
+ continue;
+ for (q = 0; q < 16; q++) {
+ u32 qmax;
+
+ writel((phyno << 8) | q, TMU_TEQ_CTRL);
+ writel(BIT(22), TMU_TEQ_QCFG);
+
+ if (phyno == 3)
+ qmax = DEFAULT_TMU3_QDEPTH;
+ else
+ qmax = (q == 0) ? DEFAULT_Q0_QDEPTH :
+ DEFAULT_MAX_QDEPTH;
+
+ writel(qmax << 18, TMU_TEQ_HW_PROB_CFG2);
+ writel(qmax >> 14, TMU_TEQ_HW_PROB_CFG3);
+ }
+ }
+ writel(0x05, TMU_TEQ_DISABLE_DROPCHK);
+ writel(0, TMU_CTRL);
+}
+
+/**************************** HIF ***************************/
+/*
+ * Enable hif tx DMA and interrupt
+ */
+void hif_tx_enable(void)
+{
+ writel(HIF_CTRL_DMA_EN, HIF_TX_CTRL);
+}
+
+/*
+ * Disable hif tx DMA and interrupt
+ */
+void hif_tx_disable(void)
+{
+ u32 hif_int;
+
+ writel(0, HIF_TX_CTRL);
+
+ hif_int = readl(HIF_INT_ENABLE);
+ hif_int &= HIF_TXPKT_INT_EN;
+ writel(hif_int, HIF_INT_ENABLE);
+}
+
+/*
+ * Enable hif rx DMA and interrupt
+ */
+void hif_rx_enable(void)
+{
+ writel((HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+}
+
+/*
+ * Disable hif rx DMA and interrupt
+ */
+void hif_rx_disable(void)
+{
+ u32 hif_int;
+
+ writel(0, HIF_RX_CTRL);
+
+ hif_int = readl(HIF_INT_ENABLE);
+ hif_int &= HIF_RXPKT_INT_EN;
+ writel(hif_int, HIF_INT_ENABLE);
+}
+
+/*
+ * Initializes HIF copy block.
+ */
+void hif_init(void)
+{
+ /* Initialize HIF registers */
+ writel(HIF_RX_POLL_CTRL_CYCLE << 16 | HIF_TX_POLL_CTRL_CYCLE,
+ HIF_POLL_CTRL);
+ /* Make HIF AXI transactions non-bufferable */
+ writel(0x1, HIF_AXI_CTRL);
+}
diff --git a/drivers/net/pfe_eth/pfe_mdio.c b/drivers/net/pfe_eth/pfe_mdio.c
new file mode 100644
index 0000000000..a78a4d63f3
--- /dev/null
+++ b/drivers/net/pfe_eth/pfe_mdio.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <dm.h>
+#include <dm/platform_data/pfe_dm_eth.h>
+#include <net.h>
+#include <net/pfe_eth/pfe_eth.h>
+
+extern struct gemac_s gem_info[];
+#if defined(CONFIG_PHYLIB)
+
+#define MDIO_TIMEOUT 5000
+static int pfe_write_addr(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr)
+{
+ void *reg_base = bus->priv;
+ u32 devadr;
+ u32 phy;
+ u32 reg_data;
+ int timeout = MDIO_TIMEOUT;
+
+ devadr = ((dev_addr & EMAC_MII_DATA_RA_MASK) << EMAC_MII_DATA_RA_SHIFT);
+ phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
+
+ reg_data = (EMAC_MII_DATA_TA | phy | devadr | reg_addr);
+
+ writel(reg_data, reg_base + EMAC_MII_DATA_REG);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
+ if (timeout-- <= 0) {
+ printf("Phy MDIO read/write timeout\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt
+ */
+ writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
+
+ return 0;
+}
+
+static int pfe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr)
+{
+ void *reg_base = bus->priv;
+ u32 reg;
+ u32 phy;
+ u32 reg_data;
+ u16 val;
+ int timeout = MDIO_TIMEOUT;
+
+ if (dev_addr == MDIO_DEVAD_NONE) {
+ reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ } else {
+ pfe_write_addr(bus, phy_addr, dev_addr, reg_addr);
+ reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ }
+
+ phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
+
+ if (dev_addr == MDIO_DEVAD_NONE)
+ reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_RD |
+ EMAC_MII_DATA_TA | phy | reg);
+ else
+ reg_data = (EMAC_MII_DATA_OP_CL45_RD | EMAC_MII_DATA_TA |
+ phy | reg);
+
+ writel(reg_data, reg_base + EMAC_MII_DATA_REG);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
+ if (timeout-- <= 0) {
+ printf("Phy MDIO read/write timeout\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt
+ */
+ writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ val = (u16)readl(reg_base + EMAC_MII_DATA_REG);
+ debug("%s: %p phy: 0x%x reg:0x%08x val:%#x\n", __func__, reg_base,
+ phy_addr, reg_addr, val);
+
+ return val;
+}
+
+static int pfe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr, u16 data)
+{
+ void *reg_base = bus->priv;
+ u32 reg;
+ u32 phy;
+ u32 reg_data;
+ int timeout = MDIO_TIMEOUT;
+ int val;
+
+ if (dev_addr == MDIO_DEVAD_NONE) {
+ reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ } else {
+ pfe_write_addr(bus, phy_addr, dev_addr, reg_addr);
+ reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ }
+
+ phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
+
+ if (dev_addr == MDIO_DEVAD_NONE)
+ reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_WR |
+ EMAC_MII_DATA_TA | phy | reg | data);
+ else
+ reg_data = (EMAC_MII_DATA_OP_CL45_WR | EMAC_MII_DATA_TA |
+ phy | reg | data);
+
+ writel(reg_data, reg_base + EMAC_MII_DATA_REG);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
+ if (timeout-- <= 0) {
+ printf("Phy MDIO read/write timeout\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt
+ */
+ writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
+
+ debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phy_addr,
+ reg_addr, data);
+
+ return val;
+}
+
+static void pfe_configure_serdes(struct pfe_eth_dev *priv)
+{
+ struct mii_dev bus;
+ int value, sgmii_2500 = 0;
+ struct gemac_s *gem = priv->gem;
+
+ if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500)
+ sgmii_2500 = 1;
+
+ printf("%s %d\n", __func__, priv->gemac_port);
+
+ /* PCS configuration done with corresponding GEMAC */
+ bus.priv = gem_info[priv->gemac_port].gemac_base;
+
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x0);
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x1);
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x2);
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x3);
+
+ /* Reset serdes */
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x0, 0x8000);
+
+ /* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
+ value = PHY_SGMII_IF_MODE_SGMII;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_IF_MODE_AN;
+ else
+ value |= PHY_SGMII_IF_MODE_SGMII_GBT;
+
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
+
+ /* Dev ability according to SGMII specification */
+ value = PHY_SGMII_DEV_ABILITY_SGMII;
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x4, value);
+
+ /* These values taken from validation team */
+ if (!sgmii_2500) {
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x0);
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0x400);
+ } else {
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x7);
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xa120);
+ }
+
+ /* Restart AN */
+ value = PHY_SGMII_CR_DEF_VAL;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_CR_RESET_AN;
+ /* Disable Auto neg for 2.5G SGMII as it doesn't support auto neg*/
+ if (sgmii_2500)
+ value &= ~PHY_SGMII_ENABLE_AN;
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
+}
+
+int pfe_phy_configure(struct pfe_eth_dev *priv, int dev_id, int phy_id)
+{
+ struct phy_device *phydev = NULL;
+ struct udevice *dev = priv->dev;
+ struct gemac_s *gem = priv->gem;
+ struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
+
+ if (!gem->bus)
+ return -1;
+
+ /* Configure SGMII PCS */
+ if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII ||
+ gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500) {
+ out_be32(&scfg->mdioselcr, 0x00000000);
+ pfe_configure_serdes(priv);
+ }
+
+ mdelay(100);
+
+ /* By this time on-chip SGMII initialization is done
+ * we can switch mdio interface to external PHYs
+ */
+ out_be32(&scfg->mdioselcr, 0x80000000);
+
+ phydev = phy_connect(gem->bus, phy_id, dev, gem->phy_mode);
+ if (!phydev) {
+ printf("phy_connect failed\n");
+ return -ENODEV;
+ }
+
+ phy_config(phydev);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+#endif
+
+struct mii_dev *pfe_mdio_init(struct pfe_mdio_info *mdio_info)
+{
+ struct mii_dev *bus;
+ int ret;
+ u32 mdio_speed;
+ u32 pclk = 250000000;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ printf("mdio_alloc failed\n");
+ return NULL;
+ }
+ bus->read = pfe_phy_read;
+ bus->write = pfe_phy_write;
+
+ /* MAC1 MDIO used to communicate with external PHYS */
+ bus->priv = mdio_info->reg_base;
+ sprintf(bus->name, mdio_info->name);
+
+ /* configure mdio speed */
+ mdio_speed = (DIV_ROUND_UP(pclk, 4000000) << EMAC_MII_SPEED_SHIFT);
+ mdio_speed |= EMAC_HOLDTIME(0x5);
+ writel(mdio_speed, mdio_info->reg_base + EMAC_MII_CTRL_REG);
+
+ ret = mdio_register(bus);
+ if (ret) {
+ printf("mdio_register failed\n");
+ free(bus);
+ return NULL;
+ }
+ return bus;
+}
+
+void pfe_set_mdio(int dev_id, struct mii_dev *bus)
+{
+ gem_info[dev_id].bus = bus;
+}
+
+void pfe_set_phy_address_mode(int dev_id, int phy_id, int phy_mode)
+{
+ gem_info[dev_id].phy_address = phy_id;
+ gem_info[dev_id].phy_mode = phy_mode;
+}
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 7fd4a8d261..f5821dfed9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -13,6 +13,21 @@ menuconfig PHYLIB
if PHYLIB
+config PHY_ADDR_ENABLE
+ bool "Limit phy address"
+ default y if ARCH_SUNXI
+ help
+ Select this if you want to control which phy address is used
+
+if PHY_ADDR_ENABLE
+config PHY_ADDR
+ int "PHY address"
+ default 1 if ARCH_SUNXI
+ default 0
+ help
+ The address of PHY on MII bus. Usually in range of 0 to 31.
+endif
+
config B53_SWITCH
bool "Broadcom BCM53xx (RoboSwitch) Ethernet switch PHY support."
help
@@ -132,6 +147,16 @@ config PHY_NATSEMI
config PHY_REALTEK
bool "Realtek Ethernet PHYs support"
+config RTL8211E_PINE64_GIGABIT_FIX
+ bool "Fix gigabit throughput on some Pine64+ models"
+ depends on PHY_REALTEK
+ help
+ Configure the Realtek RTL8211E found on some Pine64+ models differently to
+ fix throughput on Gigabit links, turning off all internal delays in the
+ process. The settings that this touches are not documented in the CONFREG
+ section of the RTL8211E datasheet, but come from Realtek by way of the
+ Pine64 engineering team.
+
config RTL8211X_PHY_FORCE_MASTER
bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode"
depends on PHY_REALTEK
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index ad12f6d61f..6678147545 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -7,6 +7,7 @@
*/
#include <config.h>
#include <common.h>
+#include <dm.h>
#include <phy.h>
#ifndef CONFIG_PHYLIB_10G
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
index 637d89a1e1..9cb3a52c20 100644
--- a/drivers/net/phy/cortina.c
+++ b/drivers/net/phy/cortina.c
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: GPL-2.0+
*
* Copyright 2014 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
*
*/
@@ -27,6 +28,7 @@
#error The Cortina PHY needs 10G support
#endif
+#ifndef CORTINA_NO_FW_UPLOAD
struct cortina_reg_config cortina_reg_cfg[] = {
/* CS4315_enable_sr_mode */
{VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
@@ -215,12 +217,22 @@ void cs4340_upload_firmware(struct phy_device *phydev)
phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value);
}
}
+#endif
int cs4340_phy_init(struct phy_device *phydev)
{
+#ifndef CORTINA_NO_FW_UPLOAD
int timeout = 100; /* 100ms */
+#endif
int reg_value;
+ /*
+ * Cortina phy has provision to store
+ * phy firmware in attached dedicated EEPROM.
+ * Boards designed with EEPROM attached to Cortina
+ * does not require FW upload.
+ */
+#ifndef CORTINA_NO_FW_UPLOAD
/* step1: BIST test */
phy_write(phydev, 0x00, VILLA_GLOBAL_MSEQCLKCTRL, 0x0004);
phy_write(phydev, 0x00, VILLA_GLOBAL_LINE_SOFT_RESET, 0x0000);
@@ -241,6 +253,7 @@ int cs4340_phy_init(struct phy_device *phydev)
/* setp2: upload ucode */
cs4340_upload_firmware(phydev);
+#endif
reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_DWNLD_CHECKSUM_STATUS);
if (reg_value) {
debug("%s checksum status failed.\n", __func__);
@@ -295,45 +308,33 @@ int phy_cortina_init(void)
int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
{
int phy_reg;
- bool is_cortina_phy = false;
-
- switch (addr) {
-#ifdef CORTINA_PHY_ADDR1
- case CORTINA_PHY_ADDR1:
-#endif
-#ifdef CORTINA_PHY_ADDR2
- case CORTINA_PHY_ADDR2:
-#endif
-#ifdef CORTINA_PHY_ADDR3
- case CORTINA_PHY_ADDR3:
-#endif
-#ifdef CORTINA_PHY_ADDR4
- case CORTINA_PHY_ADDR4:
-#endif
- is_cortina_phy = true;
- break;
- default:
- break;
- }
/* Cortina PHY has non-standard offset of PHY ID registers */
- if (is_cortina_phy)
- phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB);
- else
- phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
+ phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB);
+ if (phy_reg < 0)
+ return -EIO;
+ *phy_id = (phy_reg & 0xffff) << 16;
+ phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB);
if (phy_reg < 0)
return -EIO;
+ *phy_id |= (phy_reg & 0xffff);
- *phy_id = (phy_reg & 0xffff) << 16;
- if (is_cortina_phy)
- phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB);
- else
- phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
+ if (*phy_id == PHY_UID_CS4340)
+ return 0;
+ /*
+ * If Cortina PHY not detected,
+ * try generic way to find PHY ID registers
+ */
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
if (phy_reg < 0)
return -EIO;
+ *phy_id = (phy_reg & 0xffff) << 16;
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
+ if (phy_reg < 0)
+ return -EIO;
*phy_id |= (phy_reg & 0xffff);
return 0;
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 6d917f86f4..d5c2a46c67 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -13,6 +13,7 @@
#include <phy.h>
#define PHY_RTL8211x_FORCE_MASTER BIT(1)
+#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
#define PHY_AUTONEGOTIATE_TIMEOUT 5000
@@ -47,6 +48,13 @@
#define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800
#define MIIM_RTL8211F_PHYSTAT_LINK 0x0004
+#define MIIM_RTL8211E_CONFREG 0x1c
+#define MIIM_RTL8211E_CONFREG_TXD 0x0002
+#define MIIM_RTL8211E_CONFREG_RXD 0x0004
+#define MIIM_RTL8211E_CONFREG_MAGIC 0xb400 /* Undocumented */
+
+#define MIIM_RTL8211E_EXT_PAGE_SELECT 0x1e
+
#define MIIM_RTL8211F_PAGE_SELECT 0x1f
#define MIIM_RTL8211F_TX_DELAY 0x100
#define MIIM_RTL8211F_LCR 0x10
@@ -60,6 +68,15 @@ static int rtl8211b_probe(struct phy_device *phydev)
return 0;
}
+static int rtl8211e_probe(struct phy_device *phydev)
+{
+#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
+ phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
+#endif
+
+ return 0;
+}
+
/* RealTek RTL8211x */
static int rtl8211x_config(struct phy_device *phydev)
{
@@ -81,6 +98,22 @@ static int rtl8211x_config(struct phy_device *phydev)
reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
}
+ if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
+ unsigned int reg;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
+ 7);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
+ /* Ensure both internal delays are turned off */
+ reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
+ /* Flip the magic undocumented bits */
+ reg |= MIIM_RTL8211E_CONFREG_MAGIC;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
+ 0);
+ }
/* read interrupt status just to clear it */
phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
@@ -279,6 +312,7 @@ static struct phy_driver RTL8211E_driver = {
.uid = 0x1cc915,
.mask = 0xffffff,
.features = PHY_GBIT_FEATURES,
+ .probe = &rtl8211e_probe,
.config = &rtl8211x_config,
.startup = &rtl8211e_startup,
.shutdown = &genphy_shutdown,
diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c
index 3f80f0495e..7142a99ce5 100644
--- a/drivers/net/phy/xilinx_phy.c
+++ b/drivers/net/phy/xilinx_phy.c
@@ -105,7 +105,7 @@ static int xilinxphy_of_init(struct phy_device *phydev)
debug("%s\n", __func__);
phytype = fdtdec_get_int(gd->fdt_blob, dev_of_offset(phydev->dev),
- "phy-type", -1);
+ "xlnx,phy-type", -1);
if (phytype == XAE_PHY_TYPE_1000BASE_X)
phydev->flags |= XAE_PHY_TYPE_1000BASE_X;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 6f48e93ab5..cb3970e051 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -11,6 +11,7 @@
#include <config.h>
#include <common.h>
+#include <environment.h>
#include <malloc.h>
#include <net.h>
#include <netdev.h>
@@ -905,7 +906,10 @@ int sh_ether_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id sh_ether_ids[] = {
+ { .compatible = "renesas,ether-r8a7790" },
{ .compatible = "renesas,ether-r8a7791" },
+ { .compatible = "renesas,ether-r8a7793" },
+ { .compatible = "renesas,ether-r8a7794" },
{ }
};
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 3ccc6b0bb6..b6e5dafe83 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -21,6 +21,7 @@
#include <malloc.h>
#include <miiphy.h>
#include <net.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
#ifdef CONFIG_DM_GPIO
#include <asm-generic/gpio.h>
#endif
@@ -278,7 +279,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv)
int ret;
u32 reg;
- reg = readl(priv->sysctl_reg);
+ reg = readl(priv->sysctl_reg + 0x30);
if (priv->variant == H3_EMAC) {
ret = sun8i_emac_set_syscon_ephy(priv, &reg);
@@ -309,7 +310,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv)
return -EINVAL;
}
- writel(reg, priv->sysctl_reg);
+ writel(reg, priv->sysctl_reg + 0x30);
return 0;
}
@@ -431,7 +432,7 @@ static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr)
tx_descs_init(priv);
/* PHY Start Up */
- genphy_parse_link(priv->phydev);
+ phy_startup(priv->phydev);
sun8i_adjust_link(priv, priv->phydev);
@@ -455,7 +456,7 @@ static int parse_phy_pins(struct udevice *dev)
{
int offset;
const char *pin_name;
- int drive, pull, i;
+ int drive, pull = SUN4I_PINCTRL_NO_PULL, i;
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
"pinctrl-0");
@@ -465,30 +466,44 @@ static int parse_phy_pins(struct udevice *dev)
}
drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0,
- "allwinner,drive", 4);
- pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0,
- "allwinner,pull", 0);
+ "drive-strength", ~0);
+ if (drive != ~0) {
+ if (drive <= 10)
+ drive = SUN4I_PINCTRL_10_MA;
+ else if (drive <= 20)
+ drive = SUN4I_PINCTRL_20_MA;
+ else if (drive <= 30)
+ drive = SUN4I_PINCTRL_30_MA;
+ else
+ drive = SUN4I_PINCTRL_40_MA;
+ }
+
+ if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-up", NULL))
+ pull = SUN4I_PINCTRL_PULL_UP;
+ else if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-down", NULL))
+ pull = SUN4I_PINCTRL_PULL_DOWN;
+
for (i = 0; ; i++) {
int pin;
pin_name = fdt_stringlist_get(gd->fdt_blob, offset,
- "allwinner,pins", i, NULL);
+ "pins", i, NULL);
if (!pin_name)
break;
- if (pin_name[0] != 'P')
- continue;
- pin = (pin_name[1] - 'A') << 5;
- if (pin >= 26 << 5)
+
+ pin = sunxi_name_to_gpio(pin_name);
+ if (pin < 0)
continue;
- pin += simple_strtol(&pin_name[2], NULL, 10);
sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC);
- sunxi_gpio_set_drv(pin, drive);
- sunxi_gpio_set_pull(pin, pull);
+ if (drive != ~0)
+ sunxi_gpio_set_drv(pin, drive);
+ if (pull != ~0)
+ sunxi_gpio_set_pull(pin, pull);
}
if (!i) {
- printf("WARNING: emac: cannot find allwinner,pins property\n");
+ printf("WARNING: emac: cannot find pins property\n");
return -2;
}
@@ -772,6 +787,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
struct eth_pdata *pdata = &sun8i_pdata->eth_pdata;
struct emac_eth_dev *priv = dev_get_priv(dev);
const char *phy_mode;
+ const fdt32_t *reg;
int node = dev_of_offset(dev);
int offset = 0;
#ifdef CONFIG_DM_GPIO
@@ -779,18 +795,40 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
int ret = 0;
#endif
- pdata->iobase = devfdt_get_addr_name(dev, "emac");
- priv->sysctl_reg = devfdt_get_addr_name(dev, "syscon");
+ pdata->iobase = devfdt_get_addr(dev);
+ if (pdata->iobase == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot find MAC base address\n", __func__);
+ return -EINVAL;
+ }
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "syscon");
+ if (offset < 0) {
+ debug("%s: cannot find syscon node\n", __func__);
+ return -EINVAL;
+ }
+ reg = fdt_getprop(gd->fdt_blob, offset, "reg", NULL);
+ if (!reg) {
+ debug("%s: cannot find reg property in syscon node\n",
+ __func__);
+ return -EINVAL;
+ }
+ priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob,
+ offset, reg);
+ if (priv->sysctl_reg == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot find syscon base address\n", __func__);
+ return -EINVAL;
+ }
pdata->phy_interface = -1;
priv->phyaddr = -1;
priv->use_internal_phy = false;
- offset = fdtdec_lookup_phandle(gd->fdt_blob, node,
- "phy");
- if (offset > 0)
- priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg",
- -1);
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy-handle");
+ if (offset < 0) {
+ debug("%s: Cannot find PHY address\n", __func__);
+ return -EINVAL;
+ }
+ priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
@@ -812,8 +850,11 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
}
if (priv->variant == H3_EMAC) {
- if (fdt_getprop(gd->fdt_blob, node,
- "allwinner,use-internal-phy", NULL))
+ int parent = fdt_parent_offset(gd->fdt_blob, offset);
+
+ if (parent >= 0 &&
+ !fdt_node_check_compatible(gd->fdt_blob, parent,
+ "allwinner,sun8i-h3-mdio-internal"))
priv->use_internal_phy = true;
}
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c
index 70a2e95a8e..80ed06ac66 100644
--- a/drivers/net/xilinx_axi_emac.c
+++ b/drivers/net/xilinx_axi_emac.c
@@ -78,9 +78,10 @@ static u8 rxframe[PKTSIZE_ALIGN] __attribute((aligned(DMAALIGN)));
struct axidma_reg {
u32 control; /* DMACR */
u32 status; /* DMASR */
- u32 current; /* CURDESC */
- u32 reserved;
- u32 tail; /* TAILDESC */
+ u32 current; /* CURDESC low 32 bit */
+ u32 current_hi; /* CURDESC high 32 bit */
+ u32 tail; /* TAILDESC low 32 bit */
+ u32 tail_hi; /* TAILDESC high 32 bit */
};
/* Private driver structures */
@@ -168,6 +169,22 @@ static inline int mdio_wait(struct axi_regs *regs)
return 0;
}
+/**
+ * axienet_dma_write - Memory mapped Axi DMA register Buffer Descriptor write.
+ * @bd: pointer to BD descriptor structure
+ * @desc: Address offset of DMA descriptors
+ *
+ * This function writes the value into the corresponding Axi DMA register.
+ */
+static inline void axienet_dma_write(struct axidma_bd *bd, u32 *desc)
+{
+#if defined(CONFIG_PHYS_64BIT)
+ writeq(bd, desc);
+#else
+ writel((u32)bd, desc);
+#endif
+}
+
static u32 phyread(struct axidma_priv *priv, u32 phyaddress, u32 registernum,
u16 *val)
{
@@ -465,7 +482,7 @@ static int axiemac_start(struct udevice *dev)
writel(temp, &priv->dmarx->control);
/* Start DMA RX channel. Now it's ready to receive data.*/
- writel((u32)&rx_bd, &priv->dmarx->current);
+ axienet_dma_write(&rx_bd, &priv->dmarx->current);
/* Setup the BD. */
memset(&rx_bd, 0, sizeof(rx_bd));
@@ -485,7 +502,7 @@ static int axiemac_start(struct udevice *dev)
writel(temp, &priv->dmarx->control);
/* Rx BD is ready - start */
- writel((u32)&rx_bd, &priv->dmarx->tail);
+ axienet_dma_write(&rx_bd, &priv->dmarx->tail);
/* Enable TX */
writel(XAE_TC_TX_MASK, &regs->tc);
@@ -527,7 +544,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len)
if (readl(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) {
u32 temp;
- writel((u32)&tx_bd, &priv->dmatx->current);
+ axienet_dma_write(&tx_bd, &priv->dmatx->current);
/* Start the hardware */
temp = readl(&priv->dmatx->control);
temp |= XAXIDMA_CR_RUNSTOP_MASK;
@@ -535,7 +552,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len)
}
/* Start transfer */
- writel((u32)&tx_bd, &priv->dmatx->tail);
+ axienet_dma_write(&tx_bd, &priv->dmatx->tail);
/* Wait for transmission to complete */
debug("axiemac: Waiting for tx to be done\n");
@@ -626,7 +643,7 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length)
flush_cache((u32)&rxframe, sizeof(rxframe));
/* Rx BD is ready - start again */
- writel((u32)&rx_bd, &priv->dmarx->tail);
+ axienet_dma_write(&rx_bd, &priv->dmarx->tail);
debug("axiemac: RX completed, framelength = %d\n", length);
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 2cc49bca92..dd36a8c22a 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -182,6 +182,7 @@ struct zynq_gem_priv {
int phy_of_handle;
struct mii_dev *bus;
struct clk clk;
+ u32 max_speed;
bool int_pcs;
};
@@ -325,7 +326,8 @@ static int zynq_phy_init(struct udevice *dev)
/* Enable only MDIO bus */
writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, &regs->nwctrl);
- if (priv->interface != PHY_INTERFACE_MODE_SGMII) {
+ if ((priv->interface != PHY_INTERFACE_MODE_SGMII) &&
+ (priv->interface != PHY_INTERFACE_MODE_GMII)) {
ret = phy_detection(dev);
if (ret) {
printf("GEM PHY init failed\n");
@@ -340,6 +342,12 @@ static int zynq_phy_init(struct udevice *dev)
priv->phydev->supported &= supported | ADVERTISED_Pause |
ADVERTISED_Asym_Pause;
+ if (priv->max_speed) {
+ ret = phy_set_supported(priv->phydev, priv->max_speed);
+ if (ret)
+ return ret;
+ }
+
priv->phydev->advertising = priv->phydev->supported;
if (priv->phy_of_handle > 0)
@@ -703,6 +711,8 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
}
priv->interface = pdata->phy_interface;
+ priv->max_speed = fdtdec_get_uint(gd->fdt_blob, priv->phy_of_handle,
+ "max-speed", SPEED_1000);
priv->int_pcs = fdtdec_get_bool(gd->fdt_blob, node,
"is-internal-pcspma");
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index da6421f35c..c20a0cc060 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -26,6 +26,16 @@ config DM_PCI_COMPAT
measure when porting a board to use driver model for PCI. Once the
board is fully supported, this option should be disabled.
+config PCI_AARDVARK
+ bool "Enable Aardvark PCIe driver"
+ default n
+ depends on DM_PCI
+ depends on ARMADA_3700
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Armada37x0 SoCs. The PCIe controller on Armada37x0 is based on
+ Aardvark hardware.
+
config PCI_PNP
bool "Enable Plug & Play support for PCI"
depends on PCI || DM_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 8fbab462a4..40ebc06f6d 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_SH4_PCI) += pci_sh4.o
obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o
+obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o
obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o
obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
new file mode 100644
index 0000000000..69a4d81c2e
--- /dev/null
+++ b/drivers/pci/pci-aardvark.c
@@ -0,0 +1,690 @@
+/*
+ * ***************************************************************************
+ * Copyright (C) 2015 Marvell International Ltd.
+ * ***************************************************************************
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * ***************************************************************************
+ */
+/* pcie_advk.c
+ *
+ * Ported from Linux driver - driver/pci/host/pci-aardvark.c
+ *
+ * Author: Victor Gu <xigu@marvell.com>
+ * Hezi Shahmoon <hezi.shahmoon@marvell.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <linux/ioport.h>
+
+/* PCIe core registers */
+#define PCIE_CORE_CMD_STATUS_REG 0x4
+#define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0)
+#define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1)
+#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2)
+#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8
+#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4)
+#define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11)
+#define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0
+#define PCIE_CORE_LINK_TRAINING BIT(5)
+#define PCIE_CORE_ERR_CAPCTL_REG 0x118
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX BIT(5)
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6)
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHECK BIT(7)
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHECK_RCV BIT(8)
+
+/* PIO registers base address and register offsets */
+#define PIO_BASE_ADDR 0x4000
+#define PIO_CTRL (PIO_BASE_ADDR + 0x0)
+#define PIO_CTRL_TYPE_MASK GENMASK(3, 0)
+#define PIO_CTRL_ADDR_WIN_DISABLE BIT(24)
+#define PIO_STAT (PIO_BASE_ADDR + 0x4)
+#define PIO_COMPLETION_STATUS_SHIFT 7
+#define PIO_COMPLETION_STATUS_MASK GENMASK(9, 7)
+#define PIO_COMPLETION_STATUS_OK 0
+#define PIO_COMPLETION_STATUS_UR 1
+#define PIO_COMPLETION_STATUS_CRS 2
+#define PIO_COMPLETION_STATUS_CA 4
+#define PIO_NON_POSTED_REQ BIT(10)
+#define PIO_ERR_STATUS BIT(11)
+#define PIO_ADDR_LS (PIO_BASE_ADDR + 0x8)
+#define PIO_ADDR_MS (PIO_BASE_ADDR + 0xc)
+#define PIO_WR_DATA (PIO_BASE_ADDR + 0x10)
+#define PIO_WR_DATA_STRB (PIO_BASE_ADDR + 0x14)
+#define PIO_RD_DATA (PIO_BASE_ADDR + 0x18)
+#define PIO_START (PIO_BASE_ADDR + 0x1c)
+#define PIO_ISR (PIO_BASE_ADDR + 0x20)
+
+/* Aardvark Control registers */
+#define CONTROL_BASE_ADDR 0x4800
+#define PCIE_CORE_CTRL0_REG (CONTROL_BASE_ADDR + 0x0)
+#define PCIE_GEN_SEL_MSK 0x3
+#define PCIE_GEN_SEL_SHIFT 0x0
+#define SPEED_GEN_1 0
+#define SPEED_GEN_2 1
+#define SPEED_GEN_3 2
+#define IS_RC_MSK 1
+#define IS_RC_SHIFT 2
+#define LANE_CNT_MSK 0x18
+#define LANE_CNT_SHIFT 0x3
+#define LANE_COUNT_1 (0 << LANE_CNT_SHIFT)
+#define LANE_COUNT_2 (1 << LANE_CNT_SHIFT)
+#define LANE_COUNT_4 (2 << LANE_CNT_SHIFT)
+#define LANE_COUNT_8 (3 << LANE_CNT_SHIFT)
+#define LINK_TRAINING_EN BIT(6)
+#define PCIE_CORE_CTRL2_REG (CONTROL_BASE_ADDR + 0x8)
+#define PCIE_CORE_CTRL2_RESERVED 0x7
+#define PCIE_CORE_CTRL2_TD_ENABLE BIT(4)
+#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
+#define PCIE_CORE_CTRL2_ADDRWIN_MAP_ENABLE BIT(6)
+
+/* LMI registers base address and register offsets */
+#define LMI_BASE_ADDR 0x6000
+#define CFG_REG (LMI_BASE_ADDR + 0x0)
+#define LTSSM_SHIFT 24
+#define LTSSM_MASK 0x3f
+#define LTSSM_L0 0x10
+
+/* PCIe core controller registers */
+#define CTRL_CORE_BASE_ADDR 0x18000
+#define CTRL_CONFIG_REG (CTRL_CORE_BASE_ADDR + 0x0)
+#define CTRL_MODE_SHIFT 0x0
+#define CTRL_MODE_MASK 0x1
+#define PCIE_CORE_MODE_DIRECT 0x0
+#define PCIE_CORE_MODE_COMMAND 0x1
+
+/* Transaction types */
+#define PCIE_CONFIG_RD_TYPE0 0x8
+#define PCIE_CONFIG_RD_TYPE1 0x9
+#define PCIE_CONFIG_WR_TYPE0 0xa
+#define PCIE_CONFIG_WR_TYPE1 0xb
+
+/* PCI_BDF shifts 8bit, so we need extra 4bit shift */
+#define PCIE_BDF(dev) (dev << 4)
+#define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20)
+#define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15)
+#define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12)
+#define PCIE_CONF_REG(reg) ((reg) & 0xffc)
+#define PCIE_CONF_ADDR(bus, devfn, where) \
+ (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
+
+/* PCIe Retries & Timeout definitions */
+#define MAX_RETRIES 10
+#define PIO_WAIT_TIMEOUT 100
+#define LINK_WAIT_TIMEOUT 100000
+
+#define CFG_RD_UR_VAL 0xFFFFFFFF
+#define CFG_RD_CRS_VAL 0xFFFF0001
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct pcie_advk - Advk PCIe controller state
+ *
+ * @reg_base: The base address of the register space.
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup
+ * (PEX switches etc).
+ * @device: The pointer to PCI uclass device.
+ */
+struct pcie_advk {
+ void *base;
+ int first_busno;
+ struct udevice *dev;
+};
+
+static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg)
+{
+ writel(val, pcie->base + reg);
+}
+
+static inline uint advk_readl(struct pcie_advk *pcie, uint reg)
+{
+ return readl(pcie->base + reg);
+}
+
+/**
+ * pcie_advk_addr_valid() - Check for valid bus address
+ *
+ * @bdf: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno)
+{
+ /*
+ * In PCIE-E only a single device (0) can exist
+ * on the local bus. Beyound the local bus, there might be
+ * a Switch and everything is possible.
+ */
+ if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * pcie_advk_wait_pio() - Wait for PIO access to be accomplished
+ *
+ * @pcie: The PCI device to access
+ *
+ * Wait up to 1 micro second for PIO access to be accomplished.
+ *
+ * Return 1 (true) if PIO access is accomplished.
+ * Return 0 (false) if PIO access is timed out.
+ */
+static int pcie_advk_wait_pio(struct pcie_advk *pcie)
+{
+ uint start, isr;
+ uint count;
+
+ for (count = 0; count < MAX_RETRIES; count++) {
+ start = advk_readl(pcie, PIO_START);
+ isr = advk_readl(pcie, PIO_ISR);
+ if (!start && isr)
+ return 1;
+ /*
+ * Do not check the PIO state too frequently,
+ * 100us delay is appropriate.
+ */
+ udelay(PIO_WAIT_TIMEOUT);
+ }
+
+ dev_err(pcie->dev, "config read/write timed out\n");
+ return 0;
+}
+
+/**
+ * pcie_advk_check_pio_status() - Validate PIO status and get the read result
+ *
+ * @pcie: Pointer to the PCI bus
+ * @read: Read from or write to configuration space - true(read) false(write)
+ * @read_val: Pointer to the read result, only valid when read is true
+ *
+ */
+static int pcie_advk_check_pio_status(struct pcie_advk *pcie,
+ bool read,
+ uint *read_val)
+{
+ uint reg;
+ unsigned int status;
+ char *strcomp_status, *str_posted;
+
+ reg = advk_readl(pcie, PIO_STAT);
+ status = (reg & PIO_COMPLETION_STATUS_MASK) >>
+ PIO_COMPLETION_STATUS_SHIFT;
+
+ switch (status) {
+ case PIO_COMPLETION_STATUS_OK:
+ if (reg & PIO_ERR_STATUS) {
+ strcomp_status = "COMP_ERR";
+ break;
+ }
+ /* Get the read result */
+ if (read)
+ *read_val = advk_readl(pcie, PIO_RD_DATA);
+ /* No error */
+ strcomp_status = NULL;
+ break;
+ case PIO_COMPLETION_STATUS_UR:
+ if (read) {
+ /* For reading, UR is not an error status. */
+ *read_val = CFG_RD_UR_VAL;
+ strcomp_status = NULL;
+ } else {
+ strcomp_status = "UR";
+ }
+ break;
+ case PIO_COMPLETION_STATUS_CRS:
+ if (read) {
+ /* For reading, CRS is not an error status. */
+ *read_val = CFG_RD_CRS_VAL;
+ strcomp_status = NULL;
+ } else {
+ strcomp_status = "CRS";
+ }
+ break;
+ case PIO_COMPLETION_STATUS_CA:
+ strcomp_status = "CA";
+ break;
+ default:
+ strcomp_status = "Unknown";
+ break;
+ }
+
+ if (!strcomp_status)
+ return 0;
+
+ if (reg & PIO_NON_POSTED_REQ)
+ str_posted = "Non-posted";
+ else
+ str_posted = "Posted";
+
+ dev_err(pcie->dev, "%s PIO Response Status: %s, %#x @ %#x\n",
+ str_posted, strcomp_status, reg,
+ advk_readl(pcie, PIO_ADDR_LS));
+
+ return -EFAULT;
+}
+
+/**
+ * pcie_advk_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+static int pcie_advk_read_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct pcie_advk *pcie = dev_get_priv(bus);
+ uint reg;
+ int ret;
+
+ dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) {
+ dev_dbg(pcie->dev, "- out of range\n");
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ /* Start PIO */
+ advk_writel(pcie, 0, PIO_START);
+ advk_writel(pcie, 1, PIO_ISR);
+
+ /* Program the control register */
+ reg = advk_readl(pcie, PIO_CTRL);
+ reg &= ~PIO_CTRL_TYPE_MASK;
+ if (PCI_BUS(bdf) == pcie->first_busno)
+ reg |= PCIE_CONFIG_RD_TYPE0;
+ else
+ reg |= PCIE_CONFIG_RD_TYPE1;
+ advk_writel(pcie, reg, PIO_CTRL);
+
+ /* Program the address registers */
+ reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset);
+ advk_writel(pcie, reg, PIO_ADDR_LS);
+ advk_writel(pcie, 0, PIO_ADDR_MS);
+
+ /* Start the transfer */
+ advk_writel(pcie, 1, PIO_START);
+
+ if (!pcie_advk_wait_pio(pcie))
+ return -EINVAL;
+
+ /* Check PIO status and get the read result */
+ ret = pcie_advk_check_pio_status(pcie, true, &reg);
+ if (ret)
+ return ret;
+
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n",
+ offset, size, reg);
+ *valuep = pci_conv_32_to_size(reg, offset, size);
+
+ return 0;
+}
+
+/**
+ * pcie_calc_datastrobe() - Calculate data strobe
+ *
+ * @offset: The offset into the device's configuration space
+ * @size: Indicates the size of access to perform
+ *
+ * Calculate data strobe according to offset and size
+ *
+ */
+static uint pcie_calc_datastrobe(uint offset, enum pci_size_t size)
+{
+ uint bytes, data_strobe;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ bytes = 1;
+ break;
+ case PCI_SIZE_16:
+ bytes = 2;
+ break;
+ default:
+ bytes = 4;
+ }
+
+ data_strobe = GENMASK(bytes - 1, 0) << (offset & 0x3);
+
+ return data_strobe;
+}
+
+/**
+ * pcie_advk_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct pcie_advk *pcie = dev_get_priv(bus);
+ uint reg;
+
+ dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n",
+ offset, size, value);
+
+ if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) {
+ dev_dbg(pcie->dev, "- out of range\n");
+ return 0;
+ }
+
+ /* Start PIO */
+ advk_writel(pcie, 0, PIO_START);
+ advk_writel(pcie, 1, PIO_ISR);
+
+ /* Program the control register */
+ reg = advk_readl(pcie, PIO_CTRL);
+ reg &= ~PIO_CTRL_TYPE_MASK;
+ if (PCI_BUS(bdf) == pcie->first_busno)
+ reg |= PCIE_CONFIG_WR_TYPE0;
+ else
+ reg |= PCIE_CONFIG_WR_TYPE1;
+ advk_writel(pcie, reg, PIO_CTRL);
+
+ /* Program the address registers */
+ reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset);
+ advk_writel(pcie, reg, PIO_ADDR_LS);
+ advk_writel(pcie, 0, PIO_ADDR_MS);
+ dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg);
+
+ /* Program the data register */
+ reg = pci_conv_size_to_32(0, value, offset, size);
+ advk_writel(pcie, reg, PIO_WR_DATA);
+ dev_dbg(pcie->dev, "\tPIO req. - val = 0x%08x\n", reg);
+
+ /* Program the data strobe */
+ reg = pcie_calc_datastrobe(offset, size);
+ advk_writel(pcie, reg, PIO_WR_DATA_STRB);
+ dev_dbg(pcie->dev, "\tPIO req. - strb = 0x%02x\n", reg);
+
+ /* Start the transfer */
+ advk_writel(pcie, 1, PIO_START);
+
+ if (!pcie_advk_wait_pio(pcie)) {
+ dev_dbg(pcie->dev, "- wait pio timeout\n");
+ return -EINVAL;
+ }
+
+ /* Check PIO status */
+ pcie_advk_check_pio_status(pcie, false, &reg);
+
+ return 0;
+}
+
+/**
+ * pcie_advk_link_up() - Check if PCIe link is up or not
+ *
+ * @pcie: The PCI device to access
+ *
+ * Return 1 (true) on link up.
+ * Return 0 (false) on link down.
+ */
+static int pcie_advk_link_up(struct pcie_advk *pcie)
+{
+ u32 val, ltssm_state;
+
+ val = advk_readl(pcie, CFG_REG);
+ ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK;
+ return ltssm_state >= LTSSM_L0;
+}
+
+/**
+ * pcie_advk_wait_for_link() - Wait for link training to be accomplished
+ *
+ * @pcie: The PCI device to access
+ *
+ * Wait up to 1 second for link training to be accomplished.
+ *
+ * Return 1 (true) if link training ends up with link up success.
+ * Return 0 (false) if link training ends up with link up failure.
+ */
+static int pcie_advk_wait_for_link(struct pcie_advk *pcie)
+{
+ int retries;
+
+ /* check if the link is up or not */
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ if (pcie_advk_link_up(pcie)) {
+ printf("PCIE-%d: Link up\n", pcie->first_busno);
+ return 0;
+ }
+
+ udelay(LINK_WAIT_TIMEOUT);
+ }
+
+ printf("PCIE-%d: Link down\n", pcie->first_busno);
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * pcie_advk_setup_hw() - PCIe initailzation
+ *
+ * @pcie: The PCI device to access
+ *
+ * Return: 0 on success
+ */
+static int pcie_advk_setup_hw(struct pcie_advk *pcie)
+{
+ u32 reg;
+
+ /* Set to Direct mode */
+ reg = advk_readl(pcie, CTRL_CONFIG_REG);
+ reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT);
+ reg |= ((PCIE_CORE_MODE_DIRECT & CTRL_MODE_MASK) << CTRL_MODE_SHIFT);
+ advk_writel(pcie, reg, CTRL_CONFIG_REG);
+
+ /* Set PCI global control register to RC mode */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg |= (IS_RC_MSK << IS_RC_SHIFT);
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /* Set Advanced Error Capabilities and Control PF0 register */
+ reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHECK |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHECK_RCV;
+ advk_writel(pcie, reg, PCIE_CORE_ERR_CAPCTL_REG);
+
+ /* Set PCIe Device Control and Status 1 PF0 register */
+ reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE |
+ PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE;
+ advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG);
+
+ /* Program PCIe Control 2 to disable strict ordering */
+ reg = PCIE_CORE_CTRL2_RESERVED |
+ PCIE_CORE_CTRL2_TD_ENABLE;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+ /* Set GEN2 */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg &= ~PCIE_GEN_SEL_MSK;
+ reg |= SPEED_GEN_2;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /* Set lane X1 */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg &= ~LANE_CNT_MSK;
+ reg |= LANE_COUNT_1;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /* Enable link training */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg |= LINK_TRAINING_EN;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /*
+ * Enable AXI address window location generation:
+ * When it is enabled, the default outbound window
+ * configurations (Default User Field: 0xD0074CFC)
+ * are used to transparent address translation for
+ * the outbound transactions. Thus, PCIe address
+ * windows are not required.
+ */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
+ reg |= PCIE_CORE_CTRL2_ADDRWIN_MAP_ENABLE;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+ /*
+ * Bypass the address window mapping for PIO:
+ * Since PIO access already contains all required
+ * info over AXI interface by PIO registers, the
+ * address window is not required.
+ */
+ reg = advk_readl(pcie, PIO_CTRL);
+ reg |= PIO_CTRL_ADDR_WIN_DISABLE;
+ advk_writel(pcie, reg, PIO_CTRL);
+
+ /* Start link training */
+ reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
+ reg |= PCIE_CORE_LINK_TRAINING;
+ advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
+
+ /* Wait for PCIe link up */
+ if (pcie_advk_wait_for_link(pcie))
+ return -ENXIO;
+
+ reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
+ reg |= PCIE_CORE_CMD_MEM_ACCESS_EN |
+ PCIE_CORE_CMD_IO_ACCESS_EN |
+ PCIE_CORE_CMD_MEM_IO_REQ_EN;
+ advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
+
+ return 0;
+}
+
+/**
+ * pcie_advk_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int pcie_advk_probe(struct udevice *dev)
+{
+ struct pcie_advk *pcie = dev_get_priv(dev);
+
+#ifdef CONFIG_DM_GPIO
+ struct gpio_desc reset_gpio;
+
+ gpio_request_by_name(dev, "reset-gpio", 0, &reset_gpio,
+ GPIOD_IS_OUT);
+ /*
+ * Issue reset to add-in card through the dedicated GPIO.
+ * Some boards are connecting the card reset pin to common system
+ * reset wire and others are using separate GPIO port.
+ * In the last case we have to release a reset of the addon card
+ * using this GPIO.
+ *
+ * FIX-ME:
+ * The PCIe RESET signal is not supposed to be released along
+ * with the SOC RESET signal. It should be lowered as early as
+ * possible before PCIe PHY initialization. Moreover, the PCIe
+ * clock should be gated as well.
+ */
+ if (dm_gpio_is_valid(&reset_gpio)) {
+ dev_dbg(pcie->dev, "Toggle PCIE Reset GPIO ...\n");
+ dm_gpio_set_value(&reset_gpio, 0);
+ mdelay(200);
+ dm_gpio_set_value(&reset_gpio, 1);
+ }
+#else
+ dev_dbg(pcie->dev, "PCIE Reset on GPIO support is missing\n");
+#endif /* CONFIG_DM_GPIO */
+
+ pcie->first_busno = dev->seq;
+ pcie->dev = pci_get_controller(dev);
+
+ return pcie_advk_setup_hw(pcie);
+}
+
+/**
+ * pcie_advk_ofdata_to_platdata() - Translate from DT to device state
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pcie_advk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct pcie_advk *pcie = dev_get_priv(dev);
+
+ /* Get the register base address */
+ pcie->base = (void *)dev_read_addr_index(dev, 0);
+ if ((fdt_addr_t)pcie->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_advk_ops = {
+ .read_config = pcie_advk_read_config,
+ .write_config = pcie_advk_write_config,
+};
+
+static const struct udevice_id pcie_advk_ids[] = {
+ { .compatible = "marvell,armada-37xx-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_advk) = {
+ .name = "pcie_advk",
+ .id = UCLASS_PCI,
+ .of_match = pcie_advk_ids,
+ .ops = &pcie_advk_ops,
+ .ofdata_to_platdata = pcie_advk_ofdata_to_platdata,
+ .probe = pcie_advk_probe,
+ .priv_auto_alloc_size = sizeof(struct pcie_advk),
+};
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index ad43e8a27c..a2e829608a 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -876,6 +876,9 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node,
#ifdef CONFIG_NR_DRAM_BANKS
bd_t *bd = gd->bd;
+ if (!bd)
+ return 0;
+
for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
if (bd->bi_dram[i].size) {
pci_set_region(hose->regions + hose->region_count++,
@@ -894,8 +897,9 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node,
#endif
if (gd->pci_ram_top && gd->pci_ram_top < base + size)
size = gd->pci_ram_top - base;
- pci_set_region(hose->regions + hose->region_count++, base, base,
- size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ if (size)
+ pci_set_region(hose->regions + hose->region_count++, base,
+ base, size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
#endif
return 0;
diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c
index a19885501c..a0032b7b03 100644
--- a/drivers/pci/pcie_dw_mvebu.c
+++ b/drivers/pci/pcie_dw_mvebu.c
@@ -111,6 +111,10 @@ struct pcie_dw_mvebu {
void *cfg_base;
fdt_size_t cfg_size;
int first_busno;
+
+ /* IO and MEM PCI regions */
+ struct pci_region io;
+ struct pci_region mem;
};
static int pcie_dw_get_link_speed(const void *regs_base)
@@ -126,6 +130,34 @@ static int pcie_dw_get_link_width(const void *regs_base)
}
/**
+ * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ */
+static void pcie_dw_prog_outbound_atu(struct pcie_dw_mvebu *pcie, int index,
+ int type, u64 cpu_addr, u64 pci_addr,
+ u32 size)
+{
+ writel(PCIE_ATU_REGION_OUTBOUND | index,
+ pcie->ctrl_base + PCIE_ATU_VIEWPORT);
+ writel(lower_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_LOWER_BASE);
+ writel(upper_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_UPPER_BASE);
+ writel(lower_32_bits(cpu_addr + size - 1),
+ pcie->ctrl_base + PCIE_ATU_LIMIT);
+ writel(lower_32_bits(pci_addr),
+ pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
+ writel(upper_32_bits(pci_addr),
+ pcie->ctrl_base + PCIE_ATU_UPPER_TARGET);
+ writel(type, pcie->ctrl_base + PCIE_ATU_CR1);
+ writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2);
+}
+
+/**
* set_cfg_address() - Configure the PCIe controller config space access
*
* @pcie: Pointer to the PCI controller state
@@ -143,27 +175,29 @@ static uintptr_t set_cfg_address(struct pcie_dw_mvebu *pcie,
pci_dev_t d, uint where)
{
uintptr_t va_address;
+ u32 atu_type;
/*
* Region #0 is used for Outbound CFG space access.
* Direction = Outbound
* Region Index = 0
*/
- writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT);
if (PCI_BUS(d) == (pcie->first_busno + 1))
/* For local bus, change TLP Type field to 4. */
- writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1);
+ atu_type = PCIE_ATU_TYPE_CFG0;
else
/* Otherwise, change TLP Type field to 5. */
- writel(PCIE_ATU_TYPE_CFG1, pcie->ctrl_base + PCIE_ATU_CR1);
+ atu_type = PCIE_ATU_TYPE_CFG1;
if (PCI_BUS(d) == pcie->first_busno) {
/* Accessing root port configuration space. */
va_address = (uintptr_t)pcie->ctrl_base;
} else {
d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno);
- writel(d << 8, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ atu_type, (u64)pcie->cfg_base,
+ d << 8, pcie->cfg_size);
va_address = (uintptr_t)pcie->cfg_base;
}
@@ -231,6 +265,10 @@ static int pcie_dw_mvebu_read_config(struct udevice *bus, pci_dev_t bdf,
debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
*valuep = pci_conv_32_to_size(value, offset, size);
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+
return 0;
}
@@ -272,6 +310,10 @@ static int pcie_dw_mvebu_write_config(struct udevice *bus, pci_dev_t bdf,
value = pci_conv_size_to_32(old, value, offset, size);
writel(value, va_address);
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+
return 0;
}
@@ -388,34 +430,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed)
}
/**
- * pcie_dw_regions_setup() - iATU region setup
- *
- * @pcie: Pointer to the PCI controller state
- *
- * Configure the iATU regions in the PCIe controller for outbound access.
- */
-static void pcie_dw_regions_setup(struct pcie_dw_mvebu *pcie)
-{
- /*
- * Region #0 is used for Outbound CFG space access.
- * Direction = Outbound
- * Region Index = 0
- */
- writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT);
-
- writel((u32)(uintptr_t)pcie->cfg_base, pcie->ctrl_base
- + PCIE_ATU_LOWER_BASE);
- writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_BASE);
- writel((u32)(uintptr_t)pcie->cfg_base + pcie->cfg_size,
- pcie->ctrl_base + PCIE_ATU_LIMIT);
-
- writel(0, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
- writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_TARGET);
- writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1);
- writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2);
-}
-
-/**
* pcie_dw_set_host_bars() - Configure the host BARs
*
* @regs_base: A pointer to the PCIe controller registers
@@ -495,7 +509,18 @@ static int pcie_dw_mvebu_probe(struct udevice *dev)
hose->first_busno);
}
- pcie_dw_regions_setup(pcie);
+ /* Store the IO and MEM windows settings for future use by the ATU */
+ pcie->io.phys_start = hose->regions[0].phys_start; /* IO base */
+ pcie->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */
+ pcie->io.size = hose->regions[0].size; /* IO size */
+
+ pcie->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
+ pcie->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */
+ pcie->mem.size = hose->regions[1].size; /* MEM size */
+
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_MEM, pcie->mem.phys_start,
+ pcie->mem.bus_start, pcie->mem.size);
/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION,
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 3b9a09ce18..119edec204 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -59,6 +59,31 @@ config SPL_NOP_PHY
This is useful when a driver uses the PHY framework but no real PHY
hardware exists.
+config BCM6318_USBH_PHY
+ bool "BCM6318 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ select POWER_DOMAIN
+ help
+ Support for the Broadcom MIPS BCM6318 USBH PHY.
+
+config BCM6348_USBH_PHY
+ bool "BCM6348 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ help
+ Support for the Broadcom MIPS BCM6348 USBH PHY.
+
+config BCM6358_USBH_PHY
+ bool "BCM6358 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ help
+ Support for the Broadcom MIPS BCM6358 USBH PHY.
+
+config BCM6368_USBH_PHY
+ bool "BCM6368 USBH PHY support"
+ depends on PHY && ARCH_BMIPS
+ help
+ Support for the Broadcom MIPS BCM6368 USBH PHY.
+
config PIPE3_PHY
bool "Support omap's PIPE3 PHY"
depends on PHY && ARCH_OMAP2PLUS
@@ -85,4 +110,12 @@ config STI_USB_PHY
used by USB2 and USB3 Host controllers available on
STiH407 SoC families.
+config MESON_GXL_USB_PHY
+ bool "Amlogic Meson GXL USB PHYs"
+ depends on PHY && ARCH_MESON && MESON_GXL
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson GXL
+ USB2 and USB3 PHYS.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 668040b0bb..72c14921b0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,11 @@
obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
+obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
+obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
+obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
+obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o
obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o
obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o
obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o
+obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o
diff --git a/drivers/phy/bcm6318-usbh-phy.c b/drivers/phy/bcm6318-usbh-phy.c
new file mode 100644
index 0000000000..6d54214581
--- /dev/null
+++ b/drivers/phy/bcm6318-usbh-phy.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+/* USBH Setup register */
+#define USBH_SETUP_REG 0x00
+#define USBH_SETUP_IOC BIT(4)
+
+/* USBH PLL Control register */
+#define USBH_PLL_REG 0x04
+#define USBH_PLL_SUSP_EN BIT(27)
+#define USBH_PLL_IDDQ_PWRDN BIT(31)
+
+/* USBH Swap Control register */
+#define USBH_SWAP_REG 0x0c
+#define USBH_SWAP_OHCI_DATA BIT(0)
+#define USBH_SWAP_OHCI_ENDIAN BIT(1)
+#define USBH_SWAP_EHCI_DATA BIT(3)
+#define USBH_SWAP_EHCI_ENDIAN BIT(4)
+
+/* USBH Sim Control register */
+#define USBH_SIM_REG 0x20
+#define USBH_SIM_LADDR BIT(5)
+
+struct bcm6318_usbh_priv {
+ void __iomem *regs;
+};
+
+static int bcm6318_usbh_init(struct phy *phy)
+{
+ struct bcm6318_usbh_priv *priv = dev_get_priv(phy->dev);
+
+ /* enable pll control susp */
+ setbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_SUSP_EN);
+
+ /* configure to work in native cpu endian */
+ clrsetbits_be32(priv->regs + USBH_SWAP_REG,
+ USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
+ USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
+
+ /* setup config */
+ setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC);
+
+ /* disable pll control pwrdn */
+ clrbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_IDDQ_PWRDN);
+
+ /* sim control config */
+ setbits_be32(priv->regs + USBH_SIM_REG, USBH_SIM_LADDR);
+
+ return 0;
+}
+
+static struct phy_ops bcm6318_usbh_ops = {
+ .init = bcm6318_usbh_init,
+};
+
+static const struct udevice_id bcm6318_usbh_ids[] = {
+ { .compatible = "brcm,bcm6318-usbh" },
+ { /* sentinel */ }
+};
+
+static int bcm6318_usbh_probe(struct udevice *dev)
+{
+ struct bcm6318_usbh_priv *priv = dev_get_priv(dev);
+ struct power_domain pwr_dom;
+ struct reset_ctl rst_ctl;
+ struct clk clk;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int ret;
+
+ addr = devfdt_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ /* enable usbh clock */
+ ret = clk_get_by_name(dev, "usbh", &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+
+ /* enable power domain */
+ ret = power_domain_get(dev, &pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_on(&pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_free(&pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ mdelay(100);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6318_usbh) = {
+ .name = "bcm6318-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6318_usbh_ids,
+ .ops = &bcm6318_usbh_ops,
+ .priv_auto_alloc_size = sizeof(struct bcm6318_usbh_priv),
+ .probe = bcm6318_usbh_probe,
+};
diff --git a/drivers/phy/bcm6348-usbh-phy.c b/drivers/phy/bcm6348-usbh-phy.c
new file mode 100644
index 0000000000..169ee0ecec
--- /dev/null
+++ b/drivers/phy/bcm6348-usbh-phy.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+#define USBH_SETUP_PORT1_EN BIT(0)
+
+struct bcm6348_usbh_priv {
+ void __iomem *regs;
+};
+
+static int bcm6348_usbh_init(struct phy *phy)
+{
+ struct bcm6348_usbh_priv *priv = dev_get_priv(phy->dev);
+
+ writel_be(USBH_SETUP_PORT1_EN, priv->regs);
+
+ return 0;
+}
+
+static struct phy_ops bcm6348_usbh_ops = {
+ .init = bcm6348_usbh_init,
+};
+
+static const struct udevice_id bcm6348_usbh_ids[] = {
+ { .compatible = "brcm,bcm6348-usbh" },
+ { /* sentinel */ }
+};
+
+static int bcm6348_usbh_probe(struct udevice *dev)
+{
+ struct bcm6348_usbh_priv *priv = dev_get_priv(dev);
+ struct reset_ctl rst_ctl;
+ struct clk clk;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int ret;
+
+ addr = devfdt_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ /* enable usbh clock */
+ ret = clk_get_by_name(dev, "usbh", &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_usbh) = {
+ .name = "bcm6348-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6348_usbh_ids,
+ .ops = &bcm6348_usbh_ops,
+ .priv_auto_alloc_size = sizeof(struct bcm6348_usbh_priv),
+ .probe = bcm6348_usbh_probe,
+};
diff --git a/drivers/phy/bcm6358-usbh-phy.c b/drivers/phy/bcm6358-usbh-phy.c
new file mode 100644
index 0000000000..e000316a93
--- /dev/null
+++ b/drivers/phy/bcm6358-usbh-phy.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+/* USBH Swap Control register */
+#define USBH_SWAP_REG 0x00
+#define USBH_SWAP_OHCI_DATA BIT(0)
+#define USBH_SWAP_OHCI_ENDIAN BIT(1)
+#define USBH_SWAP_EHCI_DATA BIT(3)
+#define USBH_SWAP_EHCI_ENDIAN BIT(4)
+
+/* USBH Test register */
+#define USBH_TEST_REG 0x24
+#define USBH_TEST_PORT_CTL 0x1c0020
+
+struct bcm6358_usbh_priv {
+ void __iomem *regs;
+};
+
+static int bcm6358_usbh_init(struct phy *phy)
+{
+ struct bcm6358_usbh_priv *priv = dev_get_priv(phy->dev);
+
+ /* configure to work in native cpu endian */
+ clrsetbits_be32(priv->regs + USBH_SWAP_REG,
+ USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
+ USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
+
+ /* test port control */
+ writel_be(USBH_TEST_PORT_CTL, priv->regs + USBH_TEST_REG);
+
+ return 0;
+}
+
+static struct phy_ops bcm6358_usbh_ops = {
+ .init = bcm6358_usbh_init,
+};
+
+static const struct udevice_id bcm6358_usbh_ids[] = {
+ { .compatible = "brcm,bcm6358-usbh" },
+ { /* sentinel */ }
+};
+
+static int bcm6358_usbh_probe(struct udevice *dev)
+{
+ struct bcm6358_usbh_priv *priv = dev_get_priv(dev);
+ struct reset_ctl rst_ctl;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int ret;
+
+ addr = devfdt_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6358_usbh) = {
+ .name = "bcm6358-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6358_usbh_ids,
+ .ops = &bcm6358_usbh_ops,
+ .priv_auto_alloc_size = sizeof(struct bcm6358_usbh_priv),
+ .probe = bcm6358_usbh_probe,
+};
diff --git a/drivers/phy/bcm6368-usbh-phy.c b/drivers/phy/bcm6368-usbh-phy.c
new file mode 100644
index 0000000000..71abc0fcc4
--- /dev/null
+++ b/drivers/phy/bcm6368-usbh-phy.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/usb-common.c:
+ * Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright 2013 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+/* USBH PLL Control register */
+#define USBH_PLL_REG 0x18
+#define USBH_PLL_IDDQ_PWRDN BIT(9)
+#define USBH_PLL_PWRDN_DELAY BIT(10)
+
+/* USBH Swap Control register */
+#define USBH_SWAP_REG 0x1c
+#define USBH_SWAP_OHCI_DATA BIT(0)
+#define USBH_SWAP_OHCI_ENDIAN BIT(1)
+#define USBH_SWAP_EHCI_DATA BIT(3)
+#define USBH_SWAP_EHCI_ENDIAN BIT(4)
+
+/* USBH Setup register */
+#define USBH_SETUP_REG 0x28
+#define USBH_SETUP_IOC BIT(4)
+#define USBH_SETUP_IPP BIT(5)
+
+struct bcm6368_usbh_hw {
+ uint32_t setup_clr;
+ uint32_t pll_clr;
+};
+
+struct bcm6368_usbh_priv {
+ const struct bcm6368_usbh_hw *hw;
+ void __iomem *regs;
+};
+
+static int bcm6368_usbh_init(struct phy *phy)
+{
+ struct bcm6368_usbh_priv *priv = dev_get_priv(phy->dev);
+ const struct bcm6368_usbh_hw *hw = priv->hw;
+
+ /* configure to work in native cpu endian */
+ clrsetbits_be32(priv->regs + USBH_SWAP_REG,
+ USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
+ USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
+
+ /* setup config */
+ if (hw->setup_clr)
+ clrbits_be32(priv->regs + USBH_SETUP_REG, hw->setup_clr);
+
+ setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC);
+
+ /* enable pll control */
+ if (hw->pll_clr)
+ clrbits_be32(priv->regs + USBH_PLL_REG, hw->pll_clr);
+
+ return 0;
+}
+
+static struct phy_ops bcm6368_usbh_ops = {
+ .init = bcm6368_usbh_init,
+};
+
+static const struct bcm6368_usbh_hw bcm6328_hw = {
+ .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY,
+ .setup_clr = 0,
+};
+
+static const struct bcm6368_usbh_hw bcm6362_hw = {
+ .pll_clr = 0,
+ .setup_clr = 0,
+};
+
+static const struct bcm6368_usbh_hw bcm6368_hw = {
+ .pll_clr = 0,
+ .setup_clr = 0,
+};
+
+static const struct bcm6368_usbh_hw bcm63268_hw = {
+ .pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY,
+ .setup_clr = USBH_SETUP_IPP,
+};
+
+static const struct udevice_id bcm6368_usbh_ids[] = {
+ {
+ .compatible = "brcm,bcm6328-usbh",
+ .data = (ulong)&bcm6328_hw,
+ }, {
+ .compatible = "brcm,bcm6362-usbh",
+ .data = (ulong)&bcm6362_hw,
+ }, {
+ .compatible = "brcm,bcm6368-usbh",
+ .data = (ulong)&bcm6368_hw,
+ }, {
+ .compatible = "brcm,bcm63268-usbh",
+ .data = (ulong)&bcm63268_hw,
+ }, { /* sentinel */ }
+};
+
+static int bcm6368_usbh_probe(struct udevice *dev)
+{
+ struct bcm6368_usbh_priv *priv = dev_get_priv(dev);
+ const struct bcm6368_usbh_hw *hw =
+ (const struct bcm6368_usbh_hw *)dev_get_driver_data(dev);
+#if defined(CONFIG_POWER_DOMAIN)
+ struct power_domain pwr_dom;
+#endif
+ struct reset_ctl rst_ctl;
+ struct clk clk;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int ret;
+
+ addr = devfdt_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+ priv->hw = hw;
+
+ /* enable usbh clock */
+ ret = clk_get_by_name(dev, "usbh", &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+
+#if defined(CONFIG_POWER_DOMAIN)
+ /* enable power domain */
+ ret = power_domain_get(dev, &pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_on(&pwr_dom);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_free(&pwr_dom);
+ if (ret < 0)
+ return ret;
+#endif
+
+ /* perform reset */
+ ret = reset_get_by_index(dev, 0, &rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_deassert(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_free(&rst_ctl);
+ if (ret < 0)
+ return ret;
+
+ /* enable usb_ref clock */
+ ret = clk_get_by_name(dev, "usb_ref", &clk);
+ if (!ret) {
+ ret = clk_enable(&clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_free(&clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ mdelay(100);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6368_usbh) = {
+ .name = "bcm6368-usbh",
+ .id = UCLASS_PHY,
+ .of_match = bcm6368_usbh_ids,
+ .ops = &bcm6368_usbh_ops,
+ .priv_auto_alloc_size = sizeof(struct bcm6368_usbh_priv),
+ .probe = bcm6368_usbh_probe,
+};
diff --git a/drivers/phy/meson-gxl-usb2.c b/drivers/phy/meson-gxl-usb2.c
new file mode 100644
index 0000000000..15c9c89fd9
--- /dev/null
+++ b/drivers/phy/meson-gxl-usb2.c
@@ -0,0 +1,238 @@
+/*
+ * Meson GXL and GXM USB2 PHY driver
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <power/regulator.h>
+#include <clk.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* bits [31:27] are read-only */
+#define U2P_R0 0x0
+ #define U2P_R0_BYPASS_SEL BIT(0)
+ #define U2P_R0_BYPASS_DM_EN BIT(1)
+ #define U2P_R0_BYPASS_DP_EN BIT(2)
+ #define U2P_R0_TXBITSTUFF_ENH BIT(3)
+ #define U2P_R0_TXBITSTUFF_EN BIT(4)
+ #define U2P_R0_DM_PULLDOWN BIT(5)
+ #define U2P_R0_DP_PULLDOWN BIT(6)
+ #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
+ #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
+ #define U2P_R0_ADP_PRB_EN BIT(9)
+ #define U2P_R0_ADP_DISCHARGE BIT(10)
+ #define U2P_R0_ADP_CHARGE BIT(11)
+ #define U2P_R0_DRV_VBUS BIT(12)
+ #define U2P_R0_ID_PULLUP BIT(13)
+ #define U2P_R0_LOOPBACK_EN_B BIT(14)
+ #define U2P_R0_OTG_DISABLE BIT(15)
+ #define U2P_R0_COMMON_ONN BIT(16)
+ #define U2P_R0_FSEL_MASK GENMASK(19, 17)
+ #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
+ #define U2P_R0_POWER_ON_RESET BIT(22)
+ #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
+ #define U2P_R0_ID_SET_ID_DQ BIT(25)
+ #define U2P_R0_ATE_RESET BIT(26)
+ #define U2P_R0_FSV_MINUS BIT(27)
+ #define U2P_R0_FSV_PLUS BIT(28)
+ #define U2P_R0_BYPASS_DM_DATA BIT(29)
+ #define U2P_R0_BYPASS_DP_DATA BIT(30)
+
+#define U2P_R1 0x4
+ #define U2P_R1_BURN_IN_TEST BIT(0)
+ #define U2P_R1_ACA_ENABLE BIT(1)
+ #define U2P_R1_DCD_ENABLE BIT(2)
+ #define U2P_R1_VDAT_SRC_EN_B BIT(3)
+ #define U2P_R1_VDAT_DET_EN_B BIT(4)
+ #define U2P_R1_CHARGES_SEL BIT(5)
+ #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
+ #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
+ #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
+ #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
+ #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
+ #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
+ #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
+ #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
+ #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
+ #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
+
+/* bits [31:14] are read-only */
+#define U2P_R2 0x8
+ #define U2P_R2_TESTDATA_IN_MASK GENMASK(7, 0)
+ #define U2P_R2_TESTADDR_MASK GENMASK(11, 8)
+ #define U2P_R2_TESTDATA_OUT_SEL BIT(12)
+ #define U2P_R2_TESTCLK BIT(13)
+ #define U2P_R2_TESTDATA_OUT_MASK GENMASK(17, 14)
+ #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
+ #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
+ #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
+ #define U2P_R2_ACA_PIN_GND BIT(21)
+ #define U2P_R2_ACA_PIN_FLOAT BIT(22)
+ #define U2P_R2_CHARGE_DETECT BIT(23)
+ #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
+ #define U2P_R2_ADP_PROBE BIT(25)
+ #define U2P_R2_ADP_SENSE BIT(26)
+ #define U2P_R2_SESSION_END BIT(27)
+ #define U2P_R2_VBUS_VALID BIT(28)
+ #define U2P_R2_B_VALID BIT(29)
+ #define U2P_R2_A_VALID BIT(30)
+ #define U2P_R2_ID_DIG BIT(31)
+
+#define U2P_R3 0xc
+
+#define RESET_COMPLETE_TIME 500
+
+struct phy_meson_gxl_usb2_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *phy_supply;
+#endif
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+};
+
+static void phy_meson_gxl_usb2_reset(struct phy_meson_gxl_usb2_priv *priv)
+{
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+
+ /* reset the PHY and wait until settings are stabilized */
+ val |= U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+ udelay(RESET_COMPLETE_TIME);
+
+ val &= ~U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+ udelay(RESET_COMPLETE_TIME);
+}
+
+static void
+phy_meson_gxl_usb2_set_host_mode(struct phy_meson_gxl_usb2_priv *priv)
+{
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+ val |= U2P_R0_DM_PULLDOWN;
+ val |= U2P_R0_DP_PULLDOWN;
+ val &= ~U2P_R0_ID_PULLUP;
+ regmap_write(priv->regmap, U2P_R0, val);
+
+ phy_meson_gxl_usb2_reset(priv);
+}
+
+static int phy_meson_gxl_usb2_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+ /* power on the PHY by taking it out of reset mode */
+ val &= ~U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+
+ phy_meson_gxl_usb2_set_host_mode(priv);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, true);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, U2P_R0, &val);
+ /* power off the PHY by putting it into reset mode */
+ val |= U2P_R0_POWER_ON_RESET;
+ regmap_write(priv->regmap, U2P_R0, val);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (priv->phy_supply) {
+ int ret = regulator_set_enable(priv->phy_supply, false);
+ if (ret) {
+ pr_err("Error disabling PHY supply\n");
+ return ret;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+struct phy_ops meson_gxl_usb2_phy_ops = {
+ .power_on = phy_meson_gxl_usb2_power_on,
+ .power_off = phy_meson_gxl_usb2_power_off,
+};
+
+int meson_gxl_usb2_phy_probe(struct udevice *dev)
+{
+ struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev, &priv->regmap);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ ret = device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get PHY regulator\n");
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id meson_gxl_usb2_phy_ids[] = {
+ { .compatible = "amlogic,meson-gxl-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_gxl_usb2_phy) = {
+ .name = "meson_gxl_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_gxl_usb2_phy_ids,
+ .probe = meson_gxl_usb2_phy_probe,
+ .ops = &meson_gxl_usb2_phy_ops,
+ .priv_auto_alloc_size = sizeof(struct phy_meson_gxl_usb2_priv),
+};
diff --git a/drivers/phy/meson-gxl-usb3.c b/drivers/phy/meson-gxl-usb3.c
new file mode 100644
index 0000000000..a385fbdf12
--- /dev/null
+++ b/drivers/phy/meson-gxl-usb3.c
@@ -0,0 +1,201 @@
+/*
+ * Meson GXL USB3 PHY driver
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <bitfield.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <clk.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/bitfield.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define USB_R0 0x00
+ #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
+ #define USB_R0_P30_PHY_RESET BIT(6)
+ #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
+ #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
+ #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
+ #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
+ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
+ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
+ #define USB_R0_U2D_ACT BIT(31)
+
+#define USB_R1 0x04
+ #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
+ #define USB_R1_U3H_PME_ENABLE BIT(1)
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
+ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
+ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
+ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
+ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
+
+#define USB_R2 0x08
+ #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
+ #define USB_R2_P30_CR_READ BIT(16)
+ #define USB_R2_P30_CR_WRITE BIT(17)
+ #define USB_R2_P30_CR_CAP_ADDR BIT(18)
+ #define USB_R2_P30_CR_CAP_DATA BIT(19)
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
+
+#define USB_R3 0x0c
+ #define USB_R3_P30_SSC_ENABLE BIT(0)
+ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
+ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
+ #define USB_R3_P30_REF_SSP_EN BIT(13)
+ #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
+ #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
+ #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
+
+#define USB_R4 0x10
+ #define USB_R4_P21_PORT_RESET_0 BIT(0)
+ #define USB_R4_P21_SLEEP_M0 BIT(1)
+ #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
+ #define USB_R4_P21_ONLY BIT(4)
+
+#define USB_R5 0x14
+ #define USB_R5_ID_DIG_SYNC BIT(0)
+ #define USB_R5_ID_DIG_REG BIT(1)
+ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
+ #define USB_R5_ID_DIG_EN_0 BIT(4)
+ #define USB_R5_ID_DIG_EN_1 BIT(5)
+ #define USB_R5_ID_DIG_CURR BIT(6)
+ #define USB_R5_ID_DIG_IRQ BIT(7)
+ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
+ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
+
+/* read-only register */
+#define USB_R6 0x18
+ #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
+ #define USB_R6_P30_CR_ACK BIT(16)
+
+struct phy_meson_gxl_usb3_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+};
+
+static int
+phy_meson_gxl_usb3_set_host_mode(struct phy_meson_gxl_usb3_priv *priv)
+{
+ uint val;
+
+ regmap_read(priv->regmap, USB_R0, &val);
+ val &= ~USB_R0_U2D_ACT;
+ regmap_write(priv->regmap, USB_R0, val);
+
+ regmap_read(priv->regmap, USB_R4, &val);
+ val &= ~USB_R4_P21_SLEEP_M0;
+ regmap_write(priv->regmap, USB_R4, val);
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, USB_R5, &val);
+ val |= USB_R5_ID_DIG_EN_0;
+ val |= USB_R5_ID_DIG_EN_1;
+ val &= ~USB_R5_ID_DIG_TH_MASK;
+ val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff);
+ regmap_write(priv->regmap, USB_R5, val);
+
+ return phy_meson_gxl_usb3_set_host_mode(priv);
+}
+
+static int phy_meson_gxl_usb3_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, USB_R5, &val);
+ val &= ~USB_R5_ID_DIG_EN_0;
+ val &= ~USB_R5_ID_DIG_EN_1;
+ regmap_write(priv->regmap, USB_R5, val);
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
+ uint val;
+
+ regmap_read(priv->regmap, USB_R1, &val);
+ val &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK;
+ val |= FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20);
+ regmap_write(priv->regmap, USB_R1, val);
+
+ return 0;
+}
+
+struct phy_ops meson_gxl_usb3_phy_ops = {
+ .init = phy_meson_gxl_usb3_init,
+ .power_on = phy_meson_gxl_usb3_power_on,
+ .power_off = phy_meson_gxl_usb3_power_off,
+};
+
+int meson_gxl_usb3_phy_probe(struct udevice *dev)
+{
+ struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev, &priv->regmap);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id meson_gxl_usb3_phy_ids[] = {
+ { .compatible = "amlogic,meson-gxl-usb3-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_gxl_usb3_phy) = {
+ .name = "meson_gxl_usb3_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_gxl_usb3_phy_ids,
+ .probe = meson_gxl_usb3_phy_probe,
+ .ops = &meson_gxl_usb3_phy_ops,
+ .priv_auto_alloc_size = sizeof(struct phy_meson_gxl_usb3_priv),
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 2bf853eba1..010eb203b7 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -44,7 +44,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IRQ_STATUS 0x10
#define IRQ_WKUP 0x18
-#define NB_FUNCS 2
+#define NB_FUNCS 3
#define GPIO_PER_REG 32
/**
@@ -128,6 +128,16 @@ struct armada_37xx_pinctrl {
.funcs = {_func1, "gpio"} \
}
+#define PIN_GRP_GPIO_3(_name, _start, _nr, _mask, _v1, _v2, _v3, _f1, _f2) \
+ { \
+ .name = _name, \
+ .start_pin = _start, \
+ .npins = _nr, \
+ .reg_mask = _mask, \
+ .val = {_v1, _v2, _v3}, \
+ .funcs = {_f1, _f2, "gpio"} \
+ }
+
#define PIN_GRP_EXTRA(_name, _start, _nr, _mask, _v1, _v2, _start2, _nr2, \
_f1, _f2) \
{ \
@@ -149,8 +159,8 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
PIN_GRP_GPIO("pwm1", 12, 1, BIT(4), "pwm"),
PIN_GRP_GPIO("pwm2", 13, 1, BIT(5), "pwm"),
PIN_GRP_GPIO("pwm3", 14, 1, BIT(6), "pwm"),
- PIN_GRP_GPIO("pmic1", 17, 1, BIT(7), "pmic"),
- PIN_GRP_GPIO("pmic0", 16, 1, BIT(8), "pmic"),
+ PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"),
+ PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"),
PIN_GRP_GPIO("i2c2", 2, 2, BIT(9), "i2c"),
PIN_GRP_GPIO("i2c1", 0, 2, BIT(10), "i2c"),
PIN_GRP_GPIO("spi_cs1", 17, 1, BIT(12), "spi"),
@@ -172,13 +182,15 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
static struct armada_37xx_pin_group armada_37xx_sb_groups[] = {
PIN_GRP_GPIO("usb32_drvvbus0", 0, 1, BIT(0), "drvbus"),
PIN_GRP_GPIO("usb2_drvvbus1", 1, 1, BIT(1), "drvbus"),
- PIN_GRP_GPIO("sdio_sb", 24, 5, BIT(2), "sdio"),
- PIN_GRP_EXTRA("rgmii", 6, 14, BIT(3), 0, BIT(3), 23, 1, "mii", "gpio"),
- PIN_GRP_GPIO("pcie1", 3, 2, BIT(4), "pcie"),
- PIN_GRP_GPIO("ptp", 20, 3, BIT(5), "ptp"),
+ PIN_GRP_GPIO("sdio_sb", 24, 6, BIT(2), "sdio"),
+ PIN_GRP_GPIO("rgmii", 6, 12, BIT(3), "mii"),
+ PIN_GRP_GPIO("smi", 18, 2, BIT(4), "smi"),
+ PIN_GRP_GPIO("pcie1", 3, 3, BIT(5) | BIT(9) | BIT(10), "pcie"),
+ PIN_GRP_GPIO("ptp", 20, 3, BIT(11) | BIT(12) | BIT(13), "ptp"),
PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"),
PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"),
- PIN_GRP("mii_col", 23, 1, BIT(8), "mii", "mii_err"),
+ PIN_GRP_GPIO_3("mii_col", 23, 1, BIT(8) | BIT(14), 0, BIT(8), BIT(14),
+ "mii", "mii_err"),
};
const struct armada_37xx_pin_data armada_37xx_pin_nb = {
@@ -189,18 +201,18 @@ const struct armada_37xx_pin_data armada_37xx_pin_nb = {
};
const struct armada_37xx_pin_data armada_37xx_pin_sb = {
- .nr_pins = 29,
+ .nr_pins = 30,
.name = "GPIO2",
.groups = armada_37xx_sb_groups,
.ngroups = ARRAY_SIZE(armada_37xx_sb_groups),
};
static inline void armada_37xx_update_reg(unsigned int *reg,
- unsigned int offset)
+ unsigned int *offset)
{
/* We never have more than 2 registers */
- if (offset >= GPIO_PER_REG) {
- offset -= GPIO_PER_REG;
+ if (*offset >= GPIO_PER_REG) {
+ *offset -= GPIO_PER_REG;
*reg += sizeof(u32);
}
}
@@ -210,7 +222,7 @@ static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
{
int f;
- for (f = 0; f < NB_FUNCS; f++)
+ for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++)
if (!strcmp(grp->funcs[f], func))
return f;
@@ -352,7 +364,7 @@ static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info)
for (j = 0; j < grp->extra_npins; j++)
grp->pins[i+j] = grp->extra_pin + j;
- for (f = 0; f < NB_FUNCS; f++) {
+ for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++) {
int ret;
/* check for unique functions and count groups */
ret = armada_37xx_add_function(info->funcs, &funcsize,
@@ -404,7 +416,7 @@ static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
struct armada_37xx_pin_group *gp = &info->groups[g];
int f;
- for (f = 0; f < NB_FUNCS; f++) {
+ for (f = 0; (f < NB_FUNCS) && gp->funcs[f]; f++) {
if (strcmp(gp->funcs[f], name) == 0) {
*groups = gp->name;
groups++;
@@ -421,7 +433,7 @@ static int armada_37xx_gpio_get(struct udevice *dev, unsigned int offset)
unsigned int reg = INPUT_VAL;
unsigned int val, mask;
- armada_37xx_update_reg(&reg, offset);
+ armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
val = readl(info->base + reg);
@@ -436,7 +448,7 @@ static int armada_37xx_gpio_set(struct udevice *dev, unsigned int offset,
unsigned int reg = OUTPUT_VAL;
unsigned int mask, val;
- armada_37xx_update_reg(&reg, offset);
+ armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
val = value ? mask : 0;
@@ -452,7 +464,7 @@ static int armada_37xx_gpio_get_direction(struct udevice *dev,
unsigned int reg = OUTPUT_EN;
unsigned int val, mask;
- armada_37xx_update_reg(&reg, offset);
+ armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
val = readl(info->base + reg);
@@ -469,7 +481,7 @@ static int armada_37xx_gpio_direction_input(struct udevice *dev,
unsigned int reg = OUTPUT_EN;
unsigned int mask;
- armada_37xx_update_reg(&reg, offset);
+ armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
clrbits_le32(info->base + reg, mask);
@@ -484,7 +496,7 @@ static int armada_37xx_gpio_direction_output(struct udevice *dev,
unsigned int reg = OUTPUT_EN;
unsigned int mask;
- armada_37xx_update_reg(&reg, offset);
+ armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
setbits_le32(info->base + reg, mask);
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index 6a73a0679b..a0a326a142 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -12,6 +12,7 @@
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/util.h>
+#include <dm/of_access.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -63,16 +64,13 @@ static int pinctrl_config_one(struct udevice *config)
*/
static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
{
- const void *fdt = gd->fdt_blob;
- int node = dev_of_offset(dev);
char propname[32]; /* long enough */
const fdt32_t *list;
uint32_t phandle;
- int config_node;
struct udevice *config;
int state, size, i, ret;
- state = fdt_stringlist_search(fdt, node, "pinctrl-names", statename);
+ state = dev_read_stringlist_search(dev, "pinctrl-names", statename);
if (state < 0) {
char *end;
/*
@@ -85,22 +83,15 @@ static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
}
snprintf(propname, sizeof(propname), "pinctrl-%d", state);
- list = fdt_getprop(fdt, node, propname, &size);
+ list = dev_read_prop(dev, propname, &size);
if (!list)
return -EINVAL;
size /= sizeof(*list);
for (i = 0; i < size; i++) {
phandle = fdt32_to_cpu(*list++);
-
- config_node = fdt_node_offset_by_phandle(fdt, phandle);
- if (config_node < 0) {
- dev_err(dev, "prop %s index %d invalid phandle\n",
- propname, i);
- return -EINVAL;
- }
- ret = uclass_get_device_by_of_offset(UCLASS_PINCONFIG,
- config_node, &config);
+ ret = uclass_get_device_by_phandle_id(UCLASS_PINCONFIG, phandle,
+ &config);
if (ret)
return ret;
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
index 2066e11cf1..31285cdd57 100644
--- a/drivers/pinctrl/pinctrl_stm32.c
+++ b/drivers/pinctrl/pinctrl_stm32.c
@@ -41,9 +41,10 @@ static int stm32_gpio_config(struct gpio_desc *desc,
return 0;
}
+
static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin)
{
- gpio_dsc->port = (port_pin & 0xF000) >> 12;
+ gpio_dsc->port = (port_pin & 0x1F000) >> 12;
gpio_dsc->pin = (port_pin & 0x0F00) >> 8;
debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port,
gpio_dsc->pin);
@@ -115,11 +116,13 @@ static int stm32_pinctrl_config(int offset)
return -EINVAL;
for (i = 0; i < len; i++) {
struct gpio_desc desc;
+
debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), offset);
rv = uclass_get_device_by_seq(UCLASS_GPIO,
- gpio_dsc.port, &desc.dev);
+ gpio_dsc.port,
+ &desc.dev);
if (rv)
return rv;
desc.offset = gpio_dsc.pin;
@@ -186,6 +189,8 @@ static const struct udevice_id stm32_pinctrl_ids[] = {
{ .compatible = "st,stm32f469-pinctrl" },
{ .compatible = "st,stm32f746-pinctrl" },
{ .compatible = "st,stm32h743-pinctrl" },
+ { .compatible = "st,stm32mp157-pinctrl" },
+ { .compatible = "st,stm32mp157-z-pinctrl" },
{ }
};
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3036.c b/drivers/pinctrl/rockchip/pinctrl_rk3036.c
index 94f6d7ad40..7e93d85dbb 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3036.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3036.c
@@ -18,6 +18,416 @@
DECLARE_GLOBAL_DATA_PTR;
+/* GRF_GPIO0A_IOMUX */
+enum {
+ GPIO0A3_SHIFT = 6,
+ GPIO0A3_MASK = 1 << GPIO0A3_SHIFT,
+ GPIO0A3_GPIO = 0,
+ GPIO0A3_I2C1_SDA,
+
+ GPIO0A2_SHIFT = 4,
+ GPIO0A2_MASK = 1 << GPIO0A2_SHIFT,
+ GPIO0A2_GPIO = 0,
+ GPIO0A2_I2C1_SCL,
+
+ GPIO0A1_SHIFT = 2,
+ GPIO0A1_MASK = 3 << GPIO0A1_SHIFT,
+ GPIO0A1_GPIO = 0,
+ GPIO0A1_I2C0_SDA,
+ GPIO0A1_PWM2,
+
+ GPIO0A0_SHIFT = 0,
+ GPIO0A0_MASK = 3 << GPIO0A0_SHIFT,
+ GPIO0A0_GPIO = 0,
+ GPIO0A0_I2C0_SCL,
+ GPIO0A0_PWM1,
+};
+
+/* GRF_GPIO0B_IOMUX */
+enum {
+ GPIO0B6_SHIFT = 12,
+ GPIO0B6_MASK = 3 << GPIO0B6_SHIFT,
+ GPIO0B6_GPIO = 0,
+ GPIO0B6_MMC1_D3,
+ GPIO0B6_I2S1_SCLK,
+
+ GPIO0B5_SHIFT = 10,
+ GPIO0B5_MASK = 3 << GPIO0B5_SHIFT,
+ GPIO0B5_GPIO = 0,
+ GPIO0B5_MMC1_D2,
+ GPIO0B5_I2S1_SDI,
+
+ GPIO0B4_SHIFT = 8,
+ GPIO0B4_MASK = 3 << GPIO0B4_SHIFT,
+ GPIO0B4_GPIO = 0,
+ GPIO0B4_MMC1_D1,
+ GPIO0B4_I2S1_LRCKTX,
+
+ GPIO0B3_SHIFT = 6,
+ GPIO0B3_MASK = 3 << GPIO0B3_SHIFT,
+ GPIO0B3_GPIO = 0,
+ GPIO0B3_MMC1_D0,
+ GPIO0B3_I2S1_LRCKRX,
+
+ GPIO0B1_SHIFT = 2,
+ GPIO0B1_MASK = 3 << GPIO0B1_SHIFT,
+ GPIO0B1_GPIO = 0,
+ GPIO0B1_MMC1_CLKOUT,
+ GPIO0B1_I2S1_MCLK,
+
+ GPIO0B0_SHIFT = 0,
+ GPIO0B0_MASK = 3,
+ GPIO0B0_GPIO = 0,
+ GPIO0B0_MMC1_CMD,
+ GPIO0B0_I2S1_SDO,
+};
+
+/* GRF_GPIO0C_IOMUX */
+enum {
+ GPIO0C4_SHIFT = 8,
+ GPIO0C4_MASK = 1 << GPIO0C4_SHIFT,
+ GPIO0C4_GPIO = 0,
+ GPIO0C4_DRIVE_VBUS,
+
+ GPIO0C3_SHIFT = 6,
+ GPIO0C3_MASK = 1 << GPIO0C3_SHIFT,
+ GPIO0C3_GPIO = 0,
+ GPIO0C3_UART0_CTSN,
+
+ GPIO0C2_SHIFT = 4,
+ GPIO0C2_MASK = 1 << GPIO0C2_SHIFT,
+ GPIO0C2_GPIO = 0,
+ GPIO0C2_UART0_RTSN,
+
+ GPIO0C1_SHIFT = 2,
+ GPIO0C1_MASK = 1 << GPIO0C1_SHIFT,
+ GPIO0C1_GPIO = 0,
+ GPIO0C1_UART0_SIN,
+
+
+ GPIO0C0_SHIFT = 0,
+ GPIO0C0_MASK = 1 << GPIO0C0_SHIFT,
+ GPIO0C0_GPIO = 0,
+ GPIO0C0_UART0_SOUT,
+};
+
+/* GRF_GPIO0D_IOMUX */
+enum {
+ GPIO0D4_SHIFT = 8,
+ GPIO0D4_MASK = 1 << GPIO0D4_SHIFT,
+ GPIO0D4_GPIO = 0,
+ GPIO0D4_SPDIF,
+
+ GPIO0D3_SHIFT = 6,
+ GPIO0D3_MASK = 1 << GPIO0D3_SHIFT,
+ GPIO0D3_GPIO = 0,
+ GPIO0D3_PWM3,
+
+ GPIO0D2_SHIFT = 4,
+ GPIO0D2_MASK = 1 << GPIO0D2_SHIFT,
+ GPIO0D2_GPIO = 0,
+ GPIO0D2_PWM0,
+};
+
+/* GRF_GPIO1A_IOMUX */
+enum {
+ GPIO1A5_SHIFT = 10,
+ GPIO1A5_MASK = 1 << GPIO1A5_SHIFT,
+ GPIO1A5_GPIO = 0,
+ GPIO1A5_I2S_SDI,
+
+ GPIO1A4_SHIFT = 8,
+ GPIO1A4_MASK = 1 << GPIO1A4_SHIFT,
+ GPIO1A4_GPIO = 0,
+ GPIO1A4_I2S_SD0,
+
+ GPIO1A3_SHIFT = 6,
+ GPIO1A3_MASK = 1 << GPIO1A3_SHIFT,
+ GPIO1A3_GPIO = 0,
+ GPIO1A3_I2S_LRCKTX,
+
+ GPIO1A2_SHIFT = 4,
+ GPIO1A2_MASK = 3 << GPIO1A2_SHIFT,
+ GPIO1A2_GPIO = 0,
+ GPIO1A2_I2S_LRCKRX,
+ GPIO1A2_PWM1_0,
+
+ GPIO1A1_SHIFT = 2,
+ GPIO1A1_MASK = 1 << GPIO1A1_SHIFT,
+ GPIO1A1_GPIO = 0,
+ GPIO1A1_I2S_SCLK,
+
+ GPIO1A0_SHIFT = 0,
+ GPIO1A0_MASK = 1 << GPIO1A0_SHIFT,
+ GPIO1A0_GPIO = 0,
+ GPIO1A0_I2S_MCLK,
+
+};
+
+/* GRF_GPIO1B_IOMUX */
+enum {
+ GPIO1B7_SHIFT = 14,
+ GPIO1B7_MASK = 1 << GPIO1B7_SHIFT,
+ GPIO1B7_GPIO = 0,
+ GPIO1B7_MMC0_CMD,
+
+ GPIO1B3_SHIFT = 6,
+ GPIO1B3_MASK = 1 << GPIO1B3_SHIFT,
+ GPIO1B3_GPIO = 0,
+ GPIO1B3_HDMI_HPD,
+
+ GPIO1B2_SHIFT = 4,
+ GPIO1B2_MASK = 1 << GPIO1B2_SHIFT,
+ GPIO1B2_GPIO = 0,
+ GPIO1B2_HDMI_SCL,
+
+ GPIO1B1_SHIFT = 2,
+ GPIO1B1_MASK = 1 << GPIO1B1_SHIFT,
+ GPIO1B1_GPIO = 0,
+ GPIO1B1_HDMI_SDA,
+
+ GPIO1B0_SHIFT = 0,
+ GPIO1B0_MASK = 1 << GPIO1B0_SHIFT,
+ GPIO1B0_GPIO = 0,
+ GPIO1B0_HDMI_CEC,
+};
+
+/* GRF_GPIO1C_IOMUX */
+enum {
+ GPIO1C5_SHIFT = 10,
+ GPIO1C5_MASK = 3 << GPIO1C5_SHIFT,
+ GPIO1C5_GPIO = 0,
+ GPIO1C5_MMC0_D3,
+ GPIO1C5_JTAG_TMS,
+
+ GPIO1C4_SHIFT = 8,
+ GPIO1C4_MASK = 3 << GPIO1C4_SHIFT,
+ GPIO1C4_GPIO = 0,
+ GPIO1C4_MMC0_D2,
+ GPIO1C4_JTAG_TCK,
+
+ GPIO1C3_SHIFT = 6,
+ GPIO1C3_MASK = 3 << GPIO1C3_SHIFT,
+ GPIO1C3_GPIO = 0,
+ GPIO1C3_MMC0_D1,
+ GPIO1C3_UART2_SOUT,
+
+ GPIO1C2_SHIFT = 4,
+ GPIO1C2_MASK = 3 << GPIO1C2_SHIFT ,
+ GPIO1C2_GPIO = 0,
+ GPIO1C2_MMC0_D0,
+ GPIO1C2_UART2_SIN,
+
+ GPIO1C1_SHIFT = 2,
+ GPIO1C1_MASK = 1 << GPIO1C1_SHIFT,
+ GPIO1C1_GPIO = 0,
+ GPIO1C1_MMC0_DETN,
+
+ GPIO1C0_SHIFT = 0,
+ GPIO1C0_MASK = 1 << GPIO1C0_SHIFT,
+ GPIO1C0_GPIO = 0,
+ GPIO1C0_MMC0_CLKOUT,
+};
+
+/* GRF_GPIO1D_IOMUX */
+enum {
+ GPIO1D7_SHIFT = 14,
+ GPIO1D7_MASK = 3 << GPIO1D7_SHIFT,
+ GPIO1D7_GPIO = 0,
+ GPIO1D7_NAND_D7,
+ GPIO1D7_EMMC_D7,
+ GPIO1D7_SPI_CSN1,
+
+ GPIO1D6_SHIFT = 12,
+ GPIO1D6_MASK = 3 << GPIO1D6_SHIFT,
+ GPIO1D6_GPIO = 0,
+ GPIO1D6_NAND_D6,
+ GPIO1D6_EMMC_D6,
+ GPIO1D6_SPI_CSN0,
+
+ GPIO1D5_SHIFT = 10,
+ GPIO1D5_MASK = 3 << GPIO1D5_SHIFT,
+ GPIO1D5_GPIO = 0,
+ GPIO1D5_NAND_D5,
+ GPIO1D5_EMMC_D5,
+ GPIO1D5_SPI_TXD,
+
+ GPIO1D4_SHIFT = 8,
+ GPIO1D4_MASK = 3 << GPIO1D4_SHIFT,
+ GPIO1D4_GPIO = 0,
+ GPIO1D4_NAND_D4,
+ GPIO1D4_EMMC_D4,
+ GPIO1D4_SPI_RXD,
+
+ GPIO1D3_SHIFT = 6,
+ GPIO1D3_MASK = 3 << GPIO1D3_SHIFT,
+ GPIO1D3_GPIO = 0,
+ GPIO1D3_NAND_D3,
+ GPIO1D3_EMMC_D3,
+ GPIO1D3_SFC_SIO3,
+
+ GPIO1D2_SHIFT = 4,
+ GPIO1D2_MASK = 3 << GPIO1D2_SHIFT,
+ GPIO1D2_GPIO = 0,
+ GPIO1D2_NAND_D2,
+ GPIO1D2_EMMC_D2,
+ GPIO1D2_SFC_SIO2,
+
+ GPIO1D1_SHIFT = 2,
+ GPIO1D1_MASK = 3 << GPIO1D1_SHIFT,
+ GPIO1D1_GPIO = 0,
+ GPIO1D1_NAND_D1,
+ GPIO1D1_EMMC_D1,
+ GPIO1D1_SFC_SIO1,
+
+ GPIO1D0_SHIFT = 0,
+ GPIO1D0_MASK = 3 << GPIO1D0_SHIFT,
+ GPIO1D0_GPIO = 0,
+ GPIO1D0_NAND_D0,
+ GPIO1D0_EMMC_D0,
+ GPIO1D0_SFC_SIO0,
+};
+
+/* GRF_GPIO2A_IOMUX */
+enum {
+ GPIO2A7_SHIFT = 14,
+ GPIO2A7_MASK = 1 << GPIO2A7_SHIFT,
+ GPIO2A7_GPIO = 0,
+ GPIO2A7_TESTCLK_OUT,
+
+ GPIO2A6_SHIFT = 12,
+ GPIO2A6_MASK = 1 << GPIO2A6_SHIFT,
+ GPIO2A6_GPIO = 0,
+ GPIO2A6_NAND_CS0,
+
+ GPIO2A4_SHIFT = 8,
+ GPIO2A4_MASK = 3 << GPIO2A4_SHIFT,
+ GPIO2A4_GPIO = 0,
+ GPIO2A4_NAND_RDY,
+ GPIO2A4_EMMC_CMD,
+ GPIO2A3_SFC_CLK,
+
+ GPIO2A3_SHIFT = 6,
+ GPIO2A3_MASK = 3 << GPIO2A3_SHIFT,
+ GPIO2A3_GPIO = 0,
+ GPIO2A3_NAND_RDN,
+ GPIO2A4_SFC_CSN1,
+
+ GPIO2A2_SHIFT = 4,
+ GPIO2A2_MASK = 3 << GPIO2A2_SHIFT,
+ GPIO2A2_GPIO = 0,
+ GPIO2A2_NAND_WRN,
+ GPIO2A4_SFC_CSN0,
+
+ GPIO2A1_SHIFT = 2,
+ GPIO2A1_MASK = 3 << GPIO2A1_SHIFT,
+ GPIO2A1_GPIO = 0,
+ GPIO2A1_NAND_CLE,
+ GPIO2A1_EMMC_CLKOUT,
+
+ GPIO2A0_SHIFT = 0,
+ GPIO2A0_MASK = 3 << GPIO2A0_SHIFT,
+ GPIO2A0_GPIO = 0,
+ GPIO2A0_NAND_ALE,
+ GPIO2A0_SPI_CLK,
+};
+
+/* GRF_GPIO2B_IOMUX */
+enum {
+ GPIO2B7_SHIFT = 14,
+ GPIO2B7_MASK = 1 << GPIO2B7_SHIFT,
+ GPIO2B7_GPIO = 0,
+ GPIO2B7_MAC_RXER,
+
+ GPIO2B6_SHIFT = 12,
+ GPIO2B6_MASK = 3 << GPIO2B6_SHIFT,
+ GPIO2B6_GPIO = 0,
+ GPIO2B6_MAC_CLKOUT,
+ GPIO2B6_MAC_CLKIN,
+
+ GPIO2B5_SHIFT = 10,
+ GPIO2B5_MASK = 1 << GPIO2B5_SHIFT,
+ GPIO2B5_GPIO = 0,
+ GPIO2B5_MAC_TXEN,
+
+ GPIO2B4_SHIFT = 8,
+ GPIO2B4_MASK = 1 << GPIO2B4_SHIFT,
+ GPIO2B4_GPIO = 0,
+ GPIO2B4_MAC_MDIO,
+
+ GPIO2B2_SHIFT = 4,
+ GPIO2B2_MASK = 1 << GPIO2B2_SHIFT,
+ GPIO2B2_GPIO = 0,
+ GPIO2B2_MAC_CRS,
+};
+
+/* GRF_GPIO2C_IOMUX */
+enum {
+ GPIO2C7_SHIFT = 14,
+ GPIO2C7_MASK = 3 << GPIO2C7_SHIFT,
+ GPIO2C7_GPIO = 0,
+ GPIO2C7_UART1_SOUT,
+ GPIO2C7_TESTCLK_OUT1,
+
+ GPIO2C6_SHIFT = 12,
+ GPIO2C6_MASK = 1 << GPIO2C6_SHIFT,
+ GPIO2C6_GPIO = 0,
+ GPIO2C6_UART1_SIN,
+
+ GPIO2C5_SHIFT = 10,
+ GPIO2C5_MASK = 1 << GPIO2C5_SHIFT,
+ GPIO2C5_GPIO = 0,
+ GPIO2C5_I2C2_SCL,
+
+ GPIO2C4_SHIFT = 8,
+ GPIO2C4_MASK = 1 << GPIO2C4_SHIFT,
+ GPIO2C4_GPIO = 0,
+ GPIO2C4_I2C2_SDA,
+
+ GPIO2C3_SHIFT = 6,
+ GPIO2C3_MASK = 1 << GPIO2C3_SHIFT,
+ GPIO2C3_GPIO = 0,
+ GPIO2C3_MAC_TXD0,
+
+ GPIO2C2_SHIFT = 4,
+ GPIO2C2_MASK = 1 << GPIO2C2_SHIFT,
+ GPIO2C2_GPIO = 0,
+ GPIO2C2_MAC_TXD1,
+
+ GPIO2C1_SHIFT = 2,
+ GPIO2C1_MASK = 1 << GPIO2C1_SHIFT,
+ GPIO2C1_GPIO = 0,
+ GPIO2C1_MAC_RXD0,
+
+ GPIO2C0_SHIFT = 0,
+ GPIO2C0_MASK = 1 << GPIO2C0_SHIFT,
+ GPIO2C0_GPIO = 0,
+ GPIO2C0_MAC_RXD1,
+};
+
+/* GRF_GPIO2D_IOMUX */
+enum {
+ GPIO2D6_SHIFT = 12,
+ GPIO2D6_MASK = 1 << GPIO2D6_SHIFT,
+ GPIO2D6_GPIO = 0,
+ GPIO2D6_I2S_SDO1,
+
+ GPIO2D5_SHIFT = 10,
+ GPIO2D5_MASK = 1 << GPIO2D5_SHIFT,
+ GPIO2D5_GPIO = 0,
+ GPIO2D5_I2S_SDO2,
+
+ GPIO2D4_SHIFT = 8,
+ GPIO2D4_MASK = 1 << GPIO2D4_SHIFT,
+ GPIO2D4_GPIO = 0,
+ GPIO2D4_I2S_SDO3,
+
+ GPIO2D1_SHIFT = 2,
+ GPIO2D1_MASK = 1 << GPIO2D1_SHIFT,
+ GPIO2D1_GPIO = 0,
+ GPIO2D1_MAC_MDC,
+};
+
struct rk3036_pinctrl_priv {
struct rk3036_grf *grf;
};
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3188.c b/drivers/pinctrl/rockchip/pinctrl_rk3188.c
index 692d8e298d..fdab836e5a 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3188.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3188.c
@@ -20,6 +20,386 @@
DECLARE_GLOBAL_DATA_PTR;
+/* GRF_GPIO0D_IOMUX */
+enum {
+ GPIO0D7_SHIFT = 14,
+ GPIO0D7_MASK = 1,
+ GPIO0D7_GPIO = 0,
+ GPIO0D7_SPI1_CSN0,
+
+ GPIO0D6_SHIFT = 12,
+ GPIO0D6_MASK = 1,
+ GPIO0D6_GPIO = 0,
+ GPIO0D6_SPI1_CLK,
+
+ GPIO0D5_SHIFT = 10,
+ GPIO0D5_MASK = 1,
+ GPIO0D5_GPIO = 0,
+ GPIO0D5_SPI1_TXD,
+
+ GPIO0D4_SHIFT = 8,
+ GPIO0D4_MASK = 1,
+ GPIO0D4_GPIO = 0,
+ GPIO0D4_SPI0_RXD,
+
+ GPIO0D3_SHIFT = 6,
+ GPIO0D3_MASK = 3,
+ GPIO0D3_GPIO = 0,
+ GPIO0D3_FLASH_CSN3,
+ GPIO0D3_EMMC_RSTN_OUT,
+
+ GPIO0D2_SHIFT = 4,
+ GPIO0D2_MASK = 3,
+ GPIO0D2_GPIO = 0,
+ GPIO0D2_FLASH_CSN2,
+ GPIO0D2_EMMC_CMD,
+
+ GPIO0D1_SHIFT = 2,
+ GPIO0D1_MASK = 1,
+ GPIO0D1_GPIO = 0,
+ GPIO0D1_FLASH_CSN1,
+
+ GPIO0D0_SHIFT = 0,
+ GPIO0D0_MASK = 3,
+ GPIO0D0_GPIO = 0,
+ GPIO0D0_FLASH_DQS,
+ GPIO0D0_EMMC_CLKOUT
+};
+
+/* GRF_GPIO1A_IOMUX */
+enum {
+ GPIO1A7_SHIFT = 14,
+ GPIO1A7_MASK = 3,
+ GPIO1A7_GPIO = 0,
+ GPIO1A7_UART1_RTS_N,
+ GPIO1A7_SPI0_CSN0,
+
+ GPIO1A6_SHIFT = 12,
+ GPIO1A6_MASK = 3,
+ GPIO1A6_GPIO = 0,
+ GPIO1A6_UART1_CTS_N,
+ GPIO1A6_SPI0_CLK,
+
+ GPIO1A5_SHIFT = 10,
+ GPIO1A5_MASK = 3,
+ GPIO1A5_GPIO = 0,
+ GPIO1A5_UART1_SOUT,
+ GPIO1A5_SPI0_TXD,
+
+ GPIO1A4_SHIFT = 8,
+ GPIO1A4_MASK = 3,
+ GPIO1A4_GPIO = 0,
+ GPIO1A4_UART1_SIN,
+ GPIO1A4_SPI0_RXD,
+
+ GPIO1A3_SHIFT = 6,
+ GPIO1A3_MASK = 1,
+ GPIO1A3_GPIO = 0,
+ GPIO1A3_UART0_RTS_N,
+
+ GPIO1A2_SHIFT = 4,
+ GPIO1A2_MASK = 1,
+ GPIO1A2_GPIO = 0,
+ GPIO1A2_UART0_CTS_N,
+
+ GPIO1A1_SHIFT = 2,
+ GPIO1A1_MASK = 1,
+ GPIO1A1_GPIO = 0,
+ GPIO1A1_UART0_SOUT,
+
+ GPIO1A0_SHIFT = 0,
+ GPIO1A0_MASK = 1,
+ GPIO1A0_GPIO = 0,
+ GPIO1A0_UART0_SIN,
+};
+
+/* GRF_GPIO1B_IOMUX */
+enum {
+ GPIO1B7_SHIFT = 14,
+ GPIO1B7_MASK = 1,
+ GPIO1B7_GPIO = 0,
+ GPIO1B7_SPI0_CSN1,
+
+ GPIO1B6_SHIFT = 12,
+ GPIO1B6_MASK = 3,
+ GPIO1B6_GPIO = 0,
+ GPIO1B6_SPDIF_TX,
+ GPIO1B6_SPI1_CSN1,
+
+ GPIO1B5_SHIFT = 10,
+ GPIO1B5_MASK = 3,
+ GPIO1B5_GPIO = 0,
+ GPIO1B5_UART3_RTS_N,
+ GPIO1B5_RESERVED,
+
+ GPIO1B4_SHIFT = 8,
+ GPIO1B4_MASK = 3,
+ GPIO1B4_GPIO = 0,
+ GPIO1B4_UART3_CTS_N,
+ GPIO1B4_GPS_RFCLK,
+
+ GPIO1B3_SHIFT = 6,
+ GPIO1B3_MASK = 3,
+ GPIO1B3_GPIO = 0,
+ GPIO1B3_UART3_SOUT,
+ GPIO1B3_GPS_SIG,
+
+ GPIO1B2_SHIFT = 4,
+ GPIO1B2_MASK = 3,
+ GPIO1B2_GPIO = 0,
+ GPIO1B2_UART3_SIN,
+ GPIO1B2_GPS_MAG,
+
+ GPIO1B1_SHIFT = 2,
+ GPIO1B1_MASK = 3,
+ GPIO1B1_GPIO = 0,
+ GPIO1B1_UART2_SOUT,
+ GPIO1B1_JTAG_TDO,
+
+ GPIO1B0_SHIFT = 0,
+ GPIO1B0_MASK = 3,
+ GPIO1B0_GPIO = 0,
+ GPIO1B0_UART2_SIN,
+ GPIO1B0_JTAG_TDI,
+};
+
+/* GRF_GPIO1D_IOMUX */
+enum {
+ GPIO1D7_SHIFT = 14,
+ GPIO1D7_MASK = 1,
+ GPIO1D7_GPIO = 0,
+ GPIO1D7_I2C4_SCL,
+
+ GPIO1D6_SHIFT = 12,
+ GPIO1D6_MASK = 1,
+ GPIO1D6_GPIO = 0,
+ GPIO1D6_I2C4_SDA,
+
+ GPIO1D5_SHIFT = 10,
+ GPIO1D5_MASK = 1,
+ GPIO1D5_GPIO = 0,
+ GPIO1D5_I2C2_SCL,
+
+ GPIO1D4_SHIFT = 8,
+ GPIO1D4_MASK = 1,
+ GPIO1D4_GPIO = 0,
+ GPIO1D4_I2C2_SDA,
+
+ GPIO1D3_SHIFT = 6,
+ GPIO1D3_MASK = 1,
+ GPIO1D3_GPIO = 0,
+ GPIO1D3_I2C1_SCL,
+
+ GPIO1D2_SHIFT = 4,
+ GPIO1D2_MASK = 1,
+ GPIO1D2_GPIO = 0,
+ GPIO1D2_I2C1_SDA,
+
+ GPIO1D1_SHIFT = 2,
+ GPIO1D1_MASK = 1,
+ GPIO1D1_GPIO = 0,
+ GPIO1D1_I2C0_SCL,
+
+ GPIO1D0_SHIFT = 0,
+ GPIO1D0_MASK = 1,
+ GPIO1D0_GPIO = 0,
+ GPIO1D0_I2C0_SDA,
+};
+
+/* GRF_GPIO3A_IOMUX */
+enum {
+ GPIO3A7_SHIFT = 14,
+ GPIO3A7_MASK = 1,
+ GPIO3A7_GPIO = 0,
+ GPIO3A7_SDMMC0_DATA3,
+
+ GPIO3A6_SHIFT = 12,
+ GPIO3A6_MASK = 1,
+ GPIO3A6_GPIO = 0,
+ GPIO3A6_SDMMC0_DATA2,
+
+ GPIO3A5_SHIFT = 10,
+ GPIO3A5_MASK = 1,
+ GPIO3A5_GPIO = 0,
+ GPIO3A5_SDMMC0_DATA1,
+
+ GPIO3A4_SHIFT = 8,
+ GPIO3A4_MASK = 1,
+ GPIO3A4_GPIO = 0,
+ GPIO3A4_SDMMC0_DATA0,
+
+ GPIO3A3_SHIFT = 6,
+ GPIO3A3_MASK = 1,
+ GPIO3A3_GPIO = 0,
+ GPIO3A3_SDMMC0_CMD,
+
+ GPIO3A2_SHIFT = 4,
+ GPIO3A2_MASK = 1,
+ GPIO3A2_GPIO = 0,
+ GPIO3A2_SDMMC0_CLKOUT,
+
+ GPIO3A1_SHIFT = 2,
+ GPIO3A1_MASK = 1,
+ GPIO3A1_GPIO = 0,
+ GPIO3A1_SDMMC0_PWREN,
+
+ GPIO3A0_SHIFT = 0,
+ GPIO3A0_MASK = 1,
+ GPIO3A0_GPIO = 0,
+ GPIO3A0_SDMMC0_RSTN,
+};
+
+/* GRF_GPIO3B_IOMUX */
+enum {
+ GPIO3B7_SHIFT = 14,
+ GPIO3B7_MASK = 3,
+ GPIO3B7_GPIO = 0,
+ GPIO3B7_CIF_DATA11,
+ GPIO3B7_I2C3_SCL,
+
+ GPIO3B6_SHIFT = 12,
+ GPIO3B6_MASK = 3,
+ GPIO3B6_GPIO = 0,
+ GPIO3B6_CIF_DATA10,
+ GPIO3B6_I2C3_SDA,
+
+ GPIO3B5_SHIFT = 10,
+ GPIO3B5_MASK = 3,
+ GPIO3B5_GPIO = 0,
+ GPIO3B5_CIF_DATA1,
+ GPIO3B5_HSADC_DATA9,
+
+ GPIO3B4_SHIFT = 8,
+ GPIO3B4_MASK = 3,
+ GPIO3B4_GPIO = 0,
+ GPIO3B4_CIF_DATA0,
+ GPIO3B4_HSADC_DATA8,
+
+ GPIO3B3_SHIFT = 6,
+ GPIO3B3_MASK = 1,
+ GPIO3B3_GPIO = 0,
+ GPIO3B3_CIF_CLKOUT,
+
+ GPIO3B2_SHIFT = 4,
+ GPIO3B2_MASK = 1,
+ GPIO3B2_GPIO = 0,
+ /* no muxes */
+
+ GPIO3B1_SHIFT = 2,
+ GPIO3B1_MASK = 1,
+ GPIO3B1_GPIO = 0,
+ GPIO3B1_SDMMC0_WRITE_PRT,
+
+ GPIO3B0_SHIFT = 0,
+ GPIO3B0_MASK = 1,
+ GPIO3B0_GPIO = 0,
+ GPIO3B0_SDMMC_DETECT_N,
+};
+
+/* GRF_GPIO3C_IOMUX */
+enum {
+ GPIO3C7_SHIFT = 14,
+ GPIO3C7_MASK = 3,
+ GPIO3C7_GPIO = 0,
+ GPIO3C7_SDMMC1_WRITE_PRT,
+ GPIO3C7_RMII_CRS_DVALID,
+ GPIO3C7_RESERVED,
+
+ GPIO3C6_SHIFT = 12,
+ GPIO3C6_MASK = 3,
+ GPIO3C6_GPIO = 0,
+ GPIO3C6_SDMMC1_DECTN,
+ GPIO3C6_RMII_RX_ERR,
+ GPIO3C6_RESERVED,
+
+ GPIO3C5_SHIFT = 10,
+ GPIO3C5_MASK = 3,
+ GPIO3C5_GPIO = 0,
+ GPIO3C5_SDMMC1_CLKOUT,
+ GPIO3C5_RMII_CLKOUT,
+ GPIO3C5_RMII_CLKIN,
+
+ GPIO3C4_SHIFT = 8,
+ GPIO3C4_MASK = 3,
+ GPIO3C4_GPIO = 0,
+ GPIO3C4_SDMMC1_DATA3,
+ GPIO3C4_RMII_RXD1,
+ GPIO3C4_RESERVED,
+
+ GPIO3C3_SHIFT = 6,
+ GPIO3C3_MASK = 3,
+ GPIO3C3_GPIO = 0,
+ GPIO3C3_SDMMC1_DATA2,
+ GPIO3C3_RMII_RXD0,
+ GPIO3C3_RESERVED,
+
+ GPIO3C2_SHIFT = 4,
+ GPIO3C2_MASK = 3,
+ GPIO3C2_GPIO = 0,
+ GPIO3C2_SDMMC1_DATA1,
+ GPIO3C2_RMII_TXD0,
+ GPIO3C2_RESERVED,
+
+ GPIO3C1_SHIFT = 2,
+ GPIO3C1_MASK = 3,
+ GPIO3C1_GPIO = 0,
+ GPIO3C1_SDMMC1_DATA0,
+ GPIO3C1_RMII_TXD1,
+ GPIO3C1_RESERVED,
+
+ GPIO3C0_SHIFT = 0,
+ GPIO3C0_MASK = 3,
+ GPIO3C0_GPIO = 0,
+ GPIO3C0_SDMMC1_CMD,
+ GPIO3C0_RMII_TX_EN,
+ GPIO3C0_RESERVED,
+};
+
+/* GRF_GPIO3D_IOMUX */
+enum {
+ GPIO3D6_SHIFT = 12,
+ GPIO3D6_MASK = 3,
+ GPIO3D6_GPIO = 0,
+ GPIO3D6_PWM_3,
+ GPIO3D6_JTAG_TMS,
+ GPIO3D6_HOST_DRV_VBUS,
+
+ GPIO3D5_SHIFT = 10,
+ GPIO3D5_MASK = 3,
+ GPIO3D5_GPIO = 0,
+ GPIO3D5_PWM_2,
+ GPIO3D5_JTAG_TCK,
+ GPIO3D5_OTG_DRV_VBUS,
+
+ GPIO3D4_SHIFT = 8,
+ GPIO3D4_MASK = 3,
+ GPIO3D4_GPIO = 0,
+ GPIO3D4_PWM_1,
+ GPIO3D4_JTAG_TRSTN,
+
+ GPIO3D3_SHIFT = 6,
+ GPIO3D3_MASK = 3,
+ GPIO3D3_GPIO = 0,
+ GPIO3D3_PWM_0,
+
+ GPIO3D2_SHIFT = 4,
+ GPIO3D2_MASK = 3,
+ GPIO3D2_GPIO = 0,
+ GPIO3D2_SDMMC1_INT_N,
+
+ GPIO3D1_SHIFT = 2,
+ GPIO3D1_MASK = 3,
+ GPIO3D1_GPIO = 0,
+ GPIO3D1_SDMMC1_BACKEND_PWR,
+ GPIO3D1_MII_MDCLK,
+
+ GPIO3D0_SHIFT = 0,
+ GPIO3D0_MASK = 3,
+ GPIO3D0_GPIO = 0,
+ GPIO3D0_SDMMC1_PWR_EN,
+ GPIO3D0_MII_MD,
+};
+
struct rk3188_pinctrl_priv {
struct rk3188_grf *grf;
struct rk3188_pmu *pmu;
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3399.c b/drivers/pinctrl/rockchip/pinctrl_rk3399.c
index 19a7415522..c7052257aa 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3399.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3399.c
@@ -70,6 +70,60 @@ static void pinctrl_rk3399_i2c_config(struct rk3399_grf_regs *grf,
PMUGRF_GPIO1C0_SEL_MASK,
PMUGRF_I2C0PMU_SCL << PMUGRF_GPIO1C0_SEL_SHIFT);
break;
+
+ case PERIPH_ID_I2C1:
+ rk_clrsetreg(&grf->gpio4a_iomux,
+ GRF_GPIO4A1_SEL_MASK,
+ GRF_I2C1_SDA << GRF_GPIO4A1_SEL_SHIFT);
+ rk_clrsetreg(&grf->gpio4a_iomux,
+ GRF_GPIO4A2_SEL_MASK,
+ GRF_I2C1_SCL << GRF_GPIO4A2_SEL_SHIFT);
+ break;
+
+ case PERIPH_ID_I2C2:
+ rk_clrsetreg(&grf->gpio2a_iomux,
+ GRF_GPIO2A0_SEL_MASK,
+ GRF_I2C2_SDA << GRF_GPIO2A0_SEL_SHIFT);
+ rk_clrsetreg(&grf->gpio2a_iomux,
+ GRF_GPIO2A1_SEL_MASK,
+ GRF_I2C2_SCL << GRF_GPIO2A1_SEL_SHIFT);
+ break;
+ case PERIPH_ID_I2C3:
+ rk_clrsetreg(&grf->gpio4c_iomux,
+ GRF_GPIO4C0_SEL_MASK,
+ GRF_HDMII2C_SCL << GRF_GPIO4C0_SEL_SHIFT);
+ rk_clrsetreg(&grf->gpio4c_iomux,
+ GRF_GPIO4C1_SEL_MASK,
+ GRF_HDMII2C_SDA << GRF_GPIO4C1_SEL_SHIFT);
+ break;
+
+ case PERIPH_ID_I2C4:
+ rk_clrsetreg(&pmugrf->gpio1b_iomux,
+ PMUGRF_GPIO1B3_SEL_MASK,
+ PMUGRF_I2C4_SDA << PMUGRF_GPIO1B3_SEL_SHIFT);
+ rk_clrsetreg(&pmugrf->gpio1b_iomux,
+ PMUGRF_GPIO1B4_SEL_MASK,
+ PMUGRF_I2C4_SCL << PMUGRF_GPIO1B4_SEL_SHIFT);
+ break;
+
+ case PERIPH_ID_I2C7:
+ rk_clrsetreg(&grf->gpio2a_iomux,
+ GRF_GPIO2A7_SEL_MASK,
+ GRF_I2C7_SDA << GRF_GPIO2A7_SEL_SHIFT);
+ rk_clrsetreg(&grf->gpio2b_iomux,
+ GRF_GPIO2B0_SEL_MASK,
+ GRF_I2C7_SCL << GRF_GPIO2B0_SEL_SHIFT);
+ break;
+
+ case PERIPH_ID_I2C6:
+ rk_clrsetreg(&grf->gpio2b_iomux,
+ GRF_GPIO2B1_SEL_MASK,
+ GRF_I2C6_SDA << GRF_GPIO2B1_SEL_SHIFT);
+ rk_clrsetreg(&grf->gpio2b_iomux,
+ GRF_GPIO2B2_SEL_MASK,
+ GRF_I2C6_SDA << GRF_GPIO2B2_SEL_SHIFT);
+ break;
+
case PERIPH_ID_I2C8:
rk_clrsetreg(&pmugrf->gpio1c_iomux,
PMUGRF_GPIO1C4_SEL_MASK,
@@ -78,13 +132,8 @@ static void pinctrl_rk3399_i2c_config(struct rk3399_grf_regs *grf,
PMUGRF_GPIO1C5_SEL_MASK,
PMUGRF_I2C8PMU_SCL << PMUGRF_GPIO1C5_SEL_SHIFT);
break;
- case PERIPH_ID_I2C1:
- case PERIPH_ID_I2C2:
- case PERIPH_ID_I2C3:
- case PERIPH_ID_I2C4:
+
case PERIPH_ID_I2C5:
- case PERIPH_ID_I2C6:
- case PERIPH_ID_I2C7:
default:
debug("i2c id = %d iomux error!\n", i2c_id);
break;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d8c107e206..1a3852442a 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -22,6 +22,7 @@ config SUNXI_NO_PMIC
config AXP152_POWER
bool "axp152 pmic support"
depends on MACH_SUN5I
+ select AXP_PMIC_BUS
select CMD_POWEROFF
---help---
Select this to enable support for the axp152 pmic found on most
@@ -30,6 +31,7 @@ config AXP152_POWER
config AXP209_POWER
bool "axp209 pmic support"
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
+ select AXP_PMIC_BUS
select CMD_POWEROFF
---help---
Select this to enable support for the axp209 pmic found on most
@@ -38,6 +40,7 @@ config AXP209_POWER
config AXP221_POWER
bool "axp221 / axp223 pmic support"
depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40
+ select AXP_PMIC_BUS
select CMD_POWEROFF
---help---
Select this to enable support for the axp221/axp223 pmic found on most
@@ -46,6 +49,7 @@ config AXP221_POWER
config AXP809_POWER
bool "axp809 pmic support"
depends on MACH_SUN9I
+ select AXP_PMIC_BUS
select CMD_POWEROFF
---help---
Say y here to enable support for the axp809 pmic found on A80 boards.
@@ -53,6 +57,7 @@ config AXP809_POWER
config AXP818_POWER
bool "axp818 pmic support"
depends on MACH_SUN8I_A83T
+ select AXP_PMIC_BUS
select CMD_POWEROFF
---help---
Say y here to enable support for the axp818 pmic found on
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 5d49c93f32..40ab9f7fa5 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -209,3 +209,11 @@ config DM_PMIC_TPS65910
The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost
DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO
pmic children.
+
+config PMIC_STPMU1
+ bool "Enable support for STMicroelectronics STPMU1 PMIC"
+ depends on DM_PMIC && DM_I2C
+ ---help---
+ The STPMU1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches.
+ It is accessed via an I2C interface. The device is used with STM32MP1
+ SoCs. This driver implements register read/write operations.
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index fc19fdc701..ad32068b3a 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o
obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
+obj-$(CONFIG_PMIC_STPMU1) += stpmu1.o
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
diff --git a/drivers/power/pmic/stpmu1.c b/drivers/power/pmic/stpmu1.c
new file mode 100644
index 0000000000..4615365ea8
--- /dev/null
+++ b/drivers/power/pmic/stpmu1.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/stpmu1.h>
+
+#define STMPU1_NUM_OF_REGS 0x100
+
+static int stpmu1_reg_count(struct udevice *dev)
+{
+ return STMPU1_NUM_OF_REGS;
+}
+
+static int stpmu1_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret)
+ dev_err(dev, "%s: failed to write register %#x :%d",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret)
+ dev_err(dev, "%s: failed to read register %#x : %d",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static struct dm_pmic_ops stpmu1_ops = {
+ .reg_count = stpmu1_reg_count,
+ .read = stpmu1_read,
+ .write = stpmu1_write,
+};
+
+static const struct udevice_id stpmu1_ids[] = {
+ { .compatible = "st,stpmu1" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_stpmu1) = {
+ .name = "stpmu1_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = stpmu1_ids,
+ .ops = &stpmu1_ops,
+};
diff --git a/drivers/power/regulator/pbias_regulator.c b/drivers/power/regulator/pbias_regulator.c
index 116b7f480a..adf589b224 100644
--- a/drivers/power/regulator/pbias_regulator.c
+++ b/drivers/power/regulator/pbias_regulator.c
@@ -225,9 +225,6 @@ static int pbias_regulator_set_value(struct udevice *dev, int uV)
int rc;
u32 reg;
- debug("Setting %s voltage to %s\n", p->name,
- (reg & p->vmode) ? "3.0v" : "1.8v");
-
rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
if (rc)
return rc;
@@ -239,6 +236,9 @@ static int pbias_regulator_set_value(struct udevice *dev, int uV)
else
return -EINVAL;
+ debug("Setting %s voltage to %s\n", p->name,
+ (reg & p->vmode) ? "3.0v" : "1.8v");
+
return pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
}
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c
index 2364c2dfdd..7d3e11d667 100644
--- a/drivers/pwm/rk_pwm.c
+++ b/drivers/pwm/rk_pwm.c
@@ -76,7 +76,7 @@ static int rk_pwm_ofdata_to_platdata(struct udevice *dev)
{
struct rk_pwm_priv *priv = dev_get_priv(dev);
- priv->regs = (struct rk3288_pwm *)devfdt_get_addr(dev);
+ priv->regs = (struct rk3288_pwm *)dev_read_addr(dev);
return 0;
}
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index 47969f3f28..496e2b793b 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -33,3 +33,5 @@ config STM32_SDRAM
STM32F7 family devices support flexible memory controller(FMC) to
support external memories like sdram, psram & nand.
This driver is for the sdram memory interface with the FMC.
+
+source "drivers/ram/stm32mp1/Kconfig"
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
index 51ae6be655..3820d03aa4 100644
--- a/drivers/ram/Makefile
+++ b/drivers/ram/Makefile
@@ -6,6 +6,7 @@
#
obj-$(CONFIG_RAM) += ram-uclass.o
obj-$(CONFIG_SANDBOX) += sandbox_ram.o
+obj-$(CONFIG_STM32MP1_DDR) += stm32mp1/
obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_ram.o
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
index 76c1fe80a7..5cb470c209 100644
--- a/drivers/ram/rockchip/sdram_rk3399.c
+++ b/drivers/ram/rockchip/sdram_rk3399.c
@@ -1015,6 +1015,7 @@ static int switch_to_phy_index1(struct dram_info *dram,
writel(RK_CLRSETBITS(1 << 1, 1 << 1), &dram->cic->cic_ctrl0);
while (!(readl(&dram->cic->cic_status0) & (1 << 0))) {
mdelay(10);
+ i++;
if (i > 10) {
debug("index1 frequency done overtime\n");
return -ETIME;
diff --git a/drivers/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig
new file mode 100644
index 0000000000..b9c816662c
--- /dev/null
+++ b/drivers/ram/stm32mp1/Kconfig
@@ -0,0 +1,12 @@
+
+config STM32MP1_DDR
+ bool "STM32MP1 DDR driver"
+ depends on DM && OF_CONTROL && ARCH_STM32MP
+ select RAM
+ select SPL_RAM if SPL
+ default y
+ help
+ activate STM32MP1 DDR controller driver for STM32MP1 soc
+ family: support for LPDDR2, LPDDR3 and DDR3
+ the SDRAM parameters for controleur and phy need to be provided
+ in device tree (computed by DDR tuning tools)
diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile
new file mode 100644
index 0000000000..9f05cd4b21
--- /dev/null
+++ b/drivers/ram/stm32mp1/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+#
+# SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+#
+
+obj-y += stm32mp1_ram.o
+obj-y += stm32mp1_ddr.o
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
new file mode 100644
index 0000000000..ffe50d9cc2
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <ram.h>
+#include <reset.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/arch/ddr.h>
+#include <linux/iopoll.h>
+#include "stm32mp1_ddr.h"
+#include "stm32mp1_ddr_regs.h"
+
+#define RCC_DDRITFCR 0xD8
+
+#define RCC_DDRITFCR_DDRCAPBRST (BIT(14))
+#define RCC_DDRITFCR_DDRCAXIRST (BIT(15))
+#define RCC_DDRITFCR_DDRCORERST (BIT(16))
+#define RCC_DDRITFCR_DPHYAPBRST (BIT(17))
+#define RCC_DDRITFCR_DPHYRST (BIT(18))
+#define RCC_DDRITFCR_DPHYCTLRST (BIT(19))
+
+struct reg_desc {
+ const char *name;
+ u16 offset; /* offset for base address */
+ u8 par_offset; /* offset for parameter array */
+};
+
+#define INVALID_OFFSET 0xFF
+
+#define DDRCTL_REG(x, y) \
+ {#x,\
+ offsetof(struct stm32mp1_ddrctl, x),\
+ offsetof(struct y, x)}
+
+#define DDRPHY_REG(x, y) \
+ {#x,\
+ offsetof(struct stm32mp1_ddrphy, x),\
+ offsetof(struct y, x)}
+
+#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
+static const struct reg_desc ddr_reg[] = {
+ DDRCTL_REG_REG(mstr),
+ DDRCTL_REG_REG(mrctrl0),
+ DDRCTL_REG_REG(mrctrl1),
+ DDRCTL_REG_REG(derateen),
+ DDRCTL_REG_REG(derateint),
+ DDRCTL_REG_REG(pwrctl),
+ DDRCTL_REG_REG(pwrtmg),
+ DDRCTL_REG_REG(hwlpctl),
+ DDRCTL_REG_REG(rfshctl0),
+ DDRCTL_REG_REG(rfshctl3),
+ DDRCTL_REG_REG(crcparctl0),
+ DDRCTL_REG_REG(zqctl0),
+ DDRCTL_REG_REG(dfitmg0),
+ DDRCTL_REG_REG(dfitmg1),
+ DDRCTL_REG_REG(dfilpcfg0),
+ DDRCTL_REG_REG(dfiupd0),
+ DDRCTL_REG_REG(dfiupd1),
+ DDRCTL_REG_REG(dfiupd2),
+ DDRCTL_REG_REG(dfiphymstr),
+ DDRCTL_REG_REG(odtmap),
+ DDRCTL_REG_REG(dbg0),
+ DDRCTL_REG_REG(dbg1),
+ DDRCTL_REG_REG(dbgcmd),
+ DDRCTL_REG_REG(poisoncfg),
+ DDRCTL_REG_REG(pccfg),
+};
+
+#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
+static const struct reg_desc ddr_timing[] = {
+ DDRCTL_REG_TIMING(rfshtmg),
+ DDRCTL_REG_TIMING(dramtmg0),
+ DDRCTL_REG_TIMING(dramtmg1),
+ DDRCTL_REG_TIMING(dramtmg2),
+ DDRCTL_REG_TIMING(dramtmg3),
+ DDRCTL_REG_TIMING(dramtmg4),
+ DDRCTL_REG_TIMING(dramtmg5),
+ DDRCTL_REG_TIMING(dramtmg6),
+ DDRCTL_REG_TIMING(dramtmg7),
+ DDRCTL_REG_TIMING(dramtmg8),
+ DDRCTL_REG_TIMING(dramtmg14),
+ DDRCTL_REG_TIMING(odtcfg),
+};
+
+#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
+static const struct reg_desc ddr_map[] = {
+ DDRCTL_REG_MAP(addrmap1),
+ DDRCTL_REG_MAP(addrmap2),
+ DDRCTL_REG_MAP(addrmap3),
+ DDRCTL_REG_MAP(addrmap4),
+ DDRCTL_REG_MAP(addrmap5),
+ DDRCTL_REG_MAP(addrmap6),
+ DDRCTL_REG_MAP(addrmap9),
+ DDRCTL_REG_MAP(addrmap10),
+ DDRCTL_REG_MAP(addrmap11),
+};
+
+#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
+static const struct reg_desc ddr_perf[] = {
+ DDRCTL_REG_PERF(sched),
+ DDRCTL_REG_PERF(sched1),
+ DDRCTL_REG_PERF(perfhpr1),
+ DDRCTL_REG_PERF(perflpr1),
+ DDRCTL_REG_PERF(perfwr1),
+ DDRCTL_REG_PERF(pcfgr_0),
+ DDRCTL_REG_PERF(pcfgw_0),
+ DDRCTL_REG_PERF(pcfgqos0_0),
+ DDRCTL_REG_PERF(pcfgqos1_0),
+ DDRCTL_REG_PERF(pcfgwqos0_0),
+ DDRCTL_REG_PERF(pcfgwqos1_0),
+ DDRCTL_REG_PERF(pcfgr_1),
+ DDRCTL_REG_PERF(pcfgw_1),
+ DDRCTL_REG_PERF(pcfgqos0_1),
+ DDRCTL_REG_PERF(pcfgqos1_1),
+ DDRCTL_REG_PERF(pcfgwqos0_1),
+ DDRCTL_REG_PERF(pcfgwqos1_1),
+};
+
+#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
+static const struct reg_desc ddrphy_reg[] = {
+ DDRPHY_REG_REG(pgcr),
+ DDRPHY_REG_REG(aciocr),
+ DDRPHY_REG_REG(dxccr),
+ DDRPHY_REG_REG(dsgcr),
+ DDRPHY_REG_REG(dcr),
+ DDRPHY_REG_REG(odtcr),
+ DDRPHY_REG_REG(zq0cr1),
+ DDRPHY_REG_REG(dx0gcr),
+ DDRPHY_REG_REG(dx1gcr),
+ DDRPHY_REG_REG(dx2gcr),
+ DDRPHY_REG_REG(dx3gcr),
+};
+
+#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
+static const struct reg_desc ddrphy_timing[] = {
+ DDRPHY_REG_TIMING(ptr0),
+ DDRPHY_REG_TIMING(ptr1),
+ DDRPHY_REG_TIMING(ptr2),
+ DDRPHY_REG_TIMING(dtpr0),
+ DDRPHY_REG_TIMING(dtpr1),
+ DDRPHY_REG_TIMING(dtpr2),
+ DDRPHY_REG_TIMING(mr0),
+ DDRPHY_REG_TIMING(mr1),
+ DDRPHY_REG_TIMING(mr2),
+ DDRPHY_REG_TIMING(mr3),
+};
+
+#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
+static const struct reg_desc ddrphy_cal[] = {
+ DDRPHY_REG_CAL(dx0dllcr),
+ DDRPHY_REG_CAL(dx0dqtr),
+ DDRPHY_REG_CAL(dx0dqstr),
+ DDRPHY_REG_CAL(dx1dllcr),
+ DDRPHY_REG_CAL(dx1dqtr),
+ DDRPHY_REG_CAL(dx1dqstr),
+ DDRPHY_REG_CAL(dx2dllcr),
+ DDRPHY_REG_CAL(dx2dqtr),
+ DDRPHY_REG_CAL(dx2dqstr),
+ DDRPHY_REG_CAL(dx3dllcr),
+ DDRPHY_REG_CAL(dx3dqtr),
+ DDRPHY_REG_CAL(dx3dqstr),
+};
+
+enum reg_type {
+ REG_REG,
+ REG_TIMING,
+ REG_PERF,
+ REG_MAP,
+ REGPHY_REG,
+ REGPHY_TIMING,
+ REGPHY_CAL,
+ REG_TYPE_NB
+};
+
+enum base_type {
+ DDR_BASE,
+ DDRPHY_BASE,
+ NONE_BASE
+};
+
+struct ddr_reg_info {
+ const char *name;
+ const struct reg_desc *desc;
+ u8 size;
+ enum base_type base;
+};
+
+#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
+
+const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
+[REG_REG] = {
+ "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE},
+[REG_TIMING] = {
+ "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE},
+[REG_PERF] = {
+ "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE},
+[REG_MAP] = {
+ "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE},
+[REGPHY_REG] = {
+ "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE},
+[REGPHY_TIMING] = {
+ "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE},
+[REGPHY_CAL] = {
+ "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE},
+};
+
+const char *base_name[] = {
+ [DDR_BASE] = "ctl",
+ [DDRPHY_BASE] = "phy",
+};
+
+static u32 get_base_addr(const struct ddr_info *priv, enum base_type base)
+{
+ if (base == DDRPHY_BASE)
+ return (u32)priv->phy;
+ else
+ return (u32)priv->ctl;
+}
+
+static void set_reg(const struct ddr_info *priv,
+ enum reg_type type,
+ const void *param)
+{
+ unsigned int i;
+ unsigned int *ptr, value;
+ enum base_type base = ddr_registers[type].base;
+ u32 base_addr = get_base_addr(priv, base);
+ const struct reg_desc *desc = ddr_registers[type].desc;
+
+ debug("init %s\n", ddr_registers[type].name);
+ for (i = 0; i < ddr_registers[type].size; i++) {
+ ptr = (unsigned int *)(base_addr + desc[i].offset);
+ if (desc[i].par_offset == INVALID_OFFSET) {
+ pr_err("invalid parameter offset for %s", desc[i].name);
+ } else {
+ value = *((u32 *)((u32)param +
+ desc[i].par_offset));
+ writel(value, ptr);
+ debug("[0x%x] %s= 0x%08x\n",
+ (u32)ptr, desc[i].name, value);
+ }
+ }
+}
+
+static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
+{
+ u32 pgsr;
+ int ret;
+
+ ret = readl_poll_timeout(&phy->pgsr, pgsr,
+ pgsr & (DDRPHYC_PGSR_IDONE |
+ DDRPHYC_PGSR_DTERR |
+ DDRPHYC_PGSR_DTIERR |
+ DDRPHYC_PGSR_DFTERR |
+ DDRPHYC_PGSR_RVERR |
+ DDRPHYC_PGSR_RVEIRR),
+ 1000000);
+ debug("\n[0x%08x] pgsr = 0x%08x ret=%d\n",
+ (u32)&phy->pgsr, pgsr, ret);
+}
+
+void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir)
+{
+ pir |= DDRPHYC_PIR_INIT;
+ writel(pir, &phy->pir);
+ debug("[0x%08x] pir = 0x%08x -> 0x%08x\n",
+ (u32)&phy->pir, pir, readl(&phy->pir));
+
+ /* need to wait 10 configuration clock before start polling */
+ udelay(10);
+
+ /* Wait DRAM initialization and Gate Training Evaluation complete */
+ ddrphy_idone_wait(phy);
+}
+
+/* start quasi dynamic register update */
+static void start_sw_done(struct stm32mp1_ddrctl *ctl)
+{
+ clrbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+}
+
+/* wait quasi dynamic register update */
+static void wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
+{
+ int ret;
+ u32 swstat;
+
+ setbits_le32(&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+
+ ret = readl_poll_timeout(&ctl->swstat, swstat,
+ swstat & DDRCTRL_SWSTAT_SW_DONE_ACK,
+ 1000000);
+ if (ret)
+ panic("Timeout initialising DRAM : DDR->swstat = %x\n",
+ swstat);
+
+ debug("[0x%08x] swstat = 0x%08x\n", (u32)&ctl->swstat, swstat);
+}
+
+/* wait quasi dynamic register update */
+static void wait_operating_mode(struct ddr_info *priv, int mode)
+{
+ u32 stat, val, mask, val2 = 0, mask2 = 0;
+ int ret;
+
+ mask = DDRCTRL_STAT_OPERATING_MODE_MASK;
+ val = mode;
+ /* self-refresh due to software => check also STAT.selfref_type */
+ if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) {
+ mask |= DDRCTRL_STAT_SELFREF_TYPE_MASK;
+ stat |= DDRCTRL_STAT_SELFREF_TYPE_SR;
+ } else if (mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) {
+ /* normal mode: handle also automatic self refresh */
+ mask2 = DDRCTRL_STAT_OPERATING_MODE_MASK |
+ DDRCTRL_STAT_SELFREF_TYPE_MASK;
+ val2 = DDRCTRL_STAT_OPERATING_MODE_SR |
+ DDRCTRL_STAT_SELFREF_TYPE_ASR;
+ }
+
+ ret = readl_poll_timeout(&priv->ctl->stat, stat,
+ ((stat & mask) == val) ||
+ (mask2 && ((stat & mask2) == val2)),
+ 1000000);
+
+ if (ret)
+ panic("Timeout DRAM : DDR->stat = %x\n", stat);
+
+ debug("[0x%08x] stat = 0x%08x\n", (u32)&priv->ctl->stat, stat);
+}
+
+void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
+{
+ start_sw_done(ctl);
+ /* quasi-dynamic register update*/
+ setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
+ clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+ wait_sw_done_ack(ctl);
+}
+
+void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
+ u32 rfshctl3, u32 pwrctl)
+{
+ start_sw_done(ctl);
+ if (!(rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH))
+ clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
+ if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN)
+ setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+ wait_sw_done_ack(ctl);
+}
+
+/* board-specific DDR power initializations. */
+__weak int board_ddr_power_init(void)
+{
+ return 0;
+}
+
+__maybe_unused
+void stm32mp1_ddr_init(struct ddr_info *priv,
+ const struct stm32mp1_ddr_config *config)
+{
+ u32 pir;
+ int ret;
+
+ ret = board_ddr_power_init();
+
+ if (ret)
+ panic("ddr power init failed\n");
+
+ debug("name = %s\n", config->info.name);
+ debug("speed = %d MHz\n", config->info.speed);
+ debug("size = 0x%x\n", config->info.size);
+/*
+ * 1. Program the DWC_ddr_umctl2 registers
+ * 1.1 RESETS: presetn, core_ddrc_rstn, aresetn
+ */
+ /* Assert All DDR part */
+ setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST);
+ setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST);
+ setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
+ setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST);
+ setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST);
+ setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST);
+
+/* 1.2. start CLOCK */
+ if (stm32mp1_ddr_clk_enable(priv, config->info.speed))
+ panic("invalid DRAM clock : %d MHz\n",
+ config->info.speed);
+
+/* 1.3. deassert reset */
+ /* de-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST */
+ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST);
+ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST);
+ /* De-assert presetn once the clocks are active
+ * and stable via DDRCAPBRST bit
+ */
+ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST);
+
+/* 1.4. wait 4 cycles for synchronization */
+ asm(" nop");
+ asm(" nop");
+ asm(" nop");
+ asm(" nop");
+
+/* 1.5. initialize registers ddr_umctl2 */
+ /* Stop uMCTL2 before PHY is ready */
+ clrbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+ debug("[0x%08x] dfimisc = 0x%08x\n",
+ (u32)&priv->ctl->dfimisc, readl(&priv->ctl->dfimisc));
+
+ set_reg(priv, REG_REG, &config->c_reg);
+ set_reg(priv, REG_TIMING, &config->c_timing);
+ set_reg(priv, REG_MAP, &config->c_map);
+
+ /* skip CTRL init, SDRAM init is done by PHY PUBL */
+ clrsetbits_le32(&priv->ctl->init0,
+ DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK,
+ DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL);
+
+ set_reg(priv, REG_PERF, &config->c_perf);
+
+/* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */
+ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
+ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST);
+ clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST);
+
+/* 3. start PHY init by accessing relevant PUBL registers
+ * (DXGCR, DCR, PTR*, MR*, DTPR*)
+ */
+ set_reg(priv, REGPHY_REG, &config->p_reg);
+ set_reg(priv, REGPHY_TIMING, &config->p_timing);
+ set_reg(priv, REGPHY_CAL, &config->p_cal);
+
+/* 4. Monitor PHY init status by polling PUBL register PGSR.IDONE
+ * Perform DDR PHY DRAM initialization and Gate Training Evaluation
+ */
+ ddrphy_idone_wait(priv->phy);
+
+/* 5. Indicate to PUBL that controller performs SDRAM initialization
+ * by setting PIR.INIT and PIR CTLDINIT and pool PGSR.IDONE
+ * DRAM init is done by PHY, init0.skip_dram.init = 1
+ */
+ pir = DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | DDRPHYC_PIR_ZCAL |
+ DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_DRAMINIT | DDRPHYC_PIR_ICPC;
+
+ if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
+ pir |= DDRPHYC_PIR_DRAMRST; /* only for DDR3 */
+
+ stm32mp1_ddrphy_init(priv->phy, pir);
+
+/* 6. SET DFIMISC.dfi_init_complete_en to 1 */
+ /* Enable quasi-dynamic register programming*/
+ start_sw_done(priv->ctl);
+ setbits_le32(&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+ wait_sw_done_ack(priv->ctl);
+
+/* 7. Wait for DWC_ddr_umctl2 to move to normal operation mode
+ * by monitoring STAT.operating_mode signal
+ */
+ /* wait uMCTL2 ready */
+
+ wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
+
+ debug("DDR DQS training : ");
+/* 8. Disable Auto refresh and power down by setting
+ * - RFSHCTL3.dis_au_refresh = 1
+ * - PWRCTL.powerdown_en = 0
+ * - DFIMISC.dfiinit_complete_en = 0
+ */
+ stm32mp1_refresh_disable(priv->ctl);
+
+/* 9. Program PUBL PGCR to enable refresh during training and rank to train
+ * not done => keep the programed value in PGCR
+ */
+
+/* 10. configure PUBL PIR register to specify which training step to run */
+ /* warning : RVTRN is not supported by this PUBL */
+ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+
+/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
+ ddrphy_idone_wait(priv->phy);
+
+/* 12. set back registers in step 8 to the orginal values if desidered */
+ stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+ config->c_reg.pwrctl);
+
+ /* enable uMCTL2 AXI port 0 and 1 */
+ setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
+ setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
+}
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
new file mode 100644
index 0000000000..b77d823868
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#ifndef _RAM_STM32MP1_DDR_H
+#define _RAM_STM32MP1_DDR_H
+
+enum stm32mp1_ddr_interact_step {
+ STEP_DDR_RESET,
+ STEP_CTL_INIT,
+ STEP_PHY_INIT,
+ STEP_DDR_READY,
+ STEP_RUN,
+};
+
+/* DDR CTL and DDR PHY REGISTERS */
+struct stm32mp1_ddrctl;
+struct stm32mp1_ddrphy;
+
+/**
+ * struct ddr_info
+ *
+ * @dev: pointer for the device
+ * @info: UCLASS RAM information
+ * @ctl: DDR controleur base address
+ * @clk: DDR clock
+ * @phy: DDR PHY base address
+ * @rcc: rcc base address
+ */
+struct ddr_info {
+ struct udevice *dev;
+ struct ram_info info;
+ struct clk clk;
+ struct stm32mp1_ddrctl *ctl;
+ struct stm32mp1_ddrphy *phy;
+ u32 rcc;
+};
+
+struct stm32mp1_ddrctrl_reg {
+ u32 mstr;
+ u32 mrctrl0;
+ u32 mrctrl1;
+ u32 derateen;
+ u32 derateint;
+ u32 pwrctl;
+ u32 pwrtmg;
+ u32 hwlpctl;
+ u32 rfshctl0;
+ u32 rfshctl3;
+ u32 crcparctl0;
+ u32 zqctl0;
+ u32 dfitmg0;
+ u32 dfitmg1;
+ u32 dfilpcfg0;
+ u32 dfiupd0;
+ u32 dfiupd1;
+ u32 dfiupd2;
+ u32 dfiphymstr;
+ u32 odtmap;
+ u32 dbg0;
+ u32 dbg1;
+ u32 dbgcmd;
+ u32 poisoncfg;
+ u32 pccfg;
+
+};
+
+struct stm32mp1_ddrctrl_timing {
+ u32 rfshtmg;
+ u32 dramtmg0;
+ u32 dramtmg1;
+ u32 dramtmg2;
+ u32 dramtmg3;
+ u32 dramtmg4;
+ u32 dramtmg5;
+ u32 dramtmg6;
+ u32 dramtmg7;
+ u32 dramtmg8;
+ u32 dramtmg14;
+ u32 odtcfg;
+};
+
+struct stm32mp1_ddrctrl_map {
+ u32 addrmap1;
+ u32 addrmap2;
+ u32 addrmap3;
+ u32 addrmap4;
+ u32 addrmap5;
+ u32 addrmap6;
+ u32 addrmap9;
+ u32 addrmap10;
+ u32 addrmap11;
+};
+
+struct stm32mp1_ddrctrl_perf {
+ u32 sched;
+ u32 sched1;
+ u32 perfhpr1;
+ u32 perflpr1;
+ u32 perfwr1;
+ u32 pcfgr_0;
+ u32 pcfgw_0;
+ u32 pcfgqos0_0;
+ u32 pcfgqos1_0;
+ u32 pcfgwqos0_0;
+ u32 pcfgwqos1_0;
+ u32 pcfgr_1;
+ u32 pcfgw_1;
+ u32 pcfgqos0_1;
+ u32 pcfgqos1_1;
+ u32 pcfgwqos0_1;
+ u32 pcfgwqos1_1;
+};
+
+struct stm32mp1_ddrphy_reg {
+ u32 pgcr;
+ u32 aciocr;
+ u32 dxccr;
+ u32 dsgcr;
+ u32 dcr;
+ u32 odtcr;
+ u32 zq0cr1;
+ u32 dx0gcr;
+ u32 dx1gcr;
+ u32 dx2gcr;
+ u32 dx3gcr;
+};
+
+struct stm32mp1_ddrphy_timing {
+ u32 ptr0;
+ u32 ptr1;
+ u32 ptr2;
+ u32 dtpr0;
+ u32 dtpr1;
+ u32 dtpr2;
+ u32 mr0;
+ u32 mr1;
+ u32 mr2;
+ u32 mr3;
+};
+
+struct stm32mp1_ddrphy_cal {
+ u32 dx0dllcr;
+ u32 dx0dqtr;
+ u32 dx0dqstr;
+ u32 dx1dllcr;
+ u32 dx1dqtr;
+ u32 dx1dqstr;
+ u32 dx2dllcr;
+ u32 dx2dqtr;
+ u32 dx2dqstr;
+ u32 dx3dllcr;
+ u32 dx3dqtr;
+ u32 dx3dqstr;
+};
+
+struct stm32mp1_ddr_info {
+ const char *name;
+ u16 speed; /* in MHZ */
+ u32 size; /* memory size in byte = col * row * width */
+};
+
+struct stm32mp1_ddr_config {
+ struct stm32mp1_ddr_info info;
+ struct stm32mp1_ddrctrl_reg c_reg;
+ struct stm32mp1_ddrctrl_timing c_timing;
+ struct stm32mp1_ddrctrl_map c_map;
+ struct stm32mp1_ddrctrl_perf c_perf;
+ struct stm32mp1_ddrphy_reg p_reg;
+ struct stm32mp1_ddrphy_timing p_timing;
+ struct stm32mp1_ddrphy_cal p_cal;
+};
+
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u16 mem_speed);
+void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir);
+void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl);
+void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
+ u32 rfshctl3,
+ u32 pwrctl);
+
+void stm32mp1_ddr_init(
+ struct ddr_info *priv,
+ const struct stm32mp1_ddr_config *config);
+
+int stm32mp1_dump_reg(const struct ddr_info *priv,
+ const char *name);
+
+void stm32mp1_edit_reg(const struct ddr_info *priv,
+ char *name,
+ char *string);
+
+int stm32mp1_dump_param(const struct stm32mp1_ddr_config *config,
+ const char *name);
+
+void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config,
+ char *name,
+ char *string);
+
+void stm32mp1_dump_info(
+ const struct ddr_info *priv,
+ const struct stm32mp1_ddr_config *config);
+
+bool stm32mp1_ddr_interactive(
+ void *priv,
+ enum stm32mp1_ddr_interact_step step,
+ const struct stm32mp1_ddr_config *config);
+
+#endif
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
new file mode 100644
index 0000000000..82c254b50d
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#ifndef _RAM_STM32MP1_DDR_REGS_H
+#define _RAM_STM32MP1_DDR_REGS_H
+
+/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
+struct stm32mp1_ddrctl {
+ u32 mstr ; /* 0x0 Master*/
+ u32 stat; /* 0x4 Operating Mode Status*/
+ u8 reserved008[0x10 - 0x8];
+ u32 mrctrl0; /* 0x10 Control 0.*/
+ u32 mrctrl1; /* 0x14 Control 1*/
+ u32 mrstat; /* 0x18 Status*/
+ u32 reserved01c; /* 0x1c */
+ u32 derateen; /* 0x20 Temperature Derate Enable*/
+ u32 derateint; /* 0x24 Temperature Derate Interval*/
+ u8 reserved028[0x30 - 0x28];
+ u32 pwrctl; /* 0x30 Low Power Control*/
+ u32 pwrtmg; /* 0x34 Low Power Timing*/
+ u32 hwlpctl; /* 0x38 Hardware Low Power Control*/
+ u8 reserved03c[0x50 - 0x3C];
+ u32 rfshctl0; /* 0x50 Refresh Control 0*/
+ u32 reserved054; /* 0x54 Refresh Control 1*/
+ u32 reserved058; /* 0x58 Refresh Control 2*/
+ u32 reserved05C;
+ u32 rfshctl3; /* 0x60 Refresh Control 0*/
+ u32 rfshtmg; /* 0x64 Refresh Timing*/
+ u8 reserved068[0xc0 - 0x68];
+ u32 crcparctl0; /* 0xc0 CRC Parity Control0*/
+ u32 reserved0c4; /* 0xc4 CRC Parity Control1*/
+ u32 reserved0c8; /* 0xc8 CRC Parity Control2*/
+ u32 crcparstat; /* 0xcc CRC Parity Status*/
+ u32 init0; /* 0xd0 SDRAM Initialization 0*/
+ u32 init1; /* 0xd4 SDRAM Initialization 1*/
+ u32 init2; /* 0xd8 SDRAM Initialization 2*/
+ u32 init3; /* 0xdc SDRAM Initialization 3*/
+ u32 init4; /* 0xe0 SDRAM Initialization 4*/
+ u32 init5; /* 0xe4 SDRAM Initialization 5*/
+ u32 reserved0e8;
+ u32 reserved0ec;
+ u32 dimmctl; /* 0xf0 DIMM Control*/
+ u8 reserved0f4[0x100 - 0xf4];
+ u32 dramtmg0; /* 0x100 SDRAM Timing 0*/
+ u32 dramtmg1; /* 0x104 SDRAM Timing 1*/
+ u32 dramtmg2; /* 0x108 SDRAM Timing 2*/
+ u32 dramtmg3; /* 0x10c SDRAM Timing 3*/
+ u32 dramtmg4; /* 0x110 SDRAM Timing 4*/
+ u32 dramtmg5; /* 0x114 SDRAM Timing 5*/
+ u32 dramtmg6; /* 0x118 SDRAM Timing 6*/
+ u32 dramtmg7; /* 0x11c SDRAM Timing 7*/
+ u32 dramtmg8; /* 0x120 SDRAM Timing 8*/
+ u8 reserved124[0x138 - 0x124];
+ u32 dramtmg14; /* 0x138 SDRAM Timing 14*/
+ u32 dramtmg15; /* 0x13C SDRAM Timing 15*/
+ u8 reserved140[0x180 - 0x140];
+ u32 zqctl0; /* 0x180 ZQ Control 0*/
+ u32 zqctl1; /* 0x184 ZQ Control 1*/
+ u32 zqctl2; /* 0x188 ZQ Control 2*/
+ u32 zqstat; /* 0x18c ZQ Status*/
+ u32 dfitmg0; /* 0x190 DFI Timing 0*/
+ u32 dfitmg1; /* 0x194 DFI Timing 1*/
+ u32 dfilpcfg0; /* 0x198 DFI Low Power Configuration 0*/
+ u32 reserved19c;
+ u32 dfiupd0; /* 0x1a0 DFI Update 0*/
+ u32 dfiupd1; /* 0x1a4 DFI Update 1*/
+ u32 dfiupd2; /* 0x1a8 DFI Update 2*/
+ u32 reserved1ac;
+ u32 dfimisc; /* 0x1b0 DFI Miscellaneous Control*/
+ u8 reserved1b4[0x1bc - 0x1b4];
+ u32 dfistat; /* 0x1bc DFI Miscellaneous Control*/
+ u8 reserved1c0[0x1c4 - 0x1c0];
+ u32 dfiphymstr; /* 0x1c4 DFI PHY Master interface*/
+ u8 reserved1c8[0x204 - 0x1c8];
+ u32 addrmap1; /* 0x204 Address Map 1*/
+ u32 addrmap2; /* 0x208 Address Map 2*/
+ u32 addrmap3; /* 0x20c Address Map 3*/
+ u32 addrmap4; /* 0x210 Address Map 4*/
+ u32 addrmap5; /* 0x214 Address Map 5*/
+ u32 addrmap6; /* 0x218 Address Map 6*/
+ u8 reserved21c[0x224 - 0x21c];
+ u32 addrmap9; /* 0x224 Address Map 9*/
+ u32 addrmap10; /* 0x228 Address Map 10*/
+ u32 addrmap11; /* 0x22C Address Map 11*/
+ u8 reserved230[0x240 - 0x230];
+ u32 odtcfg; /* 0x240 ODT Configuration*/
+ u32 odtmap; /* 0x244 ODT/Rank Map*/
+ u8 reserved248[0x250 - 0x248];
+ u32 sched; /* 0x250 Scheduler Control*/
+ u32 sched1; /* 0x254 Scheduler Control 1*/
+ u32 reserved258;
+ u32 perfhpr1; /* 0x25c High Priority Read CAM 1*/
+ u32 reserved260;
+ u32 perflpr1; /* 0x264 Low Priority Read CAM 1*/
+ u32 reserved268;
+ u32 perfwr1; /* 0x26c Write CAM 1*/
+ u8 reserved27c[0x300 - 0x270];
+ u32 dbg0; /* 0x300 Debug 0*/
+ u32 dbg1; /* 0x304 Debug 1*/
+ u32 dbgcam; /* 0x308 CAM Debug*/
+ u32 dbgcmd; /* 0x30c Command Debug*/
+ u32 dbgstat; /* 0x310 Status Debug*/
+ u8 reserved314[0x320 - 0x314];
+ u32 swctl; /* 0x320 Software Programming Control Enable*/
+ u32 swstat; /* 0x324 Software Programming Control Status*/
+ u8 reserved328[0x36c - 0x328];
+ u32 poisoncfg; /* 0x36c AXI Poison Configuration Register*/
+ u32 poisonstat; /* 0x370 AXI Poison Status Register*/
+ u8 reserved374[0x3fc - 0x374];
+
+ /* Multi Port registers */
+ u32 pstat; /* 0x3fc Port Status*/
+ u32 pccfg; /* 0x400 Port Common Configuration*/
+
+ /* PORT 0 */
+ u32 pcfgr_0; /* 0x404 Configuration Read*/
+ u32 pcfgw_0; /* 0x408 Configuration Write*/
+ u8 reserved40c[0x490 - 0x40c];
+ u32 pctrl_0; /* 0x490 Port Control Register */
+ u32 pcfgqos0_0; /* 0x494 Read QoS Configuration 0*/
+ u32 pcfgqos1_0; /* 0x498 Read QoS Configuration 1*/
+ u32 pcfgwqos0_0; /* 0x49c Write QoS Configuration 0*/
+ u32 pcfgwqos1_0; /* 0x4a0 Write QoS Configuration 1*/
+ u8 reserved4a4[0x4b4 - 0x4a4];
+
+ /* PORT 1 */
+ u32 pcfgr_1; /* 0x4b4 Configuration Read*/
+ u32 pcfgw_1; /* 0x4b8 Configuration Write*/
+ u8 reserved4bc[0x540 - 0x4bc];
+ u32 pctrl_1; /* 0x540 Port 2 Control Register */
+ u32 pcfgqos0_1; /* 0x544 Read QoS Configuration 0*/
+ u32 pcfgqos1_1; /* 0x548 Read QoS Configuration 1*/
+ u32 pcfgwqos0_1; /* 0x54c Write QoS Configuration 0*/
+ u32 pcfgwqos1_1; /* 0x550 Write QoS Configuration 1*/
+};
+
+/* DDR Physical Interface Control (DDRPHYC) registers*/
+struct stm32mp1_ddrphy {
+ u32 ridr; /* 0x00 R Revision Identification*/
+ u32 pir; /* 0x04 R/W PHY Initialization*/
+ u32 pgcr; /* 0x08 R/W PHY General Configuration*/
+ u32 pgsr; /* 0x0C PHY General Status*/
+ u32 dllgcr; /* 0x10 R/W DLL General Control*/
+ u32 acdllcr; /* 0x14 R/W AC DLL Control*/
+ u32 ptr0; /* 0x18 R/W PHY Timing 0*/
+ u32 ptr1; /* 0x1C R/W PHY Timing 1*/
+ u32 ptr2; /* 0x20 R/W PHY Timing 2*/
+ u32 aciocr; /* 0x24 AC I/O Configuration*/
+ u32 dxccr; /* 0x28 DATX8 Common Configuration*/
+ u32 dsgcr; /* 0x2C DDR System General Configuration*/
+ u32 dcr; /* 0x30 DRAM Configuration*/
+ u32 dtpr0; /* 0x34 DRAM Timing Parameters0*/
+ u32 dtpr1; /* 0x38 DRAM Timing Parameters1*/
+ u32 dtpr2; /* 0x3C DRAM Timing Parameters2*/
+ u32 mr0; /* 0x40 Mode 0*/
+ u32 mr1; /* 0x44 Mode 1*/
+ u32 mr2; /* 0x48 Mode 2*/
+ u32 mr3; /* 0x4C Mode 3*/
+ u32 odtcr; /* 0x50 ODT Configuration*/
+ u32 dtar; /* 0x54 data training address*/
+ u32 dtdr0; /* 0x58 */
+ u32 dtdr1; /* 0x5c */
+ u8 res1[0x0c0 - 0x060]; /* 0x60 */
+ u32 dcuar; /* 0xc0 Address*/
+ u32 dcudr; /* 0xc4 DCU Data*/
+ u32 dcurr; /* 0xc8 DCU Run*/
+ u32 dculr; /* 0xcc DCU Loop*/
+ u32 dcugcr; /* 0xd0 DCU General Configuration*/
+ u32 dcutpr; /* 0xd4 DCU Timing Parameters */
+ u32 dcusr0; /* 0xd8 DCU Status 0*/
+ u32 dcusr1; /* 0xdc DCU Status 1*/
+ u8 res2[0x100 - 0xe0]; /* 0xe0 */
+ u32 bistrr; /* 0x100 BIST Run*/
+ u32 bistmskr0; /* 0x104 BIST Mask 0*/
+ u32 bistmskr1; /* 0x108 BIST Mask 0*/
+ u32 bistwcr; /* 0x10c BIST Word Count*/
+ u32 bistlsr; /* 0x110 BIST LFSR Seed*/
+ u32 bistar0; /* 0x114 BIST Address 0*/
+ u32 bistar1; /* 0x118 BIST Address 1*/
+ u32 bistar2; /* 0x11c BIST Address 2*/
+ u32 bistupdr; /* 0x120 BIST User Data Pattern*/
+ u32 bistgsr; /* 0x124 BIST General Status*/
+ u32 bistwer; /* 0x128 BIST Word Error*/
+ u32 bistber0; /* 0x12c BIST Bit Error 0*/
+ u32 bistber1; /* 0x130 BIST Bit Error 1*/
+ u32 bistber2; /* 0x134 BIST Bit Error 2*/
+ u32 bistwcsr; /* 0x138 BIST Word Count Status*/
+ u32 bistfwr0; /* 0x13c BIST Fail Word 0*/
+ u32 bistfwr1; /* 0x140 BIST Fail Word 1*/
+ u8 res3[0x178 - 0x144]; /* 0x144 */
+ u32 gpr0; /* 0x178 General Purpose 0 (GPR0)*/
+ u32 gpr1; /* 0x17C General Purpose 1 (GPR1)*/
+ u32 zq0cr0; /* 0x180 zq 0 control 0 */
+ u32 zq0cr1; /* 0x184 zq 0 control 1 */
+ u32 zq0sr0; /* 0x188 zq 0 status 0 */
+ u32 zq0sr1; /* 0x18C zq 0 status 1 */
+ u8 res4[0x1C0 - 0x190]; /* 0x190 */
+ u32 dx0gcr; /* 0x1c0 Byte lane 0 General Configuration*/
+ u32 dx0gsr0; /* 0x1c4 Byte lane 0 General Status 0*/
+ u32 dx0gsr1; /* 0x1c8 Byte lane 0 General Status 1*/
+ u32 dx0dllcr; /* 0x1cc Byte lane 0 DLL Control*/
+ u32 dx0dqtr; /* 0x1d0 Byte lane 0 DQ Timing*/
+ u32 dx0dqstr; /* 0x1d4 Byte lane 0 DQS Timing*/
+ u8 res5[0x200 - 0x1d8]; /* 0x1d8 */
+ u32 dx1gcr; /* 0x200 Byte lane 1 General Configuration*/
+ u32 dx1gsr0; /* 0x204 Byte lane 1 General Status 0*/
+ u32 dx1gsr1; /* 0x208 Byte lane 1 General Status 1*/
+ u32 dx1dllcr; /* 0x20c Byte lane 1 DLL Control*/
+ u32 dx1dqtr; /* 0x210 Byte lane 1 DQ Timing*/
+ u32 dx1dqstr; /* 0x214 Byte lane 1 QS Timing*/
+ u8 res6[0x240 - 0x218]; /* 0x218 */
+ u32 dx2gcr; /* 0x240 Byte lane 2 General Configuration*/
+ u32 dx2gsr0; /* 0x244 Byte lane 2 General Status 0*/
+ u32 dx2gsr1; /* 0x248 Byte lane 2 General Status 1*/
+ u32 dx2dllcr; /* 0x24c Byte lane 2 DLL Control*/
+ u32 dx2dqtr; /* 0x250 Byte lane 2 DQ Timing*/
+ u32 dx2dqstr; /* 0x254 Byte lane 2 QS Timing*/
+ u8 res7[0x280 - 0x258]; /* 0x258 */
+ u32 dx3gcr; /* 0x280 Byte lane 3 General Configuration*/
+ u32 dx3gsr0; /* 0x284 Byte lane 3 General Status 0*/
+ u32 dx3gsr1; /* 0x288 Byte lane 3 General Status 1*/
+ u32 dx3dllcr; /* 0x28c Byte lane 3 DLL Control*/
+ u32 dx3dqtr; /* 0x290 Byte lane 3 DQ Timing*/
+ u32 dx3dqstr; /* 0x294 Byte lane 3 QS Timing*/
+};
+
+#define DXN(phy, offset, byte) ((u32)(phy) + (offset) + ((u32)(byte) * 0x40))
+#define DXNGCR(phy, byte) DXN(phy, 0x1c0, byte)
+#define DXNDLLCR(phy, byte) DXN(phy, 0x1cc, byte)
+#define DXNDQTR(phy, byte) DXN(phy, 0x1d0, byte)
+#define DXNDQSTR(phy, byte) DXN(phy, 0x1d4, byte)
+
+/* DDRCTRL REGISTERS */
+#define DDRCTRL_MSTR_DDR3 BIT(0)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL (0 << 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF (1 << 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER (2 << 12)
+#define DDRCTRL_MSTR_DLL_OFF_MODE BIT(15)
+
+#define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK(2, 0)
+#define DDRCTRL_STAT_OPERATING_MODE_NORMAL 1
+#define DDRCTRL_STAT_OPERATING_MODE_SR 3
+#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_ASR (3 << 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_SR (2 << 4)
+
+#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE 0
+/* only one rank supported */
+#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4
+#define DDRCTRL_MRCTRL0_MR_RANK_ALL \
+ (0x1 << DDRCTRL_MRCTRL0_MR_RANK_SHIFT)
+#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12
+#define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK(15, 12)
+#define DDRCTRL_MRCTRL0_MR_WR BIT(31)
+
+#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0)
+
+#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1)
+#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5)
+
+#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0)
+
+#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16)
+#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16
+
+#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK (0xC0000000)
+#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL (BIT(30))
+
+#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
+
+#define DDRCTRL_DBG1_DIS_HIF BIT(1)
+
+#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29)
+#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28)
+#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26)
+#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK(12, 8)
+#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK(4, 0)
+#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \
+ (DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \
+ DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY)
+#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \
+ (DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \
+ DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \
+ DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH)
+
+#define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0)
+
+#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0)
+
+#define DDRCTRL_SWCTL_SW_DONE BIT(0)
+
+#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0)
+
+#define DDRCTRL_PCTRL_N_PORT_EN BIT(0)
+
+/* DDRPHYC registers */
+#define DDRPHYC_PIR_INIT BIT(0)
+#define DDRPHYC_PIR_DLLSRST BIT(1)
+#define DDRPHYC_PIR_DLLLOCK BIT(2)
+#define DDRPHYC_PIR_ZCAL BIT(3)
+#define DDRPHYC_PIR_ITMSRST BIT(4)
+#define DDRPHYC_PIR_DRAMRST BIT(5)
+#define DDRPHYC_PIR_DRAMINIT BIT(6)
+#define DDRPHYC_PIR_QSTRN BIT(7)
+#define DDRPHYC_PIR_ICPC BIT(16)
+#define DDRPHYC_PIR_ZCALBYP BIT(30)
+#define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7)
+
+#define DDRPHYC_PGCR_DFTCMP BIT(2)
+#define DDRPHYC_PGCR_PDDISDX BIT(24)
+#define DDRPHYC_PGCR_RFSHDT_MASK GENMASK(28, 25)
+
+#define DDRPHYC_PGSR_IDONE BIT(0)
+#define DDRPHYC_PGSR_DTERR BIT(5)
+#define DDRPHYC_PGSR_DTIERR BIT(6)
+#define DDRPHYC_PGSR_DFTERR BIT(7)
+#define DDRPHYC_PGSR_RVERR BIT(8)
+#define DDRPHYC_PGSR_RVEIRR BIT(9)
+
+#define DDRPHYC_DLLGCR_BPS200 BIT(23)
+
+#define DDRPHYC_ACDLLCR_DLLDIS BIT(31)
+
+#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0)
+#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0
+#define DDRPHYC_ZQ0CRN_ZDEN BIT(28)
+
+#define DDRPHYC_DXNGCR_DXEN BIT(0)
+
+#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31)
+#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
+#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14
+
+#define DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit) (4 * (bit))
+#define DDRPHYC_DXNDQTR_DQDLY_MASK GENMASK(3, 0)
+#define DDRPHYC_DXNDQTR_DQDLY_LOW_MASK GENMASK(1, 0)
+#define DDRPHYC_DXNDQTR_DQDLY_HIGH_MASK GENMASK(3, 2)
+
+#define DDRPHYC_DXNDQSTR_DQSDLY_MASK GENMASK(22, 20)
+#define DDRPHYC_DXNDQSTR_DQSDLY_SHIFT 20
+#define DDRPHYC_DXNDQSTR_DQSNDLY_MASK GENMASK(25, 23)
+#define DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT 23
+#define DDRPHYC_DXNDQSTR_R0DGSL_MASK GENMASK(2, 0)
+#define DDRPHYC_DXNDQSTR_R0DGSL_SHIFT 0
+#define DDRPHYC_DXNDQSTR_R0DGPS_MASK GENMASK(13, 12)
+#define DDRPHYC_DXNDQSTR_R0DGPS_SHIFT 12
+
+#define DDRPHYC_BISTRR_BDXSEL_MASK GENMASK(22, 19)
+#define DDRPHYC_BISTRR_BDXSEL_SHIFT 19
+
+#define DDRPHYC_BISTGSR_BDDONE BIT(0)
+#define DDRPHYC_BISTGSR_BDXERR BIT(2)
+
+#define DDRPHYC_BISTWCSR_DXWCNT_SHIFT 16
+
+/* PWR registers */
+#define PWR_CR3 0x00C
+#define PWR_CR3_DDRSRDIS BIT(11)
+#define PWR_CR3_DDRRETEN BIT(12)
+
+#endif
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
new file mode 100644
index 0000000000..9599444650
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <ram.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include "stm32mp1_ddr.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *const clkname[] = {
+ "ddrc1",
+ "ddrc2",
+ "ddrcapb",
+ "ddrphycapb",
+ "ddrphyc" /* LAST clock => used for get_rate() */
+};
+
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
+{
+ unsigned long ddrphy_clk;
+ unsigned long ddr_clk;
+ struct clk clk;
+ int ret;
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) {
+ ret = clk_get_by_name(priv->dev, clkname[idx], &clk);
+
+ if (!ret)
+ ret = clk_enable(&clk);
+
+ if (ret) {
+ printf("error for %s : %d\n", clkname[idx], ret);
+ return ret;
+ }
+ }
+
+ priv->clk = clk;
+ ddrphy_clk = clk_get_rate(&priv->clk);
+
+ debug("DDR: mem_speed (%d MHz), RCC %d MHz\n",
+ mem_speed, (u32)(ddrphy_clk / 1000 / 1000));
+ /* max 10% frequency delta */
+ ddr_clk = abs(ddrphy_clk - mem_speed * 1000 * 1000);
+ if (ddr_clk > (mem_speed * 1000 * 100)) {
+ pr_err("DDR expected freq %d MHz, current is %d MHz\n",
+ mem_speed, (u32)(ddrphy_clk / 1000 / 1000));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
+{
+ struct ddr_info *priv = dev_get_priv(dev);
+ int ret, idx;
+ struct clk axidcg;
+ struct stm32mp1_ddr_config config;
+
+#define PARAM(x, y) \
+ { x,\
+ offsetof(struct stm32mp1_ddr_config, y),\
+ sizeof(config.y) / sizeof(u32)}
+
+#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
+#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
+
+ const struct {
+ const char *name; /* name in DT */
+ const u32 offset; /* offset in config struct */
+ const u32 size; /* size of parameters */
+ } param[] = {
+ CTL_PARAM(reg),
+ CTL_PARAM(timing),
+ CTL_PARAM(map),
+ CTL_PARAM(perf),
+ PHY_PARAM(reg),
+ PHY_PARAM(timing),
+ PHY_PARAM(cal)
+ };
+
+ config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
+ config.info.size = dev_read_u32_default(dev, "st,mem-size", 0);
+ config.info.name = dev_read_string(dev, "st,mem-name");
+ if (!config.info.name) {
+ debug("%s: no st,mem-name\n", __func__);
+ return -EINVAL;
+ }
+ printf("RAM: %s\n", config.info.name);
+
+ for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
+ ret = dev_read_u32_array(dev, param[idx].name,
+ (void *)((u32)&config +
+ param[idx].offset),
+ param[idx].size);
+ debug("%s: %s[0x%x] = %d\n", __func__,
+ param[idx].name, param[idx].size, ret);
+ if (ret) {
+ pr_err("%s: Cannot read %s\n",
+ __func__, param[idx].name);
+ return -EINVAL;
+ }
+ }
+
+ ret = clk_get_by_name(dev, "axidcg", &axidcg);
+ if (ret) {
+ debug("%s: Cannot found axidcg\n", __func__);
+ return -EINVAL;
+ }
+ clk_disable(&axidcg); /* disable clock gating during init */
+
+ stm32mp1_ddr_init(priv, &config);
+
+ clk_enable(&axidcg); /* enable clock gating */
+
+ /* check size */
+ debug("%s : get_ram_size(%x, %x)\n", __func__,
+ (u32)priv->info.base, (u32)STM32_DDR_SIZE);
+
+ priv->info.size = get_ram_size((long *)priv->info.base,
+ STM32_DDR_SIZE);
+
+ debug("%s : %x\n", __func__, (u32)priv->info.size);
+
+ /* check memory access for all memory */
+ if (config.info.size != priv->info.size) {
+ printf("DDR invalid size : 0x%x, expected 0x%x\n",
+ priv->info.size, config.info.size);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int stm32mp1_ddr_probe(struct udevice *dev)
+{
+ struct ddr_info *priv = dev_get_priv(dev);
+ struct regmap *map;
+ int ret;
+
+ debug("STM32MP1 DDR probe\n");
+ priv->dev = dev;
+
+ ret = regmap_init_mem(dev, &map);
+ if (ret)
+ return ret;
+
+ priv->ctl = regmap_get_range(map, 0);
+ priv->phy = regmap_get_range(map, 1);
+
+ priv->rcc = STM32_RCC_BASE;
+
+ priv->info.base = STM32_DDR_BASE;
+
+#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
+ priv->info.size = 0;
+ return stm32mp1_ddr_setup(dev);
+#else
+ priv->info.size = dev_read_u32_default(dev, "st,mem-size", 0);
+ return 0;
+#endif
+}
+
+static int stm32mp1_ddr_get_info(struct udevice *dev, struct ram_info *info)
+{
+ struct ddr_info *priv = dev_get_priv(dev);
+
+ *info = priv->info;
+
+ return 0;
+}
+
+static struct ram_ops stm32mp1_ddr_ops = {
+ .get_info = stm32mp1_ddr_get_info,
+};
+
+static const struct udevice_id stm32mp1_ddr_ids[] = {
+ { .compatible = "st,stm32mp1-ddr" },
+ { }
+};
+
+U_BOOT_DRIVER(ddr_stm32mp1) = {
+ .name = "stm32mp1_ddr",
+ .id = UCLASS_RAM,
+ .of_match = stm32mp1_ddr_ids,
+ .ops = &stm32mp1_ddr_ops,
+ .probe = stm32mp1_ddr_probe,
+ .priv_auto_alloc_size = sizeof(struct ddr_info),
+};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 3964b9eb6e..ccfdac7823 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -30,7 +30,7 @@ config STI_RESET
config STM32_RESET
bool "Enable the STM32 reset"
- depends on STM32
+ depends on STM32 || ARCH_STM32MP
help
Support for reset controllers on STMicroelectronics STM32 family SoCs.
This resset driver is compatible with STM32 F4/F7 and H7 SoCs.
@@ -83,4 +83,12 @@ config RESET_ROCKCHIP
though is that some reset signals, like I2C or MISC reset multiple
devices.
+config RESET_MESON
+ bool "Reset controller driver for Amlogic Meson SoCs"
+ depends on DM_RESET && ARCH_MESON
+ imply REGMAP
+ default y
+ help
+ Support for reset controller on Amlogic Meson SoC.
+
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 7d7e080c78..d1d5146825 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o
obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o
+obj-$(CONFIG_RESET_MESON) += reset-meson.o
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c
new file mode 100644
index 0000000000..5324f86f5f
--- /dev/null
+++ b/drivers/reset/reset-meson.c
@@ -0,0 +1,90 @@
+/*
+ * Amlogic Meson Reset Controller driver
+ *
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset-uclass.h>
+#include <regmap.h>
+
+#define REG_COUNT 8
+#define BITS_PER_REG 32
+#define LEVEL_OFFSET 0x7c
+
+struct meson_reset_priv {
+ struct regmap *regmap;
+};
+
+static int meson_reset_request(struct reset_ctl *reset_ctl)
+{
+ if (reset_ctl->id > (REG_COUNT * BITS_PER_REG))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int meson_reset_free(struct reset_ctl *reset_ctl)
+{
+ return 0;
+}
+
+static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert)
+{
+ struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ uint bank = reset_ctl->id / BITS_PER_REG;
+ uint offset = reset_ctl->id % BITS_PER_REG;
+ uint reg_offset = LEVEL_OFFSET + (bank << 2);
+ uint val;
+
+ regmap_read(priv->regmap, reg_offset, &val);
+ if (assert)
+ val &= ~BIT(offset);
+ else
+ val |= BIT(offset);
+ regmap_write(priv->regmap, reg_offset, val);
+
+ return 0;
+}
+
+static int meson_reset_assert(struct reset_ctl *reset_ctl)
+{
+ return meson_reset_level(reset_ctl, true);
+}
+
+static int meson_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ return meson_reset_level(reset_ctl, false);
+}
+
+struct reset_ops meson_reset_ops = {
+ .request = meson_reset_request,
+ .free = meson_reset_free,
+ .rst_assert = meson_reset_assert,
+ .rst_deassert = meson_reset_deassert,
+};
+
+static const struct udevice_id meson_reset_ids[] = {
+ { .compatible = "amlogic,meson-gxbb-reset" },
+ { }
+};
+
+static int meson_reset_probe(struct udevice *dev)
+{
+ struct meson_reset_priv *priv = dev_get_priv(dev);
+
+ return regmap_init_mem(dev, &priv->regmap);
+}
+
+U_BOOT_DRIVER(meson_reset) = {
+ .name = "meson_reset",
+ .id = UCLASS_RESET,
+ .of_match = meson_reset_ids,
+ .probe = meson_reset_probe,
+ .ops = &meson_reset_ops,
+ .priv_auto_alloc_size = sizeof(struct meson_reset_priv),
+};
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index 307a29705f..9a5c9c91b9 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -81,6 +81,40 @@ int reset_get_by_index(struct udevice *dev, int index,
return 0;
}
+int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+{
+ int i, ret, err, count;
+
+ bulk->count = 0;
+
+ count = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
+ if (!count)
+ return 0;
+
+ bulk->resets = devm_kcalloc(dev, count, sizeof(struct reset_ctl),
+ GFP_KERNEL);
+ if (!bulk->resets)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ ret = reset_get_by_index(dev, i, &bulk->resets[i]);
+ if (ret < 0)
+ goto bulk_get_err;
+
+ ++bulk->count;
+ }
+
+ return 0;
+
+bulk_get_err:
+ err = reset_release_all(bulk->resets, bulk->count);
+ if (err)
+ debug("%s: could release all resets for %p\n",
+ __func__, dev);
+
+ return ret;
+}
+
int reset_get_by_name(struct udevice *dev, const char *name,
struct reset_ctl *reset_ctl)
{
@@ -126,6 +160,19 @@ int reset_assert(struct reset_ctl *reset_ctl)
return ops->rst_assert(reset_ctl);
}
+int reset_assert_bulk(struct reset_ctl_bulk *bulk)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = reset_assert(&bulk->resets[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int reset_deassert(struct reset_ctl *reset_ctl)
{
struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
@@ -135,6 +182,19 @@ int reset_deassert(struct reset_ctl *reset_ctl)
return ops->rst_deassert(reset_ctl);
}
+int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = reset_deassert(&bulk->resets[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int reset_release_all(struct reset_ctl *reset_ctl, int count)
{
int i, ret;
diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c
index e37d6c91ef..f0ceaa0483 100644
--- a/drivers/reset/sandbox-reset-test.c
+++ b/drivers/reset/sandbox-reset-test.c
@@ -12,6 +12,7 @@
struct sandbox_reset_test {
struct reset_ctl ctl;
+ struct reset_ctl_bulk bulk;
};
int sandbox_reset_test_get(struct udevice *dev)
@@ -21,6 +22,13 @@ int sandbox_reset_test_get(struct udevice *dev)
return reset_get_by_name(dev, "test", &sbrt->ctl);
}
+int sandbox_reset_test_get_bulk(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+
+ return reset_get_bulk(dev, &sbrt->bulk);
+}
+
int sandbox_reset_test_assert(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
@@ -28,6 +36,13 @@ int sandbox_reset_test_assert(struct udevice *dev)
return reset_assert(&sbrt->ctl);
}
+int sandbox_reset_test_assert_bulk(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+
+ return reset_assert_bulk(&sbrt->bulk);
+}
+
int sandbox_reset_test_deassert(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
@@ -35,6 +50,13 @@ int sandbox_reset_test_deassert(struct udevice *dev)
return reset_deassert(&sbrt->ctl);
}
+int sandbox_reset_test_deassert_bulk(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+
+ return reset_deassert_bulk(&sbrt->bulk);
+}
+
int sandbox_reset_test_free(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
@@ -42,6 +64,13 @@ int sandbox_reset_test_free(struct udevice *dev)
return reset_free(&sbrt->ctl);
}
+int sandbox_reset_test_release_bulk(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+
+ return reset_release_bulk(&sbrt->bulk);
+}
+
static const struct udevice_id sandbox_reset_test_ids[] = {
{ .compatible = "sandbox,reset-ctl-test" },
{ }
diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c
index 4258af521b..c310749dc8 100644
--- a/drivers/reset/sandbox-reset.c
+++ b/drivers/reset/sandbox-reset.c
@@ -10,7 +10,7 @@
#include <asm/io.h>
#include <asm/reset.h>
-#define SANDBOX_RESET_SIGNALS 3
+#define SANDBOX_RESET_SIGNALS 101
struct sandbox_reset_signal {
bool asserted;
diff --git a/drivers/reset/stm32-reset.c b/drivers/reset/stm32-reset.c
index b266f46263..e98f34b037 100644
--- a/drivers/reset/stm32-reset.c
+++ b/drivers/reset/stm32-reset.c
@@ -11,7 +11,13 @@
#include <reset-uclass.h>
#include <asm/io.h>
-DECLARE_GLOBAL_DATA_PTR;
+/* reset clear offset for STM32MP RCC */
+#define RCC_CL 0x4
+
+enum rcc_type {
+ RCC_STM32 = 0,
+ RCC_STM32MP,
+};
struct stm32_reset_priv {
fdt_addr_t base;
@@ -35,7 +41,11 @@ static int stm32_reset_assert(struct reset_ctl *reset_ctl)
debug("%s: reset id = %ld bank = %d offset = %d)\n", __func__,
reset_ctl->id, bank, offset);
- setbits_le32(priv->base + bank, BIT(offset));
+ if (dev_get_driver_data(reset_ctl->dev) == RCC_STM32MP)
+ /* reset assert is done in rcc set register */
+ writel(BIT(offset), priv->base + bank);
+ else
+ setbits_le32(priv->base + bank, BIT(offset));
return 0;
}
@@ -48,7 +58,11 @@ static int stm32_reset_deassert(struct reset_ctl *reset_ctl)
debug("%s: reset id = %ld bank = %d offset = %d)\n", __func__,
reset_ctl->id, bank, offset);
- clrbits_le32(priv->base + bank, BIT(offset));
+ if (dev_get_driver_data(reset_ctl->dev) == RCC_STM32MP)
+ /* reset deassert is done in rcc clr register */
+ writel(BIT(offset), priv->base + bank + RCC_CL);
+ else
+ clrbits_le32(priv->base + bank, BIT(offset));
return 0;
}
@@ -64,16 +78,26 @@ static int stm32_reset_probe(struct udevice *dev)
{
struct stm32_reset_priv *priv = dev_get_priv(dev);
- priv->base = devfdt_get_addr(dev);
- if (priv->base == FDT_ADDR_T_NONE)
- return -EINVAL;
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE) {
+ /* for MFD, get address of parent */
+ priv->base = dev_read_addr(dev->parent);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ }
return 0;
}
+static const struct udevice_id stm32_reset_ids[] = {
+ { .compatible = "st,stm32mp1-rcc-rst", .data = RCC_STM32MP },
+ { }
+};
+
U_BOOT_DRIVER(stm32_rcc_reset) = {
.name = "stm32_rcc_reset",
.id = UCLASS_RESET,
+ .of_match = stm32_reset_ids,
.probe = stm32_reset_probe,
.priv_auto_alloc_size = sizeof(struct stm32_reset_priv),
.ops = &stm32_reset_ops,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 95ac031243..277dc3de73 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -30,6 +30,18 @@ config RTC_DS1307
Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and
compatible Real Time Clock devices.
+config RTC_ISL1208
+ bool "Enable ISL1208 driver"
+ depends on DM_RTC
+ help
+ The Renesas (formerly Intersil) ISL1208 is a I2C Real Time Clock (RTC) and
+ calendar with automatic leap year correction, 2-byte battery backed SRAM,
+ automatic power switch-over, alarm function and 15 selectable frequency
+ outputs.
+
+ This driver supports reading and writing the RTC/calendar and detects
+ total power failures.
+
config RTC_RX8010SJ
bool "Enable RX8010SJ driver"
depends on DM_RTC
diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c
index 5df15c7fd6..5e74b93b72 100644
--- a/drivers/rtc/ds1307.c
+++ b/drivers/rtc/ds1307.c
@@ -184,25 +184,8 @@ int rtc_set (struct rtc_time *tmp)
*/
void rtc_reset (void)
{
- struct rtc_time tmp;
-
rtc_write (RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */
rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0);
-
- tmp.tm_year = 1970;
- tmp.tm_mon = 1;
- tmp.tm_mday= 1;
- tmp.tm_hour = 0;
- tmp.tm_min = 0;
- tmp.tm_sec = 0;
-
- rtc_set(&tmp);
-
- printf ( "RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
- tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
-
- return;
}
@@ -321,14 +304,6 @@ read_rtc:
static int ds1307_rtc_reset(struct udevice *dev)
{
int ret;
- struct rtc_time tmp = {
- .tm_year = 1970,
- .tm_mon = 1,
- .tm_mday = 1,
- .tm_hour = 0,
- .tm_min = 0,
- .tm_sec = 0,
- };
/* clear Clock Halt */
ret = dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, 0x00);
@@ -340,14 +315,6 @@ static int ds1307_rtc_reset(struct udevice *dev)
if (ret < 0)
return ret;
- ret = ds1307_rtc_set(dev, &tmp);
- if (ret < 0)
- return ret;
-
- debug("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
- tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
-
return 0;
}
diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c
index 78473570b9..9e440d8457 100644
--- a/drivers/rtc/ds1374.c
+++ b/drivers/rtc/ds1374.c
@@ -172,8 +172,6 @@ int rtc_set (struct rtc_time *tmp){
*/
void rtc_reset (void){
- struct rtc_time tmp;
-
/* clear status flags */
rtc_write(RTC_SR_ADDR, (RTC_SR_BIT_AF|RTC_SR_BIT_OSF), false); /* clearing OSF and AF */
@@ -189,19 +187,6 @@ void rtc_reset (void){
|RTC_CTL_BIT_BBSQW), true);/* disable WD/ALM, WDSTR set to INT-pin,
set BBSQW and SQW to 32k
- set to 1 */
- tmp.tm_year = 1970;
- tmp.tm_mon = 1;
- tmp.tm_mday= 1;
- tmp.tm_hour = 0;
- tmp.tm_min = 0;
- tmp.tm_sec = 0;
-
- rtc_set(&tmp);
-
- printf("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
- tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
-
rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR, 0xAC, true);
rtc_write(RTC_WD_ALM_CNT_BYTE1_ADDR, 0xDE, true);
rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR, 0xAD, true);
diff --git a/drivers/rtc/isl1208.c b/drivers/rtc/isl1208.c
index 807e2e404e..fa1178a36e 100644
--- a/drivers/rtc/isl1208.c
+++ b/drivers/rtc/isl1208.c
@@ -14,6 +14,7 @@
#include <common.h>
#include <command.h>
+#include <dm.h>
#include <rtc.h>
#include <i2c.h>
@@ -51,45 +52,38 @@
#define RTC_STAT_BIT_BAT 0x02 /* BATTERY BIT */
#define RTC_STAT_BIT_RTCF 0x01 /* REAL TIME CLOCK FAIL BIT */
-static uchar rtc_read (uchar reg);
-static void rtc_write (uchar reg, uchar val);
-
/*
* Get the current time from the RTC
*/
-int rtc_get (struct rtc_time *tmp)
+static int isl1208_rtc_get(struct udevice *dev, struct rtc_time *tmp)
{
- int rel = 0;
- uchar sec, min, hour, mday, wday, mon, year, status;
-
- status = rtc_read (RTC_STAT_REG_ADDR);
- sec = rtc_read (RTC_SEC_REG_ADDR);
- min = rtc_read (RTC_MIN_REG_ADDR);
- hour = rtc_read (RTC_HR_REG_ADDR);
- wday = rtc_read (RTC_DAY_REG_ADDR);
- mday = rtc_read (RTC_DATE_REG_ADDR);
- mon = rtc_read (RTC_MON_REG_ADDR);
- year = rtc_read (RTC_YR_REG_ADDR);
-
- DEBUGR ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
- "hr: %02x min: %02x sec: %02x status: %02x\n",
- year, mon, mday, wday, hour, min, sec, status);
-
- if (status & RTC_STAT_BIT_RTCF) {
+ int ret;
+ uchar buf[8], val;
+
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ if (buf[RTC_STAT_REG_ADDR] & RTC_STAT_BIT_RTCF) {
printf ("### Warning: RTC oscillator has stopped\n");
- rtc_write(RTC_STAT_REG_ADDR,
- rtc_read(RTC_STAT_REG_ADDR) &~ (RTC_STAT_BIT_BAT|RTC_STAT_BIT_RTCF));
- rel = -1;
+ ret = dm_i2c_read(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ val = val & ~(RTC_STAT_BIT_BAT | RTC_STAT_BIT_RTCF);
+ ret = dm_i2c_write(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
}
- tmp->tm_sec = bcd2bin (sec & 0x7F);
- tmp->tm_min = bcd2bin (min & 0x7F);
- tmp->tm_hour = bcd2bin (hour & 0x3F);
- tmp->tm_mday = bcd2bin (mday & 0x3F);
- tmp->tm_mon = bcd2bin (mon & 0x1F);
- tmp->tm_year = bcd2bin (year)+2000;
- tmp->tm_wday = bcd2bin (wday & 0x07);
+ tmp->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F);
+ tmp->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F);
+ tmp->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F);
+ tmp->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F);
+ tmp->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F);
+ tmp->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + 2000;
+ tmp->tm_wday = bcd2bin(buf[RTC_DAY_REG_ADDR] & 0x07);
tmp->tm_yday = 0;
tmp->tm_isdst= 0;
@@ -97,51 +91,88 @@ int rtc_get (struct rtc_time *tmp)
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- return rel;
+ return 0;
}
/*
* Set the RTC
*/
-int rtc_set (struct rtc_time *tmp)
+static int isl1208_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
{
+ int ret;
+ uchar val, buf[7];
+
DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ if (tmp->tm_year < 2000 || tmp->tm_year > 2099)
+ printf("WARNING: year should be between 2000 and 2099!\n");
+
/* enable write */
- rtc_write(RTC_STAT_REG_ADDR,
- rtc_read(RTC_STAT_REG_ADDR) | RTC_STAT_BIT_WRTC);
+ ret = dm_i2c_read(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ val = val | RTC_STAT_BIT_WRTC;
+
+ ret = dm_i2c_write(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ buf[RTC_YR_REG_ADDR] = bin2bcd(tmp->tm_year % 100);
+ buf[RTC_MON_REG_ADDR] = bin2bcd(tmp->tm_mon);
+ buf[RTC_DAY_REG_ADDR] = bin2bcd(tmp->tm_wday);
+ buf[RTC_DATE_REG_ADDR] = bin2bcd(tmp->tm_mday);
+ buf[RTC_HR_REG_ADDR] = bin2bcd(tmp->tm_hour) | 0x80; /* 24h clock */
+ buf[RTC_MIN_REG_ADDR] = bin2bcd(tmp->tm_min);
+ buf[RTC_SEC_REG_ADDR] = bin2bcd(tmp->tm_sec);
- rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
- rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon));
- rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday));
- rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
- rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour) | 0x80 ); /* 24h clock */
- rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
- rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+ ret = dm_i2c_write(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
/* disable write */
- rtc_write(RTC_STAT_REG_ADDR,
- rtc_read(RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_WRTC);
+ ret = dm_i2c_read(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ val = val & ~RTC_STAT_BIT_WRTC;
+ ret = dm_i2c_write(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
return 0;
}
-void rtc_reset (void)
+static int isl1208_rtc_reset(struct udevice *dev)
{
+ return 0;
}
-/*
- * Helper functions
- */
-
-static uchar rtc_read (uchar reg)
+static int isl1208_probe(struct udevice *dev)
{
- return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
-}
+ i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+ DM_I2C_CHIP_WR_ADDRESS);
-static void rtc_write (uchar reg, uchar val)
-{
- i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+ return 0;
}
+
+static const struct rtc_ops isl1208_rtc_ops = {
+ .get = isl1208_rtc_get,
+ .set = isl1208_rtc_set,
+ .reset = isl1208_rtc_reset,
+};
+
+static const struct udevice_id isl1208_rtc_ids[] = {
+ { .compatible = "isil,isl1208" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_isl1208) = {
+ .name = "rtc-isl1208",
+ .id = UCLASS_RTC,
+ .probe = isl1208_probe,
+ .of_match = isl1208_rtc_ids,
+ .ops = &isl1208_rtc_ops,
+};
diff --git a/drivers/rtc/mx27rtc.c b/drivers/rtc/mx27rtc.c
index 29ccdf1730..b42770e05b 100644
--- a/drivers/rtc/mx27rtc.c
+++ b/drivers/rtc/mx27rtc.c
@@ -61,9 +61,5 @@ int rtc_set(struct rtc_time *time)
void rtc_reset(void)
{
- struct rtc_regs *rtc_regs = (struct rtc_regs *)IMX_RTC_BASE;
-
- writel(0, &rtc_regs->dayr);
- writel(0, &rtc_regs->hourmin);
- writel(0, &rtc_regs->seconds);
+ /* nothing to do */
}
diff --git a/drivers/rtc/rs5c372.c b/drivers/rtc/rs5c372.c
index 65f45ea5e3..c815c915d5 100644
--- a/drivers/rtc/rs5c372.c
+++ b/drivers/rtc/rs5c372.c
@@ -247,35 +247,13 @@ int rtc_set (struct rtc_time *tmp)
}
/*
- * Reset the RTC. We set the date back to 1970-01-01.
+ * Reset the RTC.
*/
void
rtc_reset (void)
{
- struct rtc_time tmp;
-
if (!setup_done)
rs5c372_enable();
-
- if (!setup_done)
- return;
-
- tmp.tm_year = 1970;
- tmp.tm_mon = 1;
- /* Jan. 1, 1970 was a Thursday */
- tmp.tm_wday= 4;
- tmp.tm_mday= 1;
- tmp.tm_hour = 0;
- tmp.tm_min = 0;
- tmp.tm_sec = 0;
-
- rtc_set(&tmp);
-
- printf ("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
- tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
-
- return;
}
#endif
diff --git a/drivers/rtc/rx8025.c b/drivers/rtc/rx8025.c
index b4a149b738..c43966a50d 100644
--- a/drivers/rtc/rx8025.c
+++ b/drivers/rtc/rx8025.c
@@ -163,11 +163,10 @@ int rtc_set (struct rtc_time *tmp)
}
/*
- * Reset the RTC. We setting the date back to 1970-01-01.
+ * Reset the RTC
*/
void rtc_reset (void)
{
- struct rtc_time tmp;
uchar buf[16];
uchar ctl2;
@@ -178,21 +177,6 @@ void rtc_reset (void)
ctl2 &= ~(RTC_CTL2_BIT_PON | RTC_CTL2_BIT_VDET);
ctl2 |= RTC_CTL2_BIT_XST | RTC_CTL2_BIT_VDSL;
rtc_write (RTC_CTL2_REG_ADDR, ctl2);
-
- tmp.tm_year = 1970;
- tmp.tm_mon = 1;
- tmp.tm_mday= 1;
- tmp.tm_hour = 0;
- tmp.tm_min = 0;
- tmp.tm_sec = 0;
-
- rtc_set(&tmp);
-
- printf ( "RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
- tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
-
- return;
}
/*
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 93e602e0ee..3d5b2bf15f 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -24,6 +24,15 @@ config REQUIRE_SERIAL_CONSOLE
during serial port initialization (default y). Set this to n on
boards which have no debug serial port whatsoever.
+config SPECIFY_CONSOLE_INDEX
+ bool "Specify the port number used for console"
+ default y if !DM_SERIAL || (SPL && !SPL_DM_SERIAL) || \
+ (TPL && !TPL_DM_SERIAL)
+ help
+ In various cases, we need to specify which of the UART devices that
+ a board or SoC has available are to be used for the console device
+ in U-Boot.
+
config SERIAL_PRESENT
bool "Provide a serial driver"
depends on DM_SERIAL
@@ -44,16 +53,39 @@ config SPL_SERIAL_PRESENT
This option enables the full UART in SPL, so if is it disabled,
the full UART driver will be omitted, thus saving space.
+# Logic to allow us to use the imply keyword to set what the default port
+# should be. The default is otherwise 1.
+config CONS_INDEX_0
+ bool
+
+config CONS_INDEX_2
+ bool
+
+config CONS_INDEX_3
+ bool
+
+config CONS_INDEX_4
+ bool
+
+config CONS_INDEX_5
+ bool
+
+config CONS_INDEX_6
+ bool
+
config CONS_INDEX
int "UART used for console"
- depends on ARCH_SUNXI
- default 2 if MACH_SUN5I
- default 5 if MACH_SUN8I_A23 || MACH_SUN8I_A33
+ depends on SPECIFY_CONSOLE_INDEX
+ range 0 6
+ default 0 if CONS_INDEX_0
+ default 2 if CONS_INDEX_2
+ default 3 if CONS_INDEX_3
+ default 4 if CONS_INDEX_4
+ default 5 if CONS_INDEX_5
+ default 6 if CONS_INDEX_6
default 1
help
- Configures the console index.
- For Allwinner SoC., default values are 2 for SUN5I and 5 for A23/A33.
- Otherwise, the index equals 1.
+ Set this to match the UART number of the serial console.
config DM_SERIAL
bool "Enable Driver Model for serial drivers"
@@ -93,8 +125,8 @@ config SERIAL_SEARCH_ALL
config SPL_DM_SERIAL
bool "Enable Driver Model for serial drivers in SPL"
- depends on DM_SERIAL
- default y if SPL && DM_SERIAL
+ depends on DM_SERIAL && SPL_DM
+ default y
help
Enable driver model for serial in SPL. This replaces
drivers/serial/serial.c with the serial uclass, which
@@ -577,10 +609,10 @@ config STI_ASC_SERIAL
config STM32_SERIAL
bool "STMicroelectronics STM32 SoCs on-chip UART"
- depends on DM_SERIAL && (STM32F4 || STM32F7 || STM32H7)
+ depends on DM_SERIAL && (STM32F4 || STM32F7 || STM32H7 || ARCH_STM32MP)
help
- If you have a machine based on a STM32 F4, F7 or H7 SoC you can
- enable its onboard serial ports, say Y to this option.
+ If you have a machine based on a STM32 F4, F7, H7 or MP1 SOC
+ you can enable its onboard serial ports, say Y to this option.
If unsure, say N.
config ZYNQ_SERIAL
@@ -592,7 +624,7 @@ config ZYNQ_SERIAL
config MPC8XX_CONS
bool "Console driver for MPC8XX"
- depends on 8xx
+ depends on MPC8xx
default y
choice
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index cac9a8b312..6937ef9628 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -5,11 +5,27 @@
# SPDX-License-Identifier: GPL-2.0+
#
+ifdef CONFIG_SPL_BUILD
+
+ifeq ($(CONFIG_$(SPL_TPL_)BUILD)$(CONFIG_$(SPL_TPL_)DM_SERIAL),yy)
+obj-y += serial-uclass.o
+else
+obj-y += serial.o
+endif
+
+else
+
ifdef CONFIG_DM_SERIAL
-obj-$(CONFIG_$(SPL_TPL_)DM_SERIAL) += serial-uclass.o
-obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
+obj-y += serial-uclass.o
else
obj-y += serial.o
+endif
+
+endif
+
+ifdef CONFIG_DM_SERIAL
+obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
+else
obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index cc4bdcb834..397c6f5203 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -109,48 +109,16 @@ U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
void name(void) \
__attribute__((weak, alias("serial_null")));
-serial_initfunc(amirix_serial_initialize);
-serial_initfunc(arc_serial_initialize);
-serial_initfunc(arm_dcc_initialize);
-serial_initfunc(asc_serial_initialize);
serial_initfunc(atmel_serial_initialize);
serial_initfunc(au1x00_serial_initialize);
-serial_initfunc(bfin_jtag_initialize);
-serial_initfunc(bfin_serial_initialize);
-serial_initfunc(bmw_serial_initialize);
-serial_initfunc(clps7111_serial_initialize);
-serial_initfunc(cogent_serial_initialize);
-serial_initfunc(cpci750_serial_initialize);
-serial_initfunc(evb64260_serial_initialize);
-serial_initfunc(imx_serial_initialize);
-serial_initfunc(iop480_serial_initialize);
-serial_initfunc(jz_serial_initialize);
-serial_initfunc(leon2_serial_initialize);
-serial_initfunc(leon3_serial_initialize);
-serial_initfunc(lh7a40x_serial_initialize);
-serial_initfunc(lpc32xx_serial_initialize);
-serial_initfunc(marvell_serial_initialize);
-serial_initfunc(max3100_serial_initialize);
serial_initfunc(mcf_serial_initialize);
-serial_initfunc(ml2_serial_initialize);
serial_initfunc(mpc85xx_serial_initialize);
serial_initfunc(mpc8xx_serial_initialize);
serial_initfunc(mxc_serial_initialize);
-serial_initfunc(mxs_auart_initialize);
serial_initfunc(ns16550_serial_initialize);
-serial_initfunc(oc_serial_initialize);
-serial_initfunc(p3mx_serial_initialize);
serial_initfunc(pl01x_serial_initialize);
serial_initfunc(pxa_serial_initialize);
-serial_initfunc(s3c24xx_serial_initialize);
-serial_initfunc(s5p_serial_initialize);
-serial_initfunc(sa1100_serial_initialize);
-serial_initfunc(sandbox_serial_initialize);
-serial_initfunc(sconsole_serial_initialize);
serial_initfunc(sh_serial_initialize);
-serial_initfunc(stm32_serial_initialize);
-serial_initfunc(uartlite_serial_initialize);
-serial_initfunc(zynq_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
@@ -196,48 +164,16 @@ void serial_register(struct serial_device *dev)
*/
void serial_initialize(void)
{
- amirix_serial_initialize();
- arc_serial_initialize();
- arm_dcc_initialize();
- asc_serial_initialize();
atmel_serial_initialize();
au1x00_serial_initialize();
- bfin_jtag_initialize();
- bfin_serial_initialize();
- bmw_serial_initialize();
- clps7111_serial_initialize();
- cogent_serial_initialize();
- cpci750_serial_initialize();
- evb64260_serial_initialize();
- imx_serial_initialize();
- iop480_serial_initialize();
- jz_serial_initialize();
- leon2_serial_initialize();
- leon3_serial_initialize();
- lh7a40x_serial_initialize();
- lpc32xx_serial_initialize();
- marvell_serial_initialize();
- max3100_serial_initialize();
mcf_serial_initialize();
- ml2_serial_initialize();
mpc85xx_serial_initialize();
mpc8xx_serial_initialize();
mxc_serial_initialize();
- mxs_auart_initialize();
ns16550_serial_initialize();
- oc_serial_initialize();
- p3mx_serial_initialize();
pl01x_serial_initialize();
pxa_serial_initialize();
- s3c24xx_serial_initialize();
- s5p_serial_initialize();
- sa1100_serial_initialize();
- sandbox_serial_initialize();
- sconsole_serial_initialize();
sh_serial_initialize();
- stm32_serial_initialize();
- uartlite_serial_initialize();
- zynq_serial_initialize();
serial_assign(default_serial_console()->name);
}
diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c
index 363affb8c5..6412ca6496 100644
--- a/drivers/serial/serial_meson.c
+++ b/drivers/serial/serial_meson.c
@@ -125,6 +125,7 @@ static const struct dm_serial_ops meson_serial_ops = {
static const struct udevice_id meson_serial_ids[] = {
{ .compatible = "amlogic,meson-uart" },
+ { .compatible = "amlogic,meson-gx-uart" },
{ }
};
diff --git a/drivers/serial/serial_mpc8xx.c b/drivers/serial/serial_mpc8xx.c
index 26a8085a69..7a5908f464 100644
--- a/drivers/serial/serial_mpc8xx.c
+++ b/drivers/serial/serial_mpc8xx.c
@@ -6,10 +6,10 @@
*/
#include <common.h>
-#include <commproc.h>
#include <command.h>
#include <serial.h>
#include <watchdog.h>
+#include <asm/cpm_8xx.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index a17698f90e..5f4ace7848 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -270,6 +270,8 @@ U_BOOT_DRIVER(serial_sh) = {
# define SCIF_BASE SCIF6_BASE
#elif defined(CONFIG_CONS_SCIF7)
# define SCIF_BASE SCIF7_BASE
+#elif defined(CONFIG_CONS_SCIFA0)
+# define SCIF_BASE SCIFA0_BASE
#else
# error "Default SCIF doesn't set....."
#endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 235a8c7d73..ec92b84ed2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -23,6 +23,13 @@ config ALTERA_SPI
IP core. Please find details on the "Embedded Peripherals IP
User Guide" of Altera.
+config ATCSPI200_SPI
+ bool "Andestech ATCSPI200 SPI driver"
+ help
+ Enable the Andestech ATCSPI200 SPI driver. This driver can be
+ used to access the SPI flash on AE3XX and AE250 platforms embedding
+ this Andestech IP core.
+
config ATH79_SPI
bool "Atheros SPI driver"
depends on ARCH_ATH79
@@ -34,7 +41,7 @@ config ATH79_SPI
config ATMEL_SPI
bool "Atmel SPI driver"
- depends on ARCH_AT91
+ default y if ARCH_AT91
help
This enables driver for the Atmel SPI Controller, present on
many AT91 (ARM) chips. This driver can be used to access
@@ -107,6 +114,14 @@ config PIC32_SPI
to access the SPI NOR flash, MMC-over-SPI on platforms based on
Microchip PIC32 family devices.
+config RENESAS_RPC_SPI
+ bool "Renesas RPC SPI driver"
+ depends on RCAR_GEN3
+ help
+ Enable the Renesas RPC SPI driver, used to access SPI NOR flash
+ on Renesas RCar Gen3 SoCs. This uses driver model and requires a
+ device tree binding to operate.
+
config ROCKCHIP_SPI
bool "Rockchip SPI driver"
help
@@ -232,13 +247,6 @@ config FSL_QSPI
used to access the SPI NOR flash on platforms embedding this
Freescale IP core.
-config ATCSPI200_SPI
- bool "Andestech ATCSPI200 SPI driver"
- help
- Enable the Andestech ATCSPI200 SPI driver. This driver can be
- used to access the SPI flash on AE3XX and AE250 platforms embedding
- this Andestech IP core.
-
config DAVINCI_SPI
bool "Davinci & Keystone SPI driver"
depends on ARCH_DAVINCI || ARCH_KEYSTONE
@@ -276,7 +284,7 @@ config LPC32XX_SSP
config MPC8XX_SPI
bool "MPC8XX SPI Driver"
- depends on 8xx
+ depends on MPC8xx
help
Enable support for SPI on MPC8XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4b6000fd9a..176bfa05cf 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_MXS_SPI) += mxs_spi.o
obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o
obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
obj-$(CONFIG_PIC32_SPI) += pic32_spi.o
+obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
obj-$(CONFIG_SH_SPI) += sh_spi.o
diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c
index 5b2e9d6264..bc08914b9e 100644
--- a/drivers/spi/atcspi200_spi.c
+++ b/drivers/spi/atcspi200_spi.c
@@ -75,9 +75,6 @@ struct atcspi200_spi_regs {
};
struct nds_spi_slave {
-#ifndef CONFIG_DM_SPI
- struct spi_slave slave;
-#endif
volatile struct atcspi200_spi_regs *regs;
int to;
unsigned int freq;
@@ -286,89 +283,6 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
return ret;
}
-#ifndef CONFIG_DM_SPI
-#define to_nds_spi_slave(s) container_of(s, struct nds_spi_slave, slave)
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct nds_spi_slave *ns;
-
- if (!spi_cs_is_valid(bus, cs))
- return NULL;
-
- ns = spi_alloc_slave(struct nds_spi_slave, bus, cs);
- if (!ns)
- return NULL;
-
- switch (bus) {
- case SPI0_BUS:
- ns->regs = (struct atcspi200_spi_regs *)SPI0_BASE;
- break;
-
- case SPI1_BUS:
- ns->regs = (struct atcspi200_spi_regs *)SPI1_BASE;
- break;
-
- default:
- return NULL;
- }
-
- ns->freq= max_hz;
- ns->mode = mode;
- ns->to = SPI_TIMEOUT;
- ns->max_transfer_length = MAX_TRANSFER_LEN;
- ns->slave.max_write_size = MAX_TRANSFER_LEN;
-
- return &ns->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- free(ns);
-}
-
-void spi_init(void)
-{
- /* do nothing */
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- return __atcspi200_spi_claim_bus(ns);
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- __atcspi200_spi_release_bus(ns);
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
- void *data_in, unsigned long flags)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- return __atcspi200_spi_xfer(ns, bitlen, data_out, data_in, flags);
-}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- return bus == 0 && cs < NSPI_MAX_CS_NUM;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- __atcspi200_spi_start(ns);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- __atcspi200_spi_stop(ns);
-}
-#else
static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz)
{
struct nds_spi_slave *ns = dev_get_priv(bus);
@@ -496,4 +410,3 @@ U_BOOT_DRIVER(atcspi200_spi) = {
.priv_auto_alloc_size = sizeof(struct nds_spi_slave),
.probe = atcspi200_spi_probe,
};
-#endif
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 8010ab434c..3cdfd366ab 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -236,7 +236,9 @@ struct atmel_spi_priv {
unsigned int freq; /* Default frequency */
unsigned int mode;
ulong bus_clk_rate;
+#ifdef CONFIG_DM_GPIO
struct gpio_desc cs_gpios[MAX_CS_COUNT];
+#endif
};
static int atmel_spi_claim_bus(struct udevice *dev)
@@ -291,6 +293,7 @@ static int atmel_spi_release_bus(struct udevice *dev)
static void atmel_spi_cs_activate(struct udevice *dev)
{
+#ifdef CONFIG_DM_GPIO
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -300,10 +303,12 @@ static void atmel_spi_cs_activate(struct udevice *dev)
return;
dm_gpio_set_value(&priv->cs_gpios[cs], 0);
+#endif
}
static void atmel_spi_cs_deactivate(struct udevice *dev)
{
+#ifdef CONFIG_DM_GPIO
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -313,6 +318,7 @@ static void atmel_spi_cs_deactivate(struct udevice *dev)
return;
dm_gpio_set_value(&priv->cs_gpios[cs], 1);
+#endif
}
static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen,
@@ -462,8 +468,7 @@ static int atmel_spi_enable_clk(struct udevice *bus)
static int atmel_spi_probe(struct udevice *bus)
{
struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus);
- struct atmel_spi_priv *priv = dev_get_priv(bus);
- int i, ret;
+ int ret;
ret = atmel_spi_enable_clk(bus);
if (ret)
@@ -471,6 +476,10 @@ static int atmel_spi_probe(struct udevice *bus)
bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus);
+#ifdef CONFIG_DM_GPIO
+ struct atmel_spi_priv *priv = dev_get_priv(bus);
+ int i;
+
ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios,
ARRAY_SIZE(priv->cs_gpios), 0);
if (ret < 0) {
@@ -485,6 +494,7 @@ static int atmel_spi_probe(struct udevice *bus)
dm_gpio_set_dir_flags(&priv->cs_gpios[i],
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
}
+#endif
writel(ATMEL_SPI_CR_SWRST, &bus_plat->regs->cr);
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index c501aeea16..0e93b62eee 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -10,6 +10,7 @@
* SPDX-License-Identifier: GPL-2.0
*/
+#include <asm-generic/gpio.h>
#include <common.h>
#include <clk.h>
#include <dm.h>
@@ -18,6 +19,7 @@
#include <spi.h>
#include <fdtdec.h>
#include <linux/compat.h>
+#include <linux/iopoll.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -97,6 +99,8 @@ struct dw_spi_priv {
struct clk clk;
unsigned long bus_clk_rate;
+ struct gpio_desc cs_gpio; /* External chip-select gpio */
+
int bits_per_word;
u8 cs; /* chip select pin */
u8 tmode; /* TR/TO/RO/EEPROM */
@@ -110,24 +114,40 @@ struct dw_spi_priv {
void *rx_end;
};
-static inline u32 dw_readl(struct dw_spi_priv *priv, u32 offset)
+static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset)
{
return __raw_readl(priv->regs + offset);
}
-static inline void dw_writel(struct dw_spi_priv *priv, u32 offset, u32 val)
+static inline void dw_write(struct dw_spi_priv *priv, u32 offset, u32 val)
{
__raw_writel(val, priv->regs + offset);
}
-static inline u16 dw_readw(struct dw_spi_priv *priv, u32 offset)
+static int request_gpio_cs(struct udevice *bus)
{
- return __raw_readw(priv->regs + offset);
-}
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+ int ret;
-static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val)
-{
- __raw_writew(val, priv->regs + offset);
+ /* External chip select gpio line is optional */
+ ret = gpio_request_by_name(bus, "cs-gpio", 0, &priv->cs_gpio, 0);
+ if (ret == -ENOENT)
+ return 0;
+
+ if (ret < 0) {
+ printf("Error: %d: Can't get %s gpio!\n", ret, bus->name);
+ return ret;
+ }
+
+ if (dm_gpio_is_valid(&priv->cs_gpio)) {
+ dm_gpio_set_dir_flags(&priv->cs_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ }
+
+ debug("%s: used external gpio for CS management\n", __func__);
+#endif
+ return 0;
}
static int dw_spi_ofdata_to_platdata(struct udevice *bus)
@@ -144,19 +164,19 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus)
debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs,
plat->frequency);
- return 0;
+ return request_gpio_cs(bus);
}
static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable)
{
- dw_writel(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
+ dw_write(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
}
/* Restart the controller, disable all interrupts, clean rx fifo */
static void spi_hw_init(struct dw_spi_priv *priv)
{
spi_enable_chip(priv, 0);
- dw_writel(priv, DW_SPI_IMR, 0xff);
+ dw_write(priv, DW_SPI_IMR, 0xff);
spi_enable_chip(priv, 1);
/*
@@ -167,13 +187,13 @@ static void spi_hw_init(struct dw_spi_priv *priv)
u32 fifo;
for (fifo = 1; fifo < 256; fifo++) {
- dw_writew(priv, DW_SPI_TXFLTR, fifo);
- if (fifo != dw_readw(priv, DW_SPI_TXFLTR))
+ dw_write(priv, DW_SPI_TXFLTR, fifo);
+ if (fifo != dw_read(priv, DW_SPI_TXFLTR))
break;
}
priv->fifo_len = (fifo == 1) ? 0 : fifo;
- dw_writew(priv, DW_SPI_TXFLTR, 0);
+ dw_write(priv, DW_SPI_TXFLTR, 0);
}
debug("%s: fifo_len=%d\n", __func__, priv->fifo_len);
}
@@ -242,7 +262,7 @@ static inline u32 tx_max(struct dw_spi_priv *priv)
u32 tx_left, tx_room, rxtx_gap;
tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3);
- tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR);
+ tx_room = priv->fifo_len - dw_read(priv, DW_SPI_TXFLR);
/*
* Another concern is about the tx/rx mismatch, we
@@ -263,7 +283,7 @@ static inline u32 rx_max(struct dw_spi_priv *priv)
{
u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3);
- return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR));
+ return min_t(u32, rx_left, dw_read(priv, DW_SPI_RXFLR));
}
static void dw_writer(struct dw_spi_priv *priv)
@@ -279,34 +299,22 @@ static void dw_writer(struct dw_spi_priv *priv)
else
txw = *(u16 *)(priv->tx);
}
- dw_writew(priv, DW_SPI_DR, txw);
+ dw_write(priv, DW_SPI_DR, txw);
debug("%s: tx=0x%02x\n", __func__, txw);
priv->tx += priv->bits_per_word >> 3;
}
}
-static int dw_reader(struct dw_spi_priv *priv)
+static void dw_reader(struct dw_spi_priv *priv)
{
- unsigned start = get_timer(0);
- u32 max;
+ u32 max = rx_max(priv);
u16 rxw;
- /* Wait for rx data to be ready */
- while (rx_max(priv) == 0) {
- if (get_timer(start) > RX_TIMEOUT)
- return -ETIMEDOUT;
- }
-
- max = rx_max(priv);
-
while (max--) {
- rxw = dw_readw(priv, DW_SPI_DR);
+ rxw = dw_read(priv, DW_SPI_DR);
debug("%s: rx=0x%02x\n", __func__, rxw);
- /*
- * Care about rx only if the transfer's original "rx" is
- * not null
- */
+ /* Care about rx if the transfer's original "rx" is not null */
if (priv->rx_end - priv->len) {
if (priv->bits_per_word == 8)
*(u8 *)(priv->rx) = rxw;
@@ -315,24 +323,30 @@ static int dw_reader(struct dw_spi_priv *priv)
}
priv->rx += priv->bits_per_word >> 3;
}
-
- return 0;
}
static int poll_transfer(struct dw_spi_priv *priv)
{
- int ret;
-
do {
dw_writer(priv);
- ret = dw_reader(priv);
- if (ret < 0)
- return ret;
+ dw_reader(priv);
} while (priv->rx_end > priv->rx);
return 0;
}
+static void external_cs_manage(struct udevice *dev, bool on)
+{
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+ struct dw_spi_priv *priv = dev_get_priv(dev->parent);
+
+ if (!dm_gpio_is_valid(&priv->cs_gpio))
+ return;
+
+ dm_gpio_set_value(&priv->cs_gpio, on ? 1 : 0);
+#endif
+}
+
static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
@@ -342,6 +356,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8 *rx = din;
int ret = 0;
u32 cr0 = 0;
+ u32 val;
u32 cs;
/* spi core configured to do 8 bit transfers */
@@ -350,6 +365,10 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
return -1;
}
+ /* Start the transaction if necessary. */
+ if (flags & SPI_XFER_BEGIN)
+ external_cs_manage(dev, false);
+
cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
(priv->mode << SPI_MODE_OFFSET) |
(priv->tmode << SPI_TMOD_OFFSET);
@@ -359,7 +378,11 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
else if (rx)
priv->tmode = SPI_TMOD_RO;
else
- priv->tmode = SPI_TMOD_TO;
+ /*
+ * In transmit only mode (SPI_TMOD_TO) input FIFO never gets
+ * any data which breaks our logic in poll_transfer() above.
+ */
+ priv->tmode = SPI_TMOD_TR;
cr0 &= ~SPI_TMOD_MASK;
cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
@@ -377,8 +400,8 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
debug("%s: cr0=%08x\n", __func__, cr0);
/* Reprogram cr0 only if changed */
- if (dw_readw(priv, DW_SPI_CTRL0) != cr0)
- dw_writew(priv, DW_SPI_CTRL0, cr0);
+ if (dw_read(priv, DW_SPI_CTRL0) != cr0)
+ dw_write(priv, DW_SPI_CTRL0, cr0);
/*
* Configure the desired SS (slave select 0...3) in the controller
@@ -386,7 +409,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
* automatically. So no cs_activate() etc is needed in this driver.
*/
cs = spi_chip_select(dev);
- dw_writel(priv, DW_SPI_SER, 1 << cs);
+ dw_write(priv, DW_SPI_SER, 1 << cs);
/* Enable controller after writing control registers */
spi_enable_chip(priv, 1);
@@ -394,6 +417,23 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Start transfer in a polling loop */
ret = poll_transfer(priv);
+ /*
+ * Wait for current transmit operation to complete.
+ * Otherwise if some data still exists in Tx FIFO it can be
+ * silently flushed, i.e. dropped on disabling of the controller,
+ * which happens when writing 0 to DW_SPI_SSIENR which happens
+ * in the beginning of new transfer.
+ */
+ if (readl_poll_timeout(priv->regs + DW_SPI_SR, val,
+ !(val & SR_TF_EMPT) || (val & SR_BUSY),
+ RX_TIMEOUT * 1000)) {
+ ret = -ETIMEDOUT;
+ }
+
+ /* Stop the transaction if necessary */
+ if (flags & SPI_XFER_END)
+ external_cs_manage(dev, true);
+
return ret;
}
@@ -412,7 +452,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed)
/* clk_div doesn't support odd number */
clk_div = priv->bus_clk_rate / speed;
clk_div = (clk_div + 1) & 0xfffe;
- dw_writel(priv, DW_SPI_BAUDR, clk_div);
+ dw_write(priv, DW_SPI_BAUDR, clk_div);
/* Enable controller after writing control registers */
spi_enable_chip(priv, 1);
diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c
index b5bd558526..eb035e9510 100644
--- a/drivers/spi/mpc8xx_spi.c
+++ b/drivers/spi/mpc8xx_spi.c
@@ -19,7 +19,7 @@
#include <common.h>
#include <mpc8xx.h>
-#include <commproc.h>
+#include <asm/cpm_8xx.h>
#include <linux/ctype.h>
#include <malloc.h>
#include <post.h>
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 1da4542af0..1ac691a68e 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -456,9 +456,6 @@ static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv)
conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
writel(conf, &priv->regs->modulctrl);
-
- _omap3_spi_set_mode(priv);
- _omap3_spi_set_speed(priv);
}
#ifndef CONFIG_DM_SPI
@@ -594,8 +591,6 @@ static int omap3_spi_claim_bus(struct udevice *dev)
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
priv->cs = slave_plat->cs;
- priv->mode = slave_plat->mode;
- priv->freq = slave_plat->max_hz;
_omap3_spi_claim_bus(priv);
return 0;
@@ -635,8 +630,10 @@ static int omap3_spi_probe(struct udevice *dev)
(struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset);
- priv->pin_dir = fdtdec_get_uint(blob, node, "ti,pindir-d0-out-d1-in",
- MCSPI_PINDIR_D0_IN_D1_OUT);
+ if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in"))
+ priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
+ else
+ priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
priv->wordlen = SPI_DEFAULT_WORDLEN;
return 0;
}
@@ -650,13 +647,29 @@ static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen,
return _spi_xfer(priv, bitlen, dout, din, flags);
}
-static int omap3_spi_set_speed(struct udevice *bus, unsigned int speed)
+static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed)
{
+ struct udevice *bus = dev->parent;
+ struct omap3_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ priv->cs = slave_plat->cs;
+ priv->freq = slave_plat->max_hz;
+ _omap3_spi_set_speed(priv);
+
return 0;
}
-static int omap3_spi_set_mode(struct udevice *bus, uint mode)
+static int omap3_spi_set_mode(struct udevice *dev, uint mode)
{
+ struct udevice *bus = dev->parent;
+ struct omap3_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ priv->cs = slave_plat->cs;
+ priv->mode = slave_plat->mode;
+ _omap3_spi_set_mode(priv);
+
return 0;
}
diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c
new file mode 100644
index 0000000000..e54f24c5d8
--- /dev/null
+++ b/drivers/spi/renesas_rpc_spi.c
@@ -0,0 +1,465 @@
+/*
+ * Renesas RCar Gen3 RPC QSPI driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <linux/errno.h>
+#include <spi.h>
+#include <wait_bit.h>
+
+#define RPC_CMNCR 0x0000 /* R/W */
+#define RPC_CMNCR_MD BIT(31)
+#define RPC_CMNCR_SFDE BIT(24)
+#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
+#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
+#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
+#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
+#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
+#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
+#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
+#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+ RPC_CMNCR_IO3FV(3))
+#define RPC_CMNCR_CPHAT BIT(6)
+#define RPC_CMNCR_CPHAR BIT(5)
+#define RPC_CMNCR_SSLP BIT(4)
+#define RPC_CMNCR_CPOL BIT(3)
+#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+
+#define RPC_SSLDR 0x0004 /* R/W */
+#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+
+#define RPC_DRCR 0x000C /* R/W */
+#define RPC_DRCR_SSLN BIT(24)
+#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+#define RPC_DRCR_RCF BIT(9)
+#define RPC_DRCR_RBE BIT(8)
+#define RPC_DRCR_SSLE BIT(0)
+
+#define RPC_DRCMR 0x0010 /* R/W */
+#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_DREAR 0x0014 /* R/W */
+#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
+#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
+
+#define RPC_DROPR 0x0018 /* R/W */
+#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
+#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
+
+#define RPC_DRENR 0x001C /* R/W */
+#define RPC_DRENR_CDB(o) (u32)((((o) & 0x3) << 30))
+#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_DRENR_DME BIT(15)
+#define RPC_DRENR_CDE BIT(14)
+#define RPC_DRENR_OCDE BIT(12)
+#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
+
+#define RPC_SMCR 0x0020 /* R/W */
+#define RPC_SMCR_SSLKP BIT(8)
+#define RPC_SMCR_SPIRE BIT(2)
+#define RPC_SMCR_SPIWE BIT(1)
+#define RPC_SMCR_SPIE BIT(0)
+
+#define RPC_SMCMR 0x0024 /* R/W */
+#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_SMADR 0x0028 /* R/W */
+#define RPC_SMOPR 0x002C /* R/W */
+#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
+#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
+
+#define RPC_SMENR 0x0030 /* R/W */
+#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
+#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_SMENR_DME BIT(15)
+#define RPC_SMENR_CDE BIT(14)
+#define RPC_SMENR_OCDE BIT(12)
+#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
+#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
+
+#define RPC_SMRDR0 0x0038 /* R */
+#define RPC_SMRDR1 0x003C /* R */
+#define RPC_SMWDR0 0x0040 /* R/W */
+#define RPC_SMWDR1 0x0044 /* R/W */
+#define RPC_CMNSR 0x0048 /* R */
+#define RPC_CMNSR_SSLF BIT(1)
+#define RPC_CMNSR_TEND BIT(0)
+
+#define RPC_DRDMCR 0x0058 /* R/W */
+#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_DRDRENR 0x005C /* R/W */
+#define RPC_DRDRENR_HYPE (0x5 << 12)
+#define RPC_DRDRENR_ADDRE BIT(8)
+#define RPC_DRDRENR_OPDRE BIT(4)
+#define RPC_DRDRENR_DRDRE BIT(0)
+
+#define RPC_SMDMCR 0x0060 /* R/W */
+#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_SMDRENR 0x0064 /* R/W */
+#define RPC_SMDRENR_HYPE (0x5 << 12)
+#define RPC_SMDRENR_ADDRE BIT(8)
+#define RPC_SMDRENR_OPDRE BIT(4)
+#define RPC_SMDRENR_SPIDRE BIT(0)
+
+#define RPC_PHYCNT 0x007C /* R/W */
+#define RPC_PHYCNT_CAL BIT(31)
+#define PRC_PHYCNT_OCTA_AA BIT(22)
+#define PRC_PHYCNT_OCTA_SA BIT(23)
+#define PRC_PHYCNT_EXDS BIT(21)
+#define RPC_PHYCNT_OCT BIT(20)
+#define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15)
+#define RPC_PHYCNT_WBUF2 BIT(4)
+#define RPC_PHYCNT_WBUF BIT(2)
+#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
+
+#define RPC_PHYINT 0x0088 /* R/W */
+#define RPC_PHYINT_RSTEN BIT(18)
+#define RPC_PHYINT_WPEN BIT(17)
+#define RPC_PHYINT_INTEN BIT(16)
+#define RPC_PHYINT_RST BIT(2)
+#define RPC_PHYINT_WP BIT(1)
+#define RPC_PHYINT_INT BIT(0)
+
+#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
+#define RPC_WBUF_SIZE 0x100
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rpc_spi_platdata {
+ fdt_addr_t regs;
+ fdt_addr_t extr;
+ s32 freq; /* Default clock freq, -1 for none */
+};
+
+struct rpc_spi_priv {
+ fdt_addr_t regs;
+ fdt_addr_t extr;
+ struct clk clk;
+
+ u8 cmdcopy[8];
+ u32 cmdlen;
+ bool cmdstarted;
+};
+
+static int rpc_spi_wait_sslf(struct udevice *dev)
+{
+ struct rpc_spi_priv *priv = dev_get_priv(dev->parent);
+
+ return wait_for_bit_le32((void *)priv->regs + RPC_CMNSR, RPC_CMNSR_SSLF,
+ false, 1000, false);
+}
+
+static int rpc_spi_wait_tend(struct udevice *dev)
+{
+ struct rpc_spi_priv *priv = dev_get_priv(dev->parent);
+
+ return wait_for_bit_le32((void *)priv->regs + RPC_CMNSR, RPC_CMNSR_TEND,
+ true, 1000, false);
+}
+
+static void rpc_spi_flush_read_cache(struct udevice *dev)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+
+ /* Flush read cache */
+ writel(RPC_DRCR_SSLN | RPC_DRCR_RBURST(0x1f) |
+ RPC_DRCR_RCF | RPC_DRCR_RBE | RPC_DRCR_SSLE,
+ priv->regs + RPC_DRCR);
+ readl(priv->regs + RPC_DRCR);
+
+}
+
+static int rpc_spi_claim_bus(struct udevice *dev, bool manual)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+
+ /*
+ * NOTE: The 0x260 are undocumented bits, but they must be set.
+ * NOTE: On H3 ES1.x (not supported in mainline U-Boot), the
+ * RPC_PHYCNT_STRTIM shall be 0, while on newer parts, the
+ * RPC_PHYCNT_STRTIM shall be 6.
+ */
+ writel(RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(6) | 0x260,
+ priv->regs + RPC_PHYCNT);
+ writel((manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_SFDE |
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | RPC_CMNCR_BSZ(0),
+ priv->regs + RPC_CMNCR);
+
+ writel(RPC_SSLDR_SPNDL(7) | RPC_SSLDR_SLNDL(7) |
+ RPC_SSLDR_SCKDL(7), priv->regs + RPC_SSLDR);
+
+ rpc_spi_flush_read_cache(dev);
+
+ return 0;
+}
+
+static int rpc_spi_release_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+
+ /* NOTE: The 0x260 are undocumented bits, but they must be set. */
+ writel(RPC_PHYCNT_STRTIM(6) | 0x260, priv->regs + RPC_PHYCNT);
+
+ rpc_spi_flush_read_cache(dev);
+
+ return 0;
+}
+
+static int rpc_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+ u32 wlen = dout ? (bitlen / 8) : 0;
+ u32 rlen = din ? (bitlen / 8) : 0;
+ u32 wloop = DIV_ROUND_UP(wlen, 4);
+ u32 smenr, smcr, offset;
+ int ret = 0;
+
+ if (!priv->cmdstarted) {
+ if (!wlen || rlen)
+ BUG();
+
+ memcpy(priv->cmdcopy, dout, wlen);
+ priv->cmdlen = wlen;
+
+ /* Command transfer start */
+ priv->cmdstarted = true;
+ if (!(flags & SPI_XFER_END))
+ return 0;
+ }
+
+ offset = (priv->cmdcopy[1] << 16) | (priv->cmdcopy[2] << 8) |
+ (priv->cmdcopy[3] << 0);
+
+ smenr = 0;
+
+ if (wlen || (!rlen && !wlen) || flags == SPI_XFER_ONCE) {
+ if (wlen && flags == SPI_XFER_END)
+ smenr = RPC_SMENR_SPIDE(0xf);
+
+ rpc_spi_claim_bus(dev, true);
+
+ writel(0, priv->regs + RPC_SMCR);
+
+ if (priv->cmdlen >= 1) { /* Command(1) */
+ writel(RPC_SMCMR_CMD(priv->cmdcopy[0]),
+ priv->regs + RPC_SMCMR);
+ smenr |= RPC_SMENR_CDE;
+ } else {
+ writel(0, priv->regs + RPC_SMCMR);
+ }
+
+ if (priv->cmdlen >= 4) { /* Address(3) */
+ writel(offset, priv->regs + RPC_SMADR);
+ smenr |= RPC_SMENR_ADE(7);
+ } else {
+ writel(0, priv->regs + RPC_SMADR);
+ }
+
+ if (priv->cmdlen >= 5) { /* Dummy(n) */
+ writel(8 * (priv->cmdlen - 4) - 1,
+ priv->regs + RPC_SMDMCR);
+ smenr |= RPC_SMENR_DME;
+ } else {
+ writel(0, priv->regs + RPC_SMDMCR);
+ }
+
+ writel(0, priv->regs + RPC_SMOPR);
+
+ writel(0, priv->regs + RPC_SMDRENR);
+
+ if (wlen && flags == SPI_XFER_END) {
+ u32 *datout = (u32 *)dout;
+
+ while (wloop--) {
+ smcr = RPC_SMCR_SPIWE | RPC_SMCR_SPIE;
+ if (wloop >= 1)
+ smcr |= RPC_SMCR_SSLKP;
+ writel(smenr, priv->regs + RPC_SMENR);
+ writel(*datout, priv->regs + RPC_SMWDR0);
+ writel(smcr, priv->regs + RPC_SMCR);
+ ret = rpc_spi_wait_tend(dev);
+ if (ret)
+ goto err;
+ datout++;
+ smenr = RPC_SMENR_SPIDE(0xf);
+ }
+
+ ret = rpc_spi_wait_sslf(dev);
+
+ } else {
+ writel(smenr, priv->regs + RPC_SMENR);
+ writel(RPC_SMCR_SPIE, priv->regs + RPC_SMCR);
+ ret = rpc_spi_wait_tend(dev);
+ }
+ } else { /* Read data only, using DRx ext access */
+ rpc_spi_claim_bus(dev, false);
+
+ if (priv->cmdlen >= 1) { /* Command(1) */
+ writel(RPC_DRCMR_CMD(priv->cmdcopy[0]),
+ priv->regs + RPC_DRCMR);
+ smenr |= RPC_DRENR_CDE;
+ } else {
+ writel(0, priv->regs + RPC_DRCMR);
+ }
+
+ if (priv->cmdlen >= 4) /* Address(3) */
+ smenr |= RPC_DRENR_ADE(7);
+
+ if (priv->cmdlen >= 5) { /* Dummy(n) */
+ writel(8 * (priv->cmdlen - 4) - 1,
+ priv->regs + RPC_DRDMCR);
+ smenr |= RPC_DRENR_DME;
+ } else {
+ writel(0, priv->regs + RPC_DRDMCR);
+ }
+
+ writel(0, priv->regs + RPC_DROPR);
+
+ writel(smenr, priv->regs + RPC_DRENR);
+
+ if (rlen)
+ memcpy_fromio(din, (void *)(priv->extr + offset), rlen);
+ else
+ readl(priv->extr); /* Dummy read */
+ }
+
+err:
+ priv->cmdstarted = false;
+
+ rpc_spi_release_bus(dev);
+
+ return ret;
+}
+
+static int rpc_spi_set_speed(struct udevice *bus, uint speed)
+{
+ /* This is a SPI NOR controller, do nothing. */
+ return 0;
+}
+
+static int rpc_spi_set_mode(struct udevice *bus, uint mode)
+{
+ /* This is a SPI NOR controller, do nothing. */
+ return 0;
+}
+
+static int rpc_spi_bind(struct udevice *parent)
+{
+ const void *fdt = gd->fdt_blob;
+ ofnode node;
+ int ret, off;
+
+ /*
+ * Check if there are any SPI NOR child nodes, if so, bind as
+ * this controller will be operated in SPI mode.
+ */
+ dev_for_each_subnode(node, parent) {
+ off = ofnode_to_offset(node);
+
+ ret = fdt_node_check_compatible(fdt, off, "spi-flash");
+ if (!ret)
+ return 0;
+
+ ret = fdt_node_check_compatible(fdt, off, "jedec,spi-nor");
+ if (!ret)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int rpc_spi_probe(struct udevice *dev)
+{
+ struct rpc_spi_platdata *plat = dev_get_platdata(dev);
+ struct rpc_spi_priv *priv = dev_get_priv(dev);
+
+ priv->regs = plat->regs;
+ priv->extr = plat->extr;
+
+ clk_enable(&priv->clk);
+
+ return 0;
+}
+
+static int rpc_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct rpc_spi_platdata *plat = dev_get_platdata(bus);
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ plat->regs = dev_read_addr_index(bus, 0);
+ plat->extr = dev_read_addr_index(bus, 1);
+
+ ret = clk_get_by_index(bus, 0, &priv->clk);
+ if (ret < 0) {
+ printf("%s: Could not get clock for %s: %d\n",
+ __func__, bus->name, ret);
+ return ret;
+ }
+
+ plat->freq = dev_read_u32_default(bus, "spi-max-freq", 50000000);
+
+ return 0;
+}
+
+static const struct dm_spi_ops rpc_spi_ops = {
+ .xfer = rpc_spi_xfer,
+ .set_speed = rpc_spi_set_speed,
+ .set_mode = rpc_spi_set_mode,
+};
+
+static const struct udevice_id rpc_spi_ids[] = {
+ { .compatible = "renesas,rpc-r8a7795" },
+ { .compatible = "renesas,rpc-r8a7796" },
+ { .compatible = "renesas,rpc-r8a77965" },
+ { .compatible = "renesas,rpc-r8a77970" },
+ { .compatible = "renesas,rpc-r8a77995" },
+ { }
+};
+
+U_BOOT_DRIVER(rpc_spi) = {
+ .name = "rpc_spi",
+ .id = UCLASS_SPI,
+ .of_match = rpc_spi_ids,
+ .ops = &rpc_spi_ops,
+ .ofdata_to_platdata = rpc_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct rpc_spi_platdata),
+ .priv_auto_alloc_size = sizeof(struct rpc_spi_priv),
+ .bind = rpc_spi_bind,
+ .probe = rpc_spi_probe,
+};
diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c
index 75999c812d..5075be3cd1 100644
--- a/drivers/spi/sh_qspi.c
+++ b/drivers/spi/sh_qspi.c
@@ -11,6 +11,7 @@
#include <console.h>
#include <malloc.h>
#include <spi.h>
+#include <wait_bit.h>
#include <asm/arch/rmobile.h>
#include <asm/io.h>
@@ -35,33 +36,35 @@
SPCMD_BRDV0
#define SPBFCR_TXRST BIT(7)
#define SPBFCR_RXRST BIT(6)
+#define SPBFCR_TXTRG 0x30
+#define SPBFCR_RXTRG 0x07
/* SH QSPI register set */
struct sh_qspi_regs {
- unsigned char spcr;
- unsigned char sslp;
- unsigned char sppcr;
- unsigned char spsr;
- unsigned long spdr;
- unsigned char spscr;
- unsigned char spssr;
- unsigned char spbr;
- unsigned char spdcr;
- unsigned char spckd;
- unsigned char sslnd;
- unsigned char spnd;
- unsigned char dummy0;
- unsigned short spcmd0;
- unsigned short spcmd1;
- unsigned short spcmd2;
- unsigned short spcmd3;
- unsigned char spbfcr;
- unsigned char dummy1;
- unsigned short spbdcr;
- unsigned long spbmul0;
- unsigned long spbmul1;
- unsigned long spbmul2;
- unsigned long spbmul3;
+ u8 spcr;
+ u8 sslp;
+ u8 sppcr;
+ u8 spsr;
+ u32 spdr;
+ u8 spscr;
+ u8 spssr;
+ u8 spbr;
+ u8 spdcr;
+ u8 spckd;
+ u8 sslnd;
+ u8 spnd;
+ u8 dummy0;
+ u16 spcmd0;
+ u16 spcmd1;
+ u16 spcmd2;
+ u16 spcmd3;
+ u8 spbfcr;
+ u8 dummy1;
+ u16 spbdcr;
+ u32 spbmul0;
+ u32 spbmul1;
+ u32 spbmul2;
+ u32 spbmul3;
};
struct sh_qspi_slave {
@@ -200,11 +203,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
struct sh_qspi_slave *ss = to_sh_qspi(slave);
- unsigned long nbyte;
- int ret = 0;
- unsigned char dtdata = 0, drdata;
- unsigned char *tdata = &dtdata, *rdata = &drdata;
- unsigned long *spbmul0 = &ss->regs->spbmul0;
+ u32 nbyte, chunk;
+ int i, ret = 0;
+ u8 dtdata = 0, drdata;
+ u8 *tdata = &dtdata, *rdata = &drdata;
+ u32 *spbmul0 = &ss->regs->spbmul0;
if (dout == NULL && din == NULL) {
if (flags & SPI_XFER_END)
@@ -230,46 +233,44 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
writel(nbyte, spbmul0);
if (dout != NULL)
- tdata = (unsigned char *)dout;
+ tdata = (u8 *)dout;
if (din != NULL)
rdata = din;
while (nbyte > 0) {
- while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
- if (ctrlc()) {
- puts("abort\n");
- return 1;
- }
- udelay(10);
+ /*
+ * Check if there is 32 Byte chunk and if there is, transfer
+ * it in one burst, otherwise transfer on byte-by-byte basis.
+ */
+ chunk = (nbyte >= 32) ? 32 : 1;
+
+ clrsetbits_8(&ss->regs->spbfcr, SPBFCR_TXTRG | SPBFCR_RXTRG,
+ chunk == 32 ? SPBFCR_TXTRG | SPBFCR_RXTRG : 0);
+
+ ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF,
+ true, 1000, true);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < chunk; i++) {
+ writeb(*tdata, &ss->regs->spdr);
+ if (dout != NULL)
+ tdata++;
}
- writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
+ ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF,
+ true, 1000, true);
+ if (ret)
+ return ret;
- while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
- if (ctrlc()) {
- puts("abort\n");
- return 1;
- }
- udelay(1);
+ for (i = 0; i < chunk; i++) {
+ *rdata = readb(&ss->regs->spdr);
+ if (din != NULL)
+ rdata++;
}
- while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
- if (ctrlc()) {
- puts("abort\n");
- return 1;
- }
- udelay(10);
- }
-
- *rdata = readb((unsigned char *)(&ss->regs->spdr));
-
- if (dout != NULL)
- tdata++;
- if (din != NULL)
- rdata++;
-
- nbyte--;
+ nbyte -= chunk;
}
if (flags & SPI_XFER_END)
diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c
index ef2b64ec5f..558708a4a7 100644
--- a/drivers/spi/stm32_qspi.c
+++ b/drivers/spi/stm32_qspi.c
@@ -16,7 +16,6 @@
#include <dm.h>
#include <errno.h>
#include <asm/arch/stm32.h>
-#include <asm/arch/stm32_defs.h>
#include <clk.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c
index 3abce7f678..22c602a4d2 100644
--- a/drivers/sysreset/sysreset_syscon.c
+++ b/drivers/sysreset/sysreset_syscon.c
@@ -15,8 +15,6 @@
#include <sysreset.h>
#include <syscon.h>
-DECLARE_GLOBAL_DATA_PTR;
-
struct syscon_reboot_priv {
struct regmap *regmap;
unsigned int offset;
@@ -55,10 +53,8 @@ int syscon_reboot_probe(struct udevice *dev)
return -ENODEV;
}
- priv->offset = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
- "offset", 0);
- priv->mask = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
- "mask", 0);
+ priv->offset = dev_read_u32_default(dev, "offset", 0);
+ priv->mask = dev_read_u32_default(dev, "mask", 0);
return 0;
}
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 3a1f8311c1..2c96896726 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -119,4 +119,11 @@ config ROCKCHIP_TIMER
Select this to enable support for the timer found on
Rockchip devices.
+config STM32_TIMER
+ bool "STM32 timer support"
+ depends on TIMER
+ help
+ Select this to enable support for the timer found on
+ STM32 devices.
+
endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 15e515407e..a6e7832154 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o
obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o
+obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
diff --git a/drivers/timer/stm32_timer.c b/drivers/timer/stm32_timer.c
new file mode 100644
index 0000000000..344e6fba1e
--- /dev/null
+++ b/drivers/timer/stm32_timer.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <timer.h>
+
+#include <asm/io.h>
+
+/* Timer control1 register */
+#define CR1_CEN BIT(0)
+#define CR1_ARPE BIT(7)
+
+/* Event Generation Register register */
+#define EGR_UG BIT(0)
+
+/* Auto reload register for free running config */
+#define GPT_FREE_RUNNING 0xFFFFFFFF
+
+struct stm32_timer_regs {
+ u32 cr1;
+ u32 cr2;
+ u32 smcr;
+ u32 dier;
+ u32 sr;
+ u32 egr;
+ u32 ccmr1;
+ u32 ccmr2;
+ u32 ccer;
+ u32 cnt;
+ u32 psc;
+ u32 arr;
+ u32 reserved;
+ u32 ccr1;
+ u32 ccr2;
+ u32 ccr3;
+ u32 ccr4;
+ u32 reserved1;
+ u32 dcr;
+ u32 dmar;
+ u32 tim2_5_or;
+};
+
+struct stm32_timer_priv {
+ struct stm32_timer_regs *base;
+};
+
+static int stm32_timer_get_count(struct udevice *dev, u64 *count)
+{
+ struct stm32_timer_priv *priv = dev_get_priv(dev);
+ struct stm32_timer_regs *regs = priv->base;
+
+ *count = readl(&regs->cnt);
+
+ return 0;
+}
+
+static int stm32_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct stm32_timer_priv *priv = dev_get_priv(dev);
+ struct stm32_timer_regs *regs;
+ struct clk clk;
+ fdt_addr_t addr;
+ int ret;
+ u32 rate, psc;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = (struct stm32_timer_regs *)addr;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ regs = priv->base;
+
+ /* Stop the timer */
+ clrbits_le32(&regs->cr1, CR1_CEN);
+
+ /* get timer clock */
+ rate = clk_get_rate(&clk);
+
+ /* we set timer prescaler to obtain a 1MHz timer counter frequency */
+ psc = (rate / CONFIG_SYS_HZ_CLOCK) - 1;
+ writel(psc, &regs->psc);
+
+ /* Set timer frequency to 1MHz */
+ uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+
+ /* Configure timer for auto-reload */
+ setbits_le32(&regs->cr1, CR1_ARPE);
+
+ /* load value for auto reload */
+ writel(GPT_FREE_RUNNING, &regs->arr);
+
+ /* start timer */
+ setbits_le32(&regs->cr1, CR1_CEN);
+
+ /* Update generation */
+ setbits_le32(&regs->egr, EGR_UG);
+
+ return 0;
+}
+
+static const struct timer_ops stm32_timer_ops = {
+ .get_count = stm32_timer_get_count,
+};
+
+static const struct udevice_id stm32_timer_ids[] = {
+ { .compatible = "st,stm32-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(stm32_timer) = {
+ .name = "stm32_timer",
+ .id = UCLASS_TIMER,
+ .of_match = stm32_timer_ids,
+ .priv_auto_alloc_size = sizeof(struct stm32_timer_priv),
+ .probe = stm32_timer_probe,
+ .ops = &stm32_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
diff --git a/drivers/usb/eth/Kconfig b/drivers/usb/eth/Kconfig
index 496a6d1933..2f6bfa8e71 100644
--- a/drivers/usb/eth/Kconfig
+++ b/drivers/usb/eth/Kconfig
@@ -23,6 +23,7 @@ config USB_ETHER_ASIX88179
config USB_ETHER_LAN75XX
bool "Microchip LAN75XX support"
depends on USB_HOST_ETHER
+ depends on PHYLIB
---help---
Say Y here if you would like to support Microchip LAN75XX Hi-Speed
USB 2.0 to 10/100/1000 Gigabit Ethernet controller.
@@ -32,6 +33,7 @@ config USB_ETHER_LAN75XX
config USB_ETHER_LAN78XX
bool "Microchip LAN78XX support"
depends on USB_HOST_ETHER
+ depends on PHYLIB
---help---
Say Y here if you would like to support Microchip LAN78XX USB 3.1
Gen 1 to 10/100/1000 Gigabit Ethernet controller.
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 6825e6b543..26b4d12a09 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -158,6 +158,7 @@ endif # USB_GADGET_DOWNLOAD
config USB_ETHER
bool "USB Ethernet Gadget"
+ depends on NET
default y if ARCH_SUNXI && USB_MUSB_GADGET
help
Creates an Ethernet network device through a USB peripheral
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index a80486e91f..386505d42d 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <console.h>
+#include <environment.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/usb/ch9.h>
diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c
index d5a10f1904..ad3ae91e6d 100644
--- a/drivers/usb/gadget/f_rockusb.c
+++ b/drivers/usb/gadget/f_rockusb.c
@@ -552,7 +552,6 @@ static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
sizeof(struct fsg_bulk_cb_wrap));
struct f_rockusb *f_rkusb = get_rkusb();
- f_rkusb->reboot_flag = 0;
memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
f_rkusb->reboot_flag = cbw->CDB[1];
rockusb_func->in_req->complete = compl_do_reset;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 90b2f78ec7..6caa61552a 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -21,6 +21,13 @@ config USB_XHCI_DWC3
Say Y or if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
+config USB_XHCI_DWC3_OF_SIMPLE
+ bool "DesignWare USB3 DRD Generic OF Simple Glue Layer"
+ select MISC
+ help
+ Support USB2/3 functionality in simple SoC integrations with
+ USB controller based on the DesignWare USB3 IP Core.
+
config USB_XHCI_MVEBU
bool "MVEBU USB 3.0 support"
default y
@@ -245,3 +252,15 @@ config USB_DWC2
Hi-Speed (480 Mbps), Full-Speed (12 Mbps), and Low-Speed (1.5 Mbps)
operation is compliant to the controller Supplement. If you want to
enable this controller in host mode, say Y.
+
+if USB_DWC2
+config USB_DWC2_BUFFER_SIZE
+ int "Data buffer size in kB"
+ default 64
+ ---help---
+ By default 64 kB buffer is used but if amount of RAM avaialble on
+ the target is not enough to accommodate allocation of buffer of
+ that size it is possible to shrink it. Smaller sizes should be fine
+ because larger transactions could be split in smaller ones.
+
+endif # USB_DWC2
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7f9ba24cfe..abe4f9087f 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -35,7 +35,6 @@ obj-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o
obj-$(CONFIG_USB_EHCI_MX6) += ehci-mx6.o
obj-$(CONFIG_USB_EHCI_MX7) += ehci-mx6.o
obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
-obj-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
@@ -50,6 +49,7 @@ obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
# xhci
obj-$(CONFIG_USB_XHCI_HCD) += xhci.o xhci-mem.o xhci-ring.o
obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o
+obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
obj-$(CONFIG_USB_XHCI_ROCKCHIP) += xhci-rockchip.o
obj-$(CONFIG_USB_XHCI_ZYNQMP) += xhci-zynqmp.o
obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index 0efe645044..4862ab0e7d 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -25,7 +25,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define DWC2_HC_CHANNEL 0
#define DWC2_STATUS_BUF_SIZE 64
-#define DWC2_DATA_BUF_SIZE (64 * 1024)
+#define DWC2_DATA_BUF_SIZE (CONFIG_USB_DWC2_BUFFER_SIZE * 1024)
#define MAX_DEVICE 16
#define MAX_ENDPOINT 16
@@ -34,6 +34,9 @@ struct dwc2_priv {
#ifdef CONFIG_DM_USB
uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
+#ifdef CONFIG_DM_REGULATOR
+ struct udevice *vbus_supply;
+#endif
#else
uint8_t *aligned_buffer;
uint8_t *status_buffer;
@@ -111,7 +114,7 @@ static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_TXFFLSH,
false, 1000, false);
if (ret)
- printf("%s: Timeout!\n", __func__);
+ dev_info(dev, "%s: Timeout!\n", __func__);
/* Wait for 3 PHY Clocks */
udelay(1);
@@ -130,7 +133,7 @@ static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_RXFFLSH,
false, 1000, false);
if (ret)
- printf("%s: Timeout!\n", __func__);
+ dev_info(dev, "%s: Timeout!\n", __func__);
/* Wait for 3 PHY Clocks */
udelay(1);
@@ -148,14 +151,14 @@ static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
true, 1000, false);
if (ret)
- printf("%s: Timeout!\n", __func__);
+ dev_info(dev, "%s: Timeout!\n", __func__);
/* Core Soft Reset */
writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
false, 1000, false);
if (ret)
- printf("%s: Timeout!\n", __func__);
+ dev_info(dev, "%s: Timeout!\n", __func__);
/*
* Wait for core to come out of reset.
@@ -168,28 +171,52 @@ static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
#if defined(CONFIG_DM_USB) && defined(CONFIG_DM_REGULATOR)
static int dwc_vbus_supply_init(struct udevice *dev)
{
- struct udevice *vbus_supply;
+ struct dwc2_priv *priv = dev_get_priv(dev);
int ret;
- ret = device_get_supply_regulator(dev, "vbus-supply", &vbus_supply);
+ ret = device_get_supply_regulator(dev, "vbus-supply",
+ &priv->vbus_supply);
if (ret) {
debug("%s: No vbus supply\n", dev->name);
return 0;
}
- ret = regulator_set_enable(vbus_supply, true);
+ ret = regulator_set_enable(priv->vbus_supply, true);
if (ret) {
- pr_err("Error enabling vbus supply\n");
+ dev_err(dev, "Error enabling vbus supply\n");
return ret;
}
return 0;
}
+
+static int dwc_vbus_supply_exit(struct udevice *dev)
+{
+ struct dwc2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (priv->vbus_supply) {
+ ret = regulator_set_enable(priv->vbus_supply, false);
+ if (ret) {
+ dev_err(dev, "Error disabling vbus supply\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
#else
static int dwc_vbus_supply_init(struct udevice *dev)
{
return 0;
}
+
+#if defined(CONFIG_DM_USB)
+static int dwc_vbus_supply_exit(struct udevice *dev)
+{
+ return 0;
+}
+#endif
#endif
/*
@@ -270,7 +297,7 @@ static void dwc_otg_core_host_init(struct udevice *dev,
ret = wait_for_bit_le32(&regs->hc_regs[i].hcchar,
DWC2_HCCHAR_CHEN, false, 1000, false);
if (ret)
- printf("%s: Timeout!\n", __func__);
+ dev_info("%s: Timeout!\n", __func__);
}
/* Turn on the vbus power. */
@@ -784,7 +811,7 @@ int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle)
uint32_t hcint, hctsiz;
ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true,
- 1000, false);
+ 2000, false);
if (ret)
return ret;
@@ -1091,7 +1118,7 @@ int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
for (;;) {
if (get_timer(0) > timeout) {
- printf("Timeout poll on interrupt endpoint\n");
+ dev_err(dev, "Timeout poll on interrupt endpoint\n");
return -ETIMEDOUT;
}
ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
@@ -1107,11 +1134,13 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
int i, j;
snpsid = readl(&regs->gsnpsid);
- printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
+ dev_info(dev, "Core Release: %x.%03x\n",
+ snpsid >> 12 & 0xf, snpsid & 0xfff);
if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
(snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
- printf("SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid);
+ dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
+ snpsid);
return -ENODEV;
}
@@ -1269,6 +1298,11 @@ static int dwc2_usb_probe(struct udevice *dev)
static int dwc2_usb_remove(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dwc_vbus_supply_exit(dev);
+ if (ret)
+ return ret;
dwc2_uninit_common(priv->regs);
diff --git a/drivers/usb/host/dwc3-of-simple.c b/drivers/usb/host/dwc3-of-simple.c
new file mode 100644
index 0000000000..54a5f60b52
--- /dev/null
+++ b/drivers/usb/host/dwc3-of-simple.c
@@ -0,0 +1,109 @@
+/*
+ * dwc3-of-simple.c - OF glue layer for simple integrations
+ *
+ * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <reset.h>
+#include <clk.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct dwc3_of_simple {
+ struct clk_bulk clks;
+ struct reset_ctl_bulk resets;
+};
+
+static int dwc3_of_simple_reset_init(struct udevice *dev,
+ struct dwc3_of_simple *simple)
+{
+ int ret;
+
+ ret = reset_get_bulk(dev, &simple->resets);
+ if (ret == -ENOTSUPP)
+ return 0;
+ else if (ret)
+ return ret;
+
+ ret = reset_deassert_bulk(&simple->resets);
+ if (ret) {
+ reset_release_bulk(&simple->resets);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dwc3_of_simple_clk_init(struct udevice *dev,
+ struct dwc3_of_simple *simple)
+{
+ int ret;
+
+ ret = clk_get_bulk(dev, &simple->clks);
+ if (ret == -ENOTSUPP)
+ return 0;
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_enable_bulk(&simple->clks);
+ if (ret) {
+ clk_release_bulk(&simple->clks);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int dwc3_of_simple_probe(struct udevice *dev)
+{
+ struct dwc3_of_simple *simple = dev_get_platdata(dev);
+ int ret;
+
+ ret = dwc3_of_simple_clk_init(dev, simple);
+ if (ret)
+ return ret;
+
+ ret = dwc3_of_simple_reset_init(dev, simple);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dwc3_of_simple_remove(struct udevice *dev)
+{
+ struct dwc3_of_simple *simple = dev_get_platdata(dev);
+
+ reset_release_bulk(&simple->resets);
+
+ clk_release_bulk(&simple->clks);
+
+ return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id dwc3_of_simple_ids[] = {
+ { .compatible = "amlogic,meson-gxl-dwc3" },
+ { }
+};
+
+U_BOOT_DRIVER(dwc3_of_simple) = {
+ .name = "dwc3-of-simple",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = dwc3_of_simple_ids,
+ .probe = dwc3_of_simple_probe,
+ .remove = dwc3_of_simple_remove,
+ .platdata_auto_alloc_size = sizeof(struct dwc3_of_simple),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c
index 1cb92c0338..b012d8651f 100644
--- a/drivers/usb/host/ehci-generic.c
+++ b/drivers/usb/host/ehci-generic.c
@@ -27,6 +27,56 @@ struct generic_ehci {
int reset_count;
};
+static int ehci_setup_phy(struct udevice *dev, int index)
+{
+ struct generic_ehci *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = generic_phy_get_by_index(dev, index, &priv->phy);
+ if (ret) {
+ if (ret != -ENOENT) {
+ dev_err(dev, "failed to get usb phy\n");
+ return ret;
+ }
+ } else {
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to init usb phy\n");
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power on usb phy\n");
+ return generic_phy_exit(&priv->phy);
+ }
+ }
+
+ return 0;
+}
+
+static int ehci_shutdown_phy(struct udevice *dev)
+{
+ struct generic_ehci *priv = dev_get_priv(dev);
+ int ret = 0;
+
+ if (generic_phy_valid(&priv->phy)) {
+ ret = generic_phy_power_off(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power off usb phy\n");
+ return ret;
+ }
+
+ ret = generic_phy_exit(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power off usb phy\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int ehci_usb_probe(struct udevice *dev)
{
struct generic_ehci *priv = dev_get_priv(dev);
@@ -51,7 +101,7 @@ static int ehci_usb_probe(struct udevice *dev)
break;
err = clk_enable(&priv->clocks[i]);
if (err) {
- pr_err("failed to enable clock %d\n", i);
+ dev_err(dev, "failed to enable clock %d\n", i);
clk_free(&priv->clocks[i]);
goto clk_err;
}
@@ -59,7 +109,8 @@ static int ehci_usb_probe(struct udevice *dev)
}
} else {
if (clock_nb != -ENOENT) {
- pr_err("failed to get clock phandle(%d)\n", clock_nb);
+ dev_err(dev, "failed to get clock phandle(%d)\n",
+ clock_nb);
return clock_nb;
}
}
@@ -80,7 +131,8 @@ static int ehci_usb_probe(struct udevice *dev)
break;
if (reset_deassert(&priv->resets[i])) {
- pr_err("failed to deassert reset %d\n", i);
+ dev_err(dev, "failed to deassert reset %d\n",
+ i);
reset_free(&priv->resets[i]);
goto reset_err;
}
@@ -88,25 +140,15 @@ static int ehci_usb_probe(struct udevice *dev)
}
} else {
if (reset_nb != -ENOENT) {
- pr_err("failed to get reset phandle(%d)\n", reset_nb);
+ dev_err(dev, "failed to get reset phandle(%d)\n",
+ reset_nb);
goto clk_err;
}
}
- err = generic_phy_get_by_index(dev, 0, &priv->phy);
- if (err) {
- if (err != -ENOENT) {
- pr_err("failed to get usb phy\n");
- goto reset_err;
- }
- } else {
-
- err = generic_phy_init(&priv->phy);
- if (err) {
- pr_err("failed to init usb phy\n");
- goto reset_err;
- }
- }
+ err = ehci_setup_phy(dev, 0);
+ if (err)
+ goto reset_err;
hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
@@ -119,20 +161,18 @@ static int ehci_usb_probe(struct udevice *dev)
return 0;
phy_err:
- if (generic_phy_valid(&priv->phy)) {
- ret = generic_phy_exit(&priv->phy);
- if (ret)
- pr_err("failed to release phy\n");
- }
+ ret = ehci_shutdown_phy(dev);
+ if (ret)
+ dev_err(dev, "failed to shutdown usb phy\n");
reset_err:
ret = reset_release_all(priv->resets, priv->reset_count);
if (ret)
- pr_err("failed to assert all resets\n");
+ dev_err(dev, "failed to assert all resets\n");
clk_err:
ret = clk_release_all(priv->clocks, priv->clock_count);
if (ret)
- pr_err("failed to disable all clocks\n");
+ dev_err(dev, "failed to disable all clocks\n");
return err;
}
@@ -146,11 +186,9 @@ static int ehci_usb_remove(struct udevice *dev)
if (ret)
return ret;
- if (generic_phy_valid(&priv->phy)) {
- ret = generic_phy_exit(&priv->phy);
- if (ret)
- return ret;
- }
+ ret = ehci_shutdown_phy(dev);
+ if (ret)
+ return ret;
ret = reset_release_all(priv->resets, priv->reset_count);
if (ret)
diff --git a/drivers/usb/host/ehci-ppc4xx.c b/drivers/usb/host/ehci-ppc4xx.c
deleted file mode 100644
index 9d23577642..0000000000
--- a/drivers/usb/host/ehci-ppc4xx.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * (C) Copyright 2010, Chris Zhang <chris@seamicro.com>
- *
- * Author: Chris Zhang <chris@seamicro.com>
- * This code is based on ehci freescale driver
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-#include <common.h>
-#include <usb.h>
-#include <asm/io.h>
-
-#include "ehci.h"
-
-/*
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- */
-int ehci_hcd_init(int index, enum usb_init_type init,
- struct ehci_hccr **hccr, struct ehci_hcor **hcor)
-{
- *hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR);
- *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
- HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
- return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the the EHCI host controller.
- */
-int ehci_hcd_stop(int index)
-{
- return 0;
-}
diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c
index bf55a71d66..5bdd7995b9 100644
--- a/drivers/usb/host/ohci-generic.c
+++ b/drivers/usb/host/ohci-generic.c
@@ -25,6 +25,56 @@ struct generic_ohci {
int reset_count; /* number of reset in reset list */
};
+static int ohci_setup_phy(struct udevice *dev, int index)
+{
+ struct generic_ohci *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = generic_phy_get_by_index(dev, index, &priv->phy);
+ if (ret) {
+ if (ret != -ENOENT) {
+ dev_err(dev, "failed to get usb phy\n");
+ return ret;
+ }
+ } else {
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to init usb phy\n");
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power on usb phy\n");
+ return generic_phy_exit(&priv->phy);
+ }
+ }
+
+ return 0;
+}
+
+static int ohci_shutdown_phy(struct udevice *dev)
+{
+ struct generic_ohci *priv = dev_get_priv(dev);
+ int ret = 0;
+
+ if (generic_phy_valid(&priv->phy)) {
+ ret = generic_phy_power_off(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power off usb phy\n");
+ return ret;
+ }
+
+ ret = generic_phy_exit(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power off usb phy\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int ohci_usb_probe(struct udevice *dev)
{
struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
@@ -47,14 +97,14 @@ static int ohci_usb_probe(struct udevice *dev)
err = clk_enable(&priv->clocks[i]);
if (err) {
- pr_err("failed to enable clock %d\n", i);
+ dev_err(dev, "failed to enable clock %d\n", i);
clk_free(&priv->clocks[i]);
goto clk_err;
}
priv->clock_count++;
}
} else if (clock_nb != -ENOENT) {
- pr_err("failed to get clock phandle(%d)\n", clock_nb);
+ dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb);
return clock_nb;
}
@@ -74,31 +124,20 @@ static int ohci_usb_probe(struct udevice *dev)
err = reset_deassert(&priv->resets[i]);
if (err) {
- pr_err("failed to deassert reset %d\n", i);
+ dev_err(dev, "failed to deassert reset %d\n", i);
reset_free(&priv->resets[i]);
goto reset_err;
}
priv->reset_count++;
}
} else if (reset_nb != -ENOENT) {
- pr_err("failed to get reset phandle(%d)\n", reset_nb);
+ dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb);
goto clk_err;
}
- err = generic_phy_get_by_index(dev, 0, &priv->phy);
- if (err) {
- if (err != -ENOENT) {
- pr_err("failed to get usb phy\n");
- goto reset_err;
- }
- } else {
-
- err = generic_phy_init(&priv->phy);
- if (err) {
- pr_err("failed to init usb phy\n");
- goto reset_err;
- }
- }
+ err = ohci_setup_phy(dev, 0);
+ if (err)
+ goto reset_err;
err = ohci_register(dev, regs);
if (err)
@@ -107,20 +146,18 @@ static int ohci_usb_probe(struct udevice *dev)
return 0;
phy_err:
- if (generic_phy_valid(&priv->phy)) {
- ret = generic_phy_exit(&priv->phy);
- if (ret)
- pr_err("failed to release phy\n");
- }
+ ret = ohci_shutdown_phy(dev);
+ if (ret)
+ dev_err(dev, "failed to shutdown usb phy\n");
reset_err:
ret = reset_release_all(priv->resets, priv->reset_count);
if (ret)
- pr_err("failed to assert all resets\n");
+ dev_err(dev, "failed to assert all resets\n");
clk_err:
ret = clk_release_all(priv->clocks, priv->clock_count);
if (ret)
- pr_err("failed to disable all clocks\n");
+ dev_err(dev, "failed to disable all clocks\n");
return err;
}
@@ -134,11 +171,9 @@ static int ohci_usb_remove(struct udevice *dev)
if (ret)
return ret;
- if (generic_phy_valid(&priv->phy)) {
- ret = generic_phy_exit(&priv->phy);
- if (ret)
- return ret;
- }
+ ret = ohci_shutdown_phy(dev);
+ if (ret)
+ return ret;
ret = reset_release_all(priv->resets, priv->reset_count);
if (ret)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c
index 258d1cd00a..c1007350b7 100644
--- a/drivers/usb/host/xhci-dwc3.c
+++ b/drivers/usb/host/xhci-dwc3.c
@@ -22,7 +22,8 @@
DECLARE_GLOBAL_DATA_PTR;
struct xhci_dwc3_platdata {
- struct phy usb_phy;
+ struct phy *usb_phys;
+ int num_phys;
};
void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
@@ -112,9 +113,89 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val)
}
#ifdef CONFIG_DM_USB
-static int xhci_dwc3_probe(struct udevice *dev)
+static int xhci_dwc3_setup_phy(struct udevice *dev, int count)
+{
+ struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
+ int i, ret;
+
+ if (!count)
+ return 0;
+
+ plat->usb_phys = devm_kcalloc(dev, count, sizeof(struct phy),
+ GFP_KERNEL);
+ if (!plat->usb_phys)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ ret = generic_phy_get_by_index(dev, i, &plat->usb_phys[i]);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get USB PHY%d for %s\n",
+ i, dev->name);
+ return ret;
+ }
+
+ ++plat->num_phys;
+ }
+
+ for (i = 0; i < plat->num_phys; i++) {
+ ret = generic_phy_init(&plat->usb_phys[i]);
+ if (ret) {
+ pr_err("Can't init USB PHY%d for %s\n",
+ i, dev->name);
+ goto phys_init_err;
+ }
+ }
+
+ for (i = 0; i < plat->num_phys; i++) {
+ ret = generic_phy_power_on(&plat->usb_phys[i]);
+ if (ret) {
+ pr_err("Can't power USB PHY%d for %s\n",
+ i, dev->name);
+ goto phys_poweron_err;
+ }
+ }
+
+ return 0;
+
+
+phys_poweron_err:
+ for (; i >= 0; i--)
+ generic_phy_power_off(&plat->usb_phys[i]);
+
+ for (i = 0; i < plat->num_phys; i++)
+ generic_phy_exit(&plat->usb_phys[i]);
+
+ return ret;
+
+phys_init_err:
+ for (; i >= 0; i--)
+ generic_phy_exit(&plat->usb_phys[i]);
+
+ return ret;
+}
+
+static int xhci_dwc3_shutdown_phy(struct udevice *dev)
{
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
+ int i, ret;
+
+ for (i = 0; i < plat->num_phys; i++) {
+ if (!generic_phy_valid(&plat->usb_phys[i]))
+ continue;
+
+ ret = generic_phy_power_off(&plat->usb_phys[i]);
+ ret |= generic_phy_exit(&plat->usb_phys[i]);
+ if (ret) {
+ pr_err("Can't shutdown USB PHY%d for %s\n",
+ i, dev->name);
+ }
+ }
+
+ return 0;
+}
+
+static int xhci_dwc3_probe(struct udevice *dev)
+{
struct xhci_hcor *hcor;
struct xhci_hccr *hccr;
struct dwc3 *dwc3_reg;
@@ -125,19 +206,10 @@ static int xhci_dwc3_probe(struct udevice *dev)
hcor = (struct xhci_hcor *)((uintptr_t)hccr +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
- ret = generic_phy_get_by_index(dev, 0, &plat->usb_phy);
- if (ret) {
- if (ret != -ENOENT) {
- pr_err("Failed to get USB PHY for %s\n", dev->name);
- return ret;
- }
- } else {
- ret = generic_phy_init(&plat->usb_phy);
- if (ret) {
- pr_err("Can't init USB PHY for %s\n", dev->name);
- return ret;
- }
- }
+ ret = xhci_dwc3_setup_phy(dev, dev_count_phandle_with_args(
+ dev, "phys", "#phy-cells"));
+ if (ret)
+ return ret;
dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
@@ -155,16 +227,7 @@ static int xhci_dwc3_probe(struct udevice *dev)
static int xhci_dwc3_remove(struct udevice *dev)
{
- struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- if (generic_phy_valid(&plat->usb_phy)) {
- ret = generic_phy_exit(&plat->usb_phy);
- if (ret) {
- pr_err("Can't deinit USB PHY for %s\n", dev->name);
- return ret;
- }
- }
+ xhci_dwc3_shutdown_phy(dev);
return xhci_deregister(dev);
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 2fc0defcd0..45a105db06 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -38,7 +38,6 @@ config BACKLIGHT_GPIO
config VIDEO_BPP8
bool "Support 8-bit-per-pixel displays"
depends on DM_VIDEO
- default n if ARCH_SUNXI
default y if DM_VIDEO
help
Support drawing text and bitmaps onto a 8-bit-per-pixel display.
@@ -49,7 +48,6 @@ config VIDEO_BPP8
config VIDEO_BPP16
bool "Support 16-bit-per-pixel displays"
depends on DM_VIDEO
- default n if ARCH_SUNXI
default y if DM_VIDEO
help
Support drawing text and bitmaps onto a 16-bit-per-pixel display.
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 0b25897062..5b7795dd44 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -768,7 +768,7 @@ static void parse_putc(const char c)
break;
case '\n': /* next line */
- if (console_col || (!console_col && nl))
+ if (console_col || nl)
console_newline(1);
nl = 1;
break;
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 6ec4f89e34..26db73b138 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -853,9 +853,10 @@ static u32 wait_for_event(u32 event)
do {
ret = lcdc_irq_handler();
udelay(1000);
- } while (!(ret & event));
+ --timeout;
+ } while (!(ret & event) && timeout);
- if (timeout <= 0) {
+ if (!(ret & event)) {
printf("%s: event %d not hit\n", __func__, event);
return -1;
}
diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c
index 30e4020686..3a6ef62890 100644
--- a/drivers/video/exynos/exynos_dp.c
+++ b/drivers/video/exynos/exynos_dp.c
@@ -321,7 +321,7 @@ static unsigned int exynos_dp_link_start(struct exynos_dp *regs,
static unsigned int exynos_dp_training_pattern_dis(struct exynos_dp *regs)
{
- unsigned int ret = EXYNOS_DP_SUCCESS;
+ unsigned int ret;
exynos_dp_set_training_pattern(regs, DP_NONE);
@@ -339,7 +339,7 @@ static unsigned int exynos_dp_enable_rx_to_enhanced_mode(
struct exynos_dp *regs, unsigned char enable)
{
unsigned char data;
- unsigned int ret = EXYNOS_DP_SUCCESS;
+ unsigned int ret;
ret = exynos_dp_read_byte_from_dpcd(regs, DPCD_LANE_COUNT_SET,
&data);
@@ -366,7 +366,7 @@ static unsigned int exynos_dp_enable_rx_to_enhanced_mode(
static unsigned int exynos_dp_set_enhanced_mode(struct exynos_dp *regs,
unsigned char enhance_mode)
{
- unsigned int ret = EXYNOS_DP_SUCCESS;
+ unsigned int ret;
ret = exynos_dp_enable_rx_to_enhanced_mode(regs, enhance_mode);
if (ret != EXYNOS_DP_SUCCESS) {
@@ -416,7 +416,7 @@ static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *regs,
static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *regs,
unsigned char lane_num, unsigned char *sw, unsigned char *em)
{
- unsigned int ret = EXYNOS_DP_SUCCESS;
+ unsigned int ret;
unsigned char buf;
unsigned int dpcd_addr;
unsigned char shift_val[DP_LANE_CNT_4] = {0, 4, 0, 4};
@@ -484,7 +484,7 @@ static int exynos_dp_reduce_link_rate(struct exynos_dp *regs,
static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *regs,
struct exynos_dp_priv *priv)
{
- unsigned int ret = EXYNOS_DP_SUCCESS;
+ unsigned int ret;
unsigned char lane_stat;
unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0, };
unsigned int i;
@@ -594,7 +594,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *regs,
static unsigned int exynos_dp_process_equalizer_training(
struct exynos_dp *regs, struct exynos_dp_priv *priv)
{
- unsigned int ret = EXYNOS_DP_SUCCESS;
+ unsigned int ret;
unsigned char lane_stat, adj_req_sw, adj_req_em, i;
unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0,};
unsigned char interlane_aligned = 0;
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index fbd7bf7838..f40e57bb8e 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -32,16 +32,18 @@ static int pwm_backlight_enable(struct udevice *dev)
uint duty_cycle;
int ret;
- plat = dev_get_uclass_platdata(priv->reg);
- debug("%s: Enable '%s', regulator '%s'/'%s'\n", __func__, dev->name,
- priv->reg->name, plat->name);
- ret = regulator_set_enable(priv->reg, true);
- if (ret) {
- debug("%s: Cannot enable regulator for PWM '%s'\n", __func__,
- dev->name);
- return ret;
+ if (priv->reg) {
+ plat = dev_get_uclass_platdata(priv->reg);
+ debug("%s: Enable '%s', regulator '%s'/'%s'\n", __func__,
+ dev->name, priv->reg->name, plat->name);
+ ret = regulator_set_enable(priv->reg, true);
+ if (ret) {
+ debug("%s: Cannot enable regulator for PWM '%s'\n",
+ __func__, dev->name);
+ return ret;
+ }
+ mdelay(120);
}
- mdelay(120);
duty_cycle = priv->period_ns * (priv->default_level - priv->min_level) /
(priv->max_level - priv->min_level + 1);
@@ -68,10 +70,8 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev)
debug("%s: start\n", __func__);
ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
"power-supply", &priv->reg);
- if (ret) {
+ if (ret)
debug("%s: Cannot get power supply: ret=%d\n", __func__, ret);
- return ret;
- }
ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
GPIOD_IS_OUT);
if (ret) {
diff --git a/drivers/video/rockchip/rk3288_mipi.c b/drivers/video/rockchip/rk3288_mipi.c
index 953b47fb8c..a7fa9c5110 100644
--- a/drivers/video/rockchip/rk3288_mipi.c
+++ b/drivers/video/rockchip/rk3288_mipi.c
@@ -136,7 +136,7 @@ static int rk_mipi_ofdata_to_platdata(struct udevice *dev)
struct rk_mipi_priv *priv = dev_get_priv(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
- if (IS_ERR(priv->grf)) {
+ if (IS_ERR_OR_NULL(priv->grf)) {
debug("%s: Get syscon grf failed (ret=%p)\n",
__func__, priv->grf);
return -ENXIO;
diff --git a/drivers/video/rockchip/rk3399_mipi.c b/drivers/video/rockchip/rk3399_mipi.c
index 9ef202bf09..b936fcec9b 100644
--- a/drivers/video/rockchip/rk3399_mipi.c
+++ b/drivers/video/rockchip/rk3399_mipi.c
@@ -128,7 +128,7 @@ static int rk_mipi_ofdata_to_platdata(struct udevice *dev)
struct rk_mipi_priv *priv = dev_get_priv(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
- if (priv->grf <= 0) {
+ if (IS_ERR_OR_NULL(priv->grf)) {
debug("%s: Get syscon grf failed (ret=%p)\n",
__func__, priv->grf);
return -ENXIO;
diff --git a/drivers/video/stb_truetype.h b/drivers/video/stb_truetype.h
index 26e483cf56..5d00bff9fd 100644
--- a/drivers/video/stb_truetype.h
+++ b/drivers/video/stb_truetype.h
@@ -1993,7 +1993,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
STBTT_assert(fabs(area) <= 1.01f);
- scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
+ scanline[x2] += area + sign * (1-(x_bottom-x2)/2) * (sy1-y_crossing);
scanline_fill[x2] += sign * (sy1-sy0);
}
diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c
index b417ac260a..e160c77e07 100644
--- a/drivers/video/stm32/stm32_ltdc.c
+++ b/drivers/video/stm32/stm32_ltdc.c
@@ -1,8 +1,7 @@
/*
- * Copyright (C) STMicroelectronics SA 2017
- *
- * Authors: Philippe Cornu <philippe.cornu@st.com>
- * Yannick Fertre <yannick.fertre@st.com>
+ * Copyright (C) 2017-2018 STMicroelectronics - All Rights Reserved
+ * Author(s): Philippe Cornu <philippe.cornu@st.com> for STMicroelectronics.
+ * Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -11,6 +10,7 @@
#include <clk.h>
#include <dm.h>
#include <panel.h>
+#include <reset.h>
#include <video.h>
#include <asm/io.h>
#include <asm/arch/gpio.h>
@@ -138,7 +138,9 @@ struct stm32_ltdc_priv {
#define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */
#define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */
+#define BF1_CA 0x400 /* Constant Alpha */
#define BF2_1PAXCA 0x007 /* 1 - (Pixel Alpha x Constant Alpha) */
+#define BF2_1CA 0x005 /* 1 - Constant Alpha */
enum stm32_ltdc_pix_fmt {
PF_ARGB8888 = 0,
@@ -161,11 +163,17 @@ static u32 stm32_ltdc_get_pixel_format(enum video_log2_bpp l2bpp)
pf = PF_RGB565;
break;
+ case VIDEO_BPP32:
+ pf = PF_ARGB8888;
+ break;
+
+ case VIDEO_BPP8:
+ pf = PF_L8;
+ break;
+
case VIDEO_BPP1:
case VIDEO_BPP2:
case VIDEO_BPP4:
- case VIDEO_BPP8:
- case VIDEO_BPP32:
default:
debug("%s: warning %dbpp not supported yet, %dbpp instead\n",
__func__, VNBITS(l2bpp), VNBITS(VIDEO_BPP16));
@@ -178,6 +186,23 @@ static u32 stm32_ltdc_get_pixel_format(enum video_log2_bpp l2bpp)
return (u32)pf;
}
+static bool has_alpha(u32 fmt)
+{
+ switch (fmt) {
+ case PF_ARGB8888:
+ case PF_ARGB1555:
+ case PF_ARGB4444:
+ case PF_AL44:
+ case PF_AL88:
+ return true;
+ case PF_RGB888:
+ case PF_RGB565:
+ case PF_L8:
+ default:
+ return false;
+ }
+}
+
static void stm32_ltdc_enable(struct stm32_ltdc_priv *priv)
{
/* Reload configuration immediately & enable LTDC */
@@ -219,6 +244,8 @@ static void stm32_ltdc_set_mode(struct stm32_ltdc_priv *priv)
val = (total_w << 16) | total_h;
clrsetbits_le32(regs + LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val);
+ setbits_le32(regs + LTDC_LIPCR, acc_act_h + 1);
+
/* Signal polarities */
val = 0;
debug("%s: timing->flags 0x%08x\n", __func__, timing->flags);
@@ -245,6 +272,7 @@ static void stm32_ltdc_set_layer1(struct stm32_ltdc_priv *priv, ulong fb_addr)
u32 line_length;
u32 bus_width;
u32 val, tmp, bpp;
+ u32 format;
x0 = priv->crop_x;
x1 = priv->crop_x + priv->crop_w - 1;
@@ -275,15 +303,18 @@ static void stm32_ltdc_set_layer1(struct stm32_ltdc_priv *priv, ulong fb_addr)
clrsetbits_le32(regs + LTDC_L1CFBLR, LXCFBLR_CFBLL | LXCFBLR_CFBP, val);
/* Pixel format */
- val = stm32_ltdc_get_pixel_format(priv->l2bpp);
- clrsetbits_le32(regs + LTDC_L1PFCR, LXPFCR_PF, val);
+ format = stm32_ltdc_get_pixel_format(priv->l2bpp);
+ clrsetbits_le32(regs + LTDC_L1PFCR, LXPFCR_PF, format);
/* Constant alpha value */
clrsetbits_le32(regs + LTDC_L1CACR, LXCACR_CONSTA, priv->alpha);
+ /* Specifies the blending factors : with or without pixel alpha */
+ /* Manage hw-specific capabilities */
+ val = has_alpha(format) ? BF1_PAXCA | BF2_1PAXCA : BF1_CA | BF2_1CA;
+
/* Blending factors */
- clrsetbits_le32(regs + LTDC_L1BFCR, LXBFCR_BF2 | LXBFCR_BF1,
- BF1_PAXCA | BF2_1PAXCA);
+ clrsetbits_le32(regs + LTDC_L1BFCR, LXBFCR_BF2 | LXBFCR_BF1, val);
/* Frame buffer line number */
clrsetbits_le32(regs + LTDC_L1CFBLNR, LXCFBLNR_CFBLN, priv->crop_h);
@@ -301,8 +332,9 @@ static int stm32_ltdc_probe(struct udevice *dev)
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
struct stm32_ltdc_priv *priv = dev_get_priv(dev);
struct udevice *panel;
- struct clk pclk, pxclk;
- int ret;
+ struct clk pclk;
+ struct reset_ctl rst;
+ int rate, ret;
priv->regs = (void *)dev_read_addr(dev);
if ((fdt_addr_t)priv->regs == FDT_ADDR_T_NONE) {
@@ -310,45 +342,60 @@ static int stm32_ltdc_probe(struct udevice *dev)
return -EINVAL;
}
- ret = uclass_first_device(UCLASS_PANEL, &panel);
+ ret = clk_get_by_index(dev, 0, &pclk);
if (ret) {
- debug("%s: panel device error %d\n", __func__, ret);
+ debug("%s: peripheral clock get error %d\n", __func__, ret);
return ret;
}
- ret = panel_enable_backlight(panel);
+ ret = clk_enable(&pclk);
if (ret) {
- debug("%s: panel %s enable backlight error %d\n",
- __func__, panel->name, ret);
+ debug("%s: peripheral clock enable error %d\n",
+ __func__, ret);
return ret;
}
- ret = fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(dev),
- 0, &priv->timing);
+ ret = reset_get_by_index(dev, 0, &rst);
if (ret) {
- debug("%s: decode display timing error %d\n", __func__, ret);
- return -EINVAL;
+ debug("%s: missing ltdc hardware reset\n", __func__);
+ return -ENODEV;
}
- ret = clk_get_by_name(dev, "pclk", &pclk);
+ /* Reset */
+ reset_deassert(&rst);
+
+ ret = uclass_first_device(UCLASS_PANEL, &panel);
if (ret) {
- debug("%s: peripheral clock get error %d\n", __func__, ret);
+ debug("%s: panel device error %d\n", __func__, ret);
return ret;
}
- ret = clk_enable(&pclk);
+ ret = panel_enable_backlight(panel);
if (ret) {
- debug("%s: peripheral clock enable error %d\n", __func__, ret);
+ debug("%s: panel %s enable backlight error %d\n",
+ __func__, panel->name, ret);
return ret;
}
- /* Verify pixel clock value if any & inform user accordingly */
- ret = clk_get_by_name(dev, "pxclk", &pxclk);
- if (!ret) {
- if (clk_get_rate(&pxclk) != priv->timing.pixelclock.typ)
- printf("Warning: please adjust ltdc pixel clock\n");
+ ret = fdtdec_decode_display_timing(gd->fdt_blob,
+ dev_of_offset(dev), 0,
+ &priv->timing);
+ if (ret) {
+ debug("%s: decode display timing error %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ rate = clk_set_rate(&pclk, priv->timing.pixelclock.typ);
+ if (rate < 0) {
+ debug("%s: fail to set pixel clock %d hz %d hz\n",
+ __func__, priv->timing.pixelclock.typ, rate);
+ return rate;
}
+ debug("%s: Set pixel clock req %d hz get %d hz\n", __func__,
+ priv->timing.pixelclock.typ, rate);
+
/* TODO Below parameters are hard-coded for the moment... */
priv->l2bpp = VIDEO_BPP16;
priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */
@@ -397,10 +444,10 @@ static const struct udevice_id stm32_ltdc_ids[] = {
};
U_BOOT_DRIVER(stm32_ltdc) = {
- .name = "stm32_ltdc",
- .id = UCLASS_VIDEO,
- .of_match = stm32_ltdc_ids,
- .probe = stm32_ltdc_probe,
- .bind = stm32_ltdc_bind,
+ .name = "stm32_display",
+ .id = UCLASS_VIDEO,
+ .of_match = stm32_ltdc_ids,
+ .probe = stm32_ltdc_probe,
+ .bind = stm32_ltdc_bind,
.priv_auto_alloc_size = sizeof(struct stm32_ltdc_priv),
};
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index f191ef16c6..4da169fffd 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -8,6 +8,7 @@
*/
#include <common.h>
+#include <efi_loader.h>
#include <asm/arch/clock.h>
#include <asm/arch/display.h>
@@ -1207,6 +1208,13 @@ void *video_hw_init(void)
gd->bd->bi_dram[0].size - sunxi_display.fb_size;
sunxi_engines_init();
+#ifdef CONFIG_EFI_LOADER
+ efi_add_memory_map(gd->fb_base,
+ ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
+ EFI_PAGE_SHIFT,
+ EFI_RESERVED_MEMORY_TYPE, false);
+#endif
+
fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
sunxi_display.fb_addr = gd->fb_base;
if (overscan_offset) {
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index 5f63c12d6c..5553d629b9 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -13,7 +13,16 @@
#include <dm.h>
#include <video.h>
#include <video_console.h>
-#include <video_font.h> /* Get font data, width and height */
+#include <video_font.h> /* Bitmap font for code page 437 */
+
+/*
+ * Structure to describe a console color
+ */
+struct vid_rgb {
+ u32 r;
+ u32 g;
+ u32 b;
+};
/* By default we scroll by a single line */
#ifndef CONFIG_CONSOLE_SCROLL_LINES
@@ -108,38 +117,45 @@ static void vidconsole_newline(struct udevice *dev)
video_sync(dev->parent);
}
-static const struct {
- unsigned r;
- unsigned g;
- unsigned b;
-} colors[] = {
+static const struct vid_rgb colors[VID_COLOR_COUNT] = {
{ 0x00, 0x00, 0x00 }, /* black */
- { 0xff, 0x00, 0x00 }, /* red */
- { 0x00, 0xff, 0x00 }, /* green */
+ { 0xc0, 0x00, 0x00 }, /* red */
+ { 0x00, 0xc0, 0x00 }, /* green */
+ { 0xc0, 0x60, 0x00 }, /* brown */
+ { 0x00, 0x00, 0xc0 }, /* blue */
+ { 0xc0, 0x00, 0xc0 }, /* magenta */
+ { 0x00, 0xc0, 0xc0 }, /* cyan */
+ { 0xc0, 0xc0, 0xc0 }, /* light gray */
+ { 0x80, 0x80, 0x80 }, /* gray */
+ { 0xff, 0x00, 0x00 }, /* bright red */
+ { 0x00, 0xff, 0x00 }, /* bright green */
{ 0xff, 0xff, 0x00 }, /* yellow */
- { 0x00, 0x00, 0xff }, /* blue */
- { 0xff, 0x00, 0xff }, /* magenta */
- { 0x00, 0xff, 0xff }, /* cyan */
+ { 0x00, 0x00, 0xff }, /* bright blue */
+ { 0xff, 0x00, 0xff }, /* bright magenta */
+ { 0x00, 0xff, 0xff }, /* bright cyan */
{ 0xff, 0xff, 0xff }, /* white */
};
-static void set_color(struct video_priv *priv, unsigned idx, unsigned *c)
+u32 vid_console_color(struct video_priv *priv, unsigned int idx)
{
switch (priv->bpix) {
case VIDEO_BPP16:
- *c = ((colors[idx].r >> 3) << 0) |
- ((colors[idx].g >> 2) << 5) |
- ((colors[idx].b >> 3) << 11);
- break;
+ return ((colors[idx].r >> 3) << 11) |
+ ((colors[idx].g >> 2) << 5) |
+ ((colors[idx].b >> 3) << 0);
case VIDEO_BPP32:
- *c = 0xff000000 |
- (colors[idx].r << 0) |
- (colors[idx].g << 8) |
- (colors[idx].b << 16);
- break;
+ return (colors[idx].r << 16) |
+ (colors[idx].g << 8) |
+ (colors[idx].b << 0);
default:
- /* unsupported, leave current color in place */
- break;
+ /*
+ * For unknown bit arrangements just support
+ * black and white.
+ */
+ if (idx)
+ return 0xffffff; /* white */
+ else
+ return 0x000000; /* black */
}
}
@@ -270,18 +286,30 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
s++;
switch (val) {
+ case 0:
+ /* all attributes off */
+ video_set_default_colors(vid_priv);
+ break;
+ case 1:
+ /* bold */
+ vid_priv->fg_col_idx |= 8;
+ vid_priv->colour_fg = vid_console_color(
+ vid_priv, vid_priv->fg_col_idx);
+ break;
case 30 ... 37:
- /* fg color */
- set_color(vid_priv, val - 30,
- (unsigned *)&vid_priv->colour_fg);
+ /* foreground color */
+ vid_priv->fg_col_idx &= ~7;
+ vid_priv->fg_col_idx |= val - 30;
+ vid_priv->colour_fg = vid_console_color(
+ vid_priv, vid_priv->fg_col_idx);
break;
case 40 ... 47:
- /* bg color */
- set_color(vid_priv, val - 40,
- (unsigned *)&vid_priv->colour_bg);
+ /* background color */
+ vid_priv->colour_bg = vid_console_color(
+ vid_priv, val - 40);
break;
default:
- /* unknown/unsupported */
+ /* ignore unsupported SGR parameter */
break;
}
}
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index dcaceed42c..b5bb8e0efd 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -91,17 +91,43 @@ void video_clear(struct udevice *dev)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
- if (priv->bpix == VIDEO_BPP32) {
+ switch (priv->bpix) {
+ case VIDEO_BPP16: {
+ u16 *ppix = priv->fb;
+ u16 *end = priv->fb + priv->fb_size;
+
+ while (ppix < end)
+ *ppix++ = priv->colour_bg;
+ break;
+ }
+ case VIDEO_BPP32: {
u32 *ppix = priv->fb;
u32 *end = priv->fb + priv->fb_size;
while (ppix < end)
*ppix++ = priv->colour_bg;
- } else {
+ break;
+ }
+ default:
memset(priv->fb, priv->colour_bg, priv->fb_size);
+ break;
}
}
+void video_set_default_colors(struct video_priv *priv)
+{
+#ifdef CONFIG_SYS_WHITE_ON_BLACK
+ /* White is used when switching to bold, use light gray here */
+ priv->fg_col_idx = VID_LIGHT_GRAY;
+ priv->colour_fg = vid_console_color(priv, VID_LIGHT_GRAY);
+ priv->colour_bg = vid_console_color(priv, VID_BLACK);
+#else
+ priv->fg_col_idx = VID_BLACK;
+ priv->colour_fg = vid_console_color(priv, VID_BLACK);
+ priv->colour_bg = vid_console_color(priv, VID_WHITE);
+#endif
+}
+
/* Flush video activity to the caches */
void video_sync(struct udevice *vid)
{
@@ -191,12 +217,8 @@ static int video_post_probe(struct udevice *dev)
priv->line_length = priv->xsize * VNBYTES(priv->bpix);
priv->fb_size = priv->line_length * priv->ysize;
- /* Set up colours - we could in future support other colours */
-#ifdef CONFIG_SYS_WHITE_ON_BLACK
- priv->colour_fg = 0xffffff;
-#else
- priv->colour_bg = 0xffffff;
-#endif
+ /* Set up colors */
+ video_set_default_colors(priv);
if (!CONFIG_IS_ENABLED(NO_FB_CLEAR))
video_clear(dev);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index fc46b6774d..dca2c901ac 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1,5 +1,13 @@
menu "Watchdog Timer Support"
+config WATCHDOG
+ bool "Enable U-Boot watchdog reset"
+ help
+ This option enables U-Boot watchdog support where U-Boot is using
+ watchdog_reset function to service watchdog device in U-Boot. Enable
+ this option if you want to service enabled watchdog by U-Boot. Disable
+ this option if you want U-Boot to start watchdog but never service it.
+
config HW_WATCHDOG
bool
@@ -48,9 +56,9 @@ config WDT_SANDBOX
bool "Enable Watchdog Timer support for Sandbox"
depends on SANDBOX && WDT
help
- Enable Watchdog Timer support in Sandbox. This is a dummy device that
- can be probed and supports all of the methods of WDT, but does not
- really do anything.
+ Enable Watchdog Timer support in Sandbox. This is a dummy device that
+ can be probed and supports all of the methods of WDT, but does not
+ really do anything.
config WDT_ASPEED
bool "Aspeed ast2400/ast2500 watchdog timer support"
@@ -78,4 +86,12 @@ config WDT_ORION
Select this to enable Orion watchdog timer, which can be found on some
Marvell Armada chips.
+config WDT_CDNS
+ bool "Cadence watchdog timer support"
+ depends on WDT
+ imply WATCHDOG
+ help
+ Select this to enable Cadence watchdog timer, which can be found on some
+ Xilinx Microzed Platform.
+
endmenu
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index ab6a6b79e1..4fee6dbd1f 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -22,3 +22,5 @@ obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
obj-$(CONFIG_WDT_ORION) += orion_wdt.o
+obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
+obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o
diff --git a/drivers/watchdog/cdns_wdt.c b/drivers/watchdog/cdns_wdt.c
new file mode 100644
index 0000000000..71733cf8ba
--- /dev/null
+++ b/drivers/watchdog/cdns_wdt.c
@@ -0,0 +1,276 @@
+/*
+ * Cadence WDT driver - Used by Xilinx Zynq
+ * Reference: Linux kernel Cadence watchdog driver.
+ *
+ * Author(s): Shreenidhi Shedi <yesshedi@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <wdt.h>
+#include <clk.h>
+#include <linux/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct cdns_regs {
+ u32 zmr; /* WD Zero mode register, offset - 0x0 */
+ u32 ccr; /* Counter Control Register offset - 0x4 */
+ u32 restart; /* Restart key register, offset - 0x8 */
+ u32 status; /* Status Register, offset - 0xC */
+};
+
+struct cdns_wdt_priv {
+ bool rst;
+ u32 timeout;
+ void __iomem *reg;
+ struct cdns_regs *regs;
+};
+
+#define CDNS_WDT_DEFAULT_TIMEOUT 10
+
+/* Supports 1 - 516 sec */
+#define CDNS_WDT_MIN_TIMEOUT 1
+#define CDNS_WDT_MAX_TIMEOUT 516
+
+/* Restart key */
+#define CDNS_WDT_RESTART_KEY 0x00001999
+
+/* Counter register access key */
+#define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
+
+/* Counter value divisor */
+#define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
+
+/* Clock prescaler value and selection */
+#define CDNS_WDT_PRESCALE_64 64
+#define CDNS_WDT_PRESCALE_512 512
+#define CDNS_WDT_PRESCALE_4096 4096
+#define CDNS_WDT_PRESCALE_SELECT_64 1
+#define CDNS_WDT_PRESCALE_SELECT_512 2
+#define CDNS_WDT_PRESCALE_SELECT_4096 3
+
+/* Input clock frequency */
+#define CDNS_WDT_CLK_75MHZ 75000000
+
+/* Counter maximum value */
+#define CDNS_WDT_COUNTER_MAX 0xFFF
+
+/********************* Register Map **********************************/
+
+/*
+ * Zero Mode Register - This register controls how the time out is indicated
+ * and also contains the access code to allow writes to the register (0xABC).
+ */
+#define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */
+#define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */
+#define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */
+#define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */
+#define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */
+
+/*
+ * Counter Control register - This register controls how fast the timer runs
+ * and the reset value and also contains the access code to allow writes to
+ * the register.
+ */
+#define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */
+
+/* Write access to Registers */
+static inline void cdns_wdt_writereg(u32 *addr, u32 val)
+{
+ writel(val, addr);
+}
+
+/**
+ * cdns_wdt_reset - Reload the watchdog timer (i.e. pat the watchdog).
+ *
+ * @dev: Watchdog device
+ *
+ * Write the restart key value (0x00001999) to the restart register.
+ *
+ * Return: Always 0
+ */
+static int cdns_wdt_reset(struct udevice *dev)
+{
+ struct cdns_wdt_priv *priv = dev_get_priv(dev);
+
+ debug("%s\n", __func__);
+
+ cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
+
+ return 0;
+}
+
+/**
+ * cdns_wdt_start - Enable and start the watchdog.
+ *
+ * @dev: Watchdog device
+ * @timeout: Timeout value
+ * @flags: Driver flags
+ *
+ * The counter value is calculated according to the formula:
+ * count = (timeout * clock) / prescaler + 1.
+ *
+ * The calculated count is divided by 0x1000 to obtain the field value
+ * to write to counter control register.
+ *
+ * Clears the contents of prescaler and counter reset value. Sets the
+ * prescaler to 4096 and the calculated count and access key
+ * to write to CCR Register.
+ *
+ * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit)
+ * or Interrupt signal(IRQEN) with a specified cycles and the access
+ * key to write to ZMR Register.
+ *
+ * Return: Upon success 0, failure -1.
+ */
+static int cdns_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ ulong clk_f;
+ u32 count, prescaler, ctrl_clksel, data = 0;
+ struct clk clock;
+ struct cdns_wdt_priv *priv = dev_get_priv(dev);
+
+ if (clk_get_by_index(dev, 0, &clock) < 0) {
+ dev_err(dev, "failed to get clock\n");
+ return -1;
+ }
+
+ clk_f = clk_get_rate(&clock);
+ if (IS_ERR_VALUE(clk_f)) {
+ dev_err(dev, "failed to get rate\n");
+ return -1;
+ }
+
+ debug("%s: CLK_FREQ %ld, timeout %lld\n", __func__, clk_f, timeout);
+
+ if ((timeout < CDNS_WDT_MIN_TIMEOUT) ||
+ (timeout > CDNS_WDT_MAX_TIMEOUT)) {
+ timeout = priv->timeout;
+ }
+
+ if (clk_f <= CDNS_WDT_CLK_75MHZ) {
+ prescaler = CDNS_WDT_PRESCALE_512;
+ ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
+ } else {
+ prescaler = CDNS_WDT_PRESCALE_4096;
+ ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
+ }
+
+ /*
+ * Counter value divisor to obtain the value of
+ * counter reset to be written to control register.
+ */
+ count = (timeout * (clk_f / prescaler)) /
+ CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
+
+ if (count > CDNS_WDT_COUNTER_MAX)
+ count = CDNS_WDT_COUNTER_MAX;
+
+ cdns_wdt_writereg(&priv->regs->zmr, CDNS_WDT_ZMR_ZKEY_VAL);
+
+ count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
+
+ /* Write counter access key first to be able write to register */
+ data = count | CDNS_WDT_REGISTER_ACCESS_KEY | ctrl_clksel;
+ cdns_wdt_writereg(&priv->regs->ccr, data);
+
+ data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
+ CDNS_WDT_ZMR_ZKEY_VAL;
+
+ /* Reset on timeout if specified in device tree. */
+ if (priv->rst) {
+ data |= CDNS_WDT_ZMR_RSTEN_MASK;
+ data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
+ } else {
+ data &= ~CDNS_WDT_ZMR_RSTEN_MASK;
+ data |= CDNS_WDT_ZMR_IRQEN_MASK;
+ }
+
+ cdns_wdt_writereg(&priv->regs->zmr, data);
+ cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
+
+ return 0;
+}
+
+/**
+ * cdns_wdt_stop - Stop the watchdog.
+ *
+ * @dev: Watchdog device
+ *
+ * Read the contents of the ZMR register, clear the WDEN bit in the register
+ * and set the access key for successful write.
+ *
+ * Return: Always 0
+ */
+static int cdns_wdt_stop(struct udevice *dev)
+{
+ struct cdns_wdt_priv *priv = dev_get_priv(dev);
+
+ cdns_wdt_writereg(&priv->regs->zmr,
+ CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
+
+ return 0;
+}
+
+/**
+ * cdns_wdt_probe - Probe call for the device.
+ *
+ * @dev: Handle to the udevice structure.
+ *
+ * Return: Always 0.
+ */
+static int cdns_wdt_probe(struct udevice *dev)
+{
+ struct cdns_wdt_priv *priv = dev_get_priv(dev);
+
+ debug("%s: Probing wdt%u\n", __func__, dev->seq);
+
+ priv->reg = ioremap((u32)priv->regs, sizeof(struct cdns_regs));
+
+ cdns_wdt_stop(dev);
+
+ return 0;
+}
+
+static int cdns_wdt_ofdata_to_platdata(struct udevice *dev)
+{
+ int node = dev_of_offset(dev);
+ struct cdns_wdt_priv *priv = dev_get_priv(dev);
+
+ priv->regs = devfdt_get_addr_ptr(dev);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ priv->timeout = fdtdec_get_int(gd->fdt_blob, node, "timeout-sec",
+ CDNS_WDT_DEFAULT_TIMEOUT);
+
+ priv->rst = fdtdec_get_bool(gd->fdt_blob, node, "reset-on-timeout");
+
+ debug("%s: timeout %d, reset %d\n", __func__, priv->timeout, priv->rst);
+
+ return 0;
+}
+
+static const struct wdt_ops cdns_wdt_ops = {
+ .start = cdns_wdt_start,
+ .reset = cdns_wdt_reset,
+ .stop = cdns_wdt_stop,
+};
+
+static const struct udevice_id cdns_wdt_ids[] = {
+ { .compatible = "cdns,wdt-r1p2" },
+ {}
+};
+
+U_BOOT_DRIVER(cdns_wdt) = {
+ .name = "cdns_wdt",
+ .id = UCLASS_WDT,
+ .of_match = cdns_wdt_ids,
+ .probe = cdns_wdt_probe,
+ .priv_auto_alloc_size = sizeof(struct cdns_wdt_priv),
+ .ofdata_to_platdata = cdns_wdt_ofdata_to_platdata,
+ .ops = &cdns_wdt_ops,
+};
diff --git a/drivers/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c
new file mode 100644
index 0000000000..ded80c4d6a
--- /dev/null
+++ b/drivers/watchdog/mpc8xx_wdt.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2017 CS Systemes d'Information
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/cpm_8xx.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void hw_watchdog_reset(void)
+{
+ immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
+
+ out_be16(&immap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */
+ out_be16(&immap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */
+}
+
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 7b1f429432..d724c964ed 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -53,16 +53,25 @@ void hw_watchdog_reset(void)
{
struct wd_timer *wdt = (struct wd_timer *)WDT_BASE;
- /* wait for posted write to complete */
- while ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WTGR)
- ;
+ /*
+ * Somebody just triggered watchdog reset and write to WTGR register
+ * is in progress. It is resetting right now, no need to trigger it
+ * again
+ */
+ if ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WTGR)
+ return;
wdt_trgr_pattern = ~wdt_trgr_pattern;
writel(wdt_trgr_pattern, &wdt->wdtwtgr);
- /* wait for posted write to complete */
- while ((readl(&wdt->wdtwwps) & WDT_WWPS_PEND_WTGR))
- ;
+ /*
+ * Don't wait for posted write to complete, i.e. don't check
+ * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to
+ * WTGR register outside of this func, and if entering it
+ * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset
+ * was just triggered. This prevents us from wasting time in busy
+ * polling of WDT_WWPS_PEND_WTGR bit.
+ */
}
static int omap_wdt_set_timeout(unsigned int timeout)