summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/ata/Kconfig10
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c17
-rw-r--r--drivers/ata/fsl_ahci.c1030
-rw-r--r--drivers/ata/fsl_sata.h1
-rw-r--r--drivers/ata/sata_ceva.c50
-rw-r--r--drivers/board/gazerbeam.c22
-rw-r--r--drivers/cache/Kconfig25
-rw-r--r--drivers/cache/Makefile4
-rw-r--r--drivers/cache/cache-l2x0.c76
-rw-r--r--drivers/cache/cache-uclass.c24
-rw-r--r--drivers/cache/sandbox_cache.c34
-rw-r--r--drivers/clk/clk-uclass.c75
-rw-r--r--drivers/clk/clk_stm32mp1.c83
-rw-r--r--drivers/clk/imx/Makefile5
-rw-r--r--drivers/clk/imx/clk-imx8.c298
-rw-r--r--drivers/clk/imx/clk-imx8.h19
-rw-r--r--drivers/clk/imx/clk-imx8qm.c307
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c311
-rw-r--r--drivers/clk/meson/g12a.c103
-rw-r--r--drivers/clk/mpc83xx_clk.c7
-rw-r--r--drivers/clk/rockchip/clk_rk3036.c6
-rw-r--r--drivers/clk/rockchip/clk_rk3128.c6
-rw-r--r--drivers/clk/rockchip/clk_rk3188.c8
-rw-r--r--drivers/clk/rockchip/clk_rk322x.c12
-rw-r--r--drivers/clk/rockchip/clk_rk3288.c8
-rw-r--r--drivers/clk/rockchip/clk_rk3328.c8
-rw-r--r--drivers/clk/rockchip/clk_rk3368.c6
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c8
-rw-r--r--drivers/clk/rockchip/clk_rv1108.c6
-rw-r--r--drivers/clk/sifive/Kconfig7
-rw-r--r--drivers/clk/sifive/Makefile2
-rw-r--r--drivers/clk/sifive/fu540-prci.c2
-rw-r--r--drivers/clk/sifive/gemgxl-mgmt.c60
-rw-r--r--drivers/core/ofnode.c17
-rw-r--r--drivers/core/root.c2
-rw-r--r--drivers/ddr/altera/Kconfig11
-rw-r--r--drivers/ddr/altera/Makefile2
-rw-r--r--drivers/ddr/altera/sdram_s10.c243
-rw-r--r--drivers/ddr/altera/sdram_s10.h188
-rw-r--r--drivers/ddr/fsl/main.c4
-rw-r--r--drivers/ddr/imx/imx8m/Kconfig4
-rw-r--r--drivers/dma/apbh_dma.c2
-rw-r--r--drivers/dma/ti/k3-udma.c35
-rw-r--r--drivers/firmware/ti_sci.c13
-rw-r--r--drivers/fpga/socfpga_arria10.c514
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/dwapb_gpio.c28
-rw-r--r--drivers/gpio/gpio-rcar.c15
-rw-r--r--drivers/gpio/gpio-rza1.c134
-rw-r--r--drivers/gpio/rk_gpio.c3
-rw-r--r--drivers/i2c/Kconfig5
-rw-r--r--drivers/i2c/ihs_i2c.c124
-rw-r--r--drivers/i2c/mvtwsi.c11
-rw-r--r--drivers/i2c/mxc_i2c.c129
-rw-r--r--drivers/i2c/rk_i2c.c6
-rw-r--r--drivers/i2c/stm32f7_i2c.c6
-rw-r--r--drivers/misc/Kconfig72
-rw-r--r--drivers/misc/Makefile8
-rw-r--r--drivers/misc/cros_ec.c2
-rw-r--r--drivers/misc/gdsys_rxaui_ctrl.c9
-rw-r--r--drivers/misc/imx8/Makefile1
-rw-r--r--drivers/misc/imx8/fuse.c86
-rw-r--r--drivers/misc/imx8/scu.c16
-rw-r--r--drivers/misc/mxc_ocotp.c23
-rw-r--r--drivers/mmc/Kconfig20
-rw-r--r--drivers/mmc/bcmstb_sdhci.c73
-rw-r--r--drivers/mmc/dw_mmc.c38
-rw-r--r--drivers/mmc/fsl_esdhc.c29
-rw-r--r--drivers/mmc/renesas-sdhi.c185
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c4
-rw-r--r--drivers/mmc/sdhci.c188
-rw-r--r--drivers/mmc/tmio-common.h4
-rw-r--r--drivers/mtd/nand/raw/davinci_nand.c39
-rw-r--r--drivers/mtd/nand/raw/fsl_elbc_spl.c4
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.c2
-rw-r--r--drivers/mtd/spi/spi-nor-core.c27
-rw-r--r--drivers/mtd/ubi/Kconfig1
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/dwc_eth_qos.c2
-rw-r--r--drivers/net/fm/fm.c2
-rw-r--r--drivers/net/gmac_rockchip.c18
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.c1
-rw-r--r--drivers/net/macb.c57
-rw-r--r--drivers/net/mscc_eswitch/Kconfig7
-rw-r--r--drivers/net/mscc_eswitch/Makefile5
-rw-r--r--drivers/net/mscc_eswitch/luton_switch.c415
-rw-r--r--drivers/net/mscc_eswitch/ocelot_switch.c434
-rw-r--r--drivers/net/mscc_eswitch/serval_switch.c703
-rw-r--r--drivers/net/mtk_eth.c7
-rw-r--r--drivers/net/phy/Kconfig39
-rw-r--r--drivers/net/phy/aquantia.c7
-rw-r--r--drivers/net/phy/micrel_ksz8xxx.c8
-rw-r--r--drivers/net/phy/micrel_ksz90x1.c26
-rw-r--r--drivers/net/phy/phy.c21
-rw-r--r--drivers/net/phy/realtek.c19
-rw-r--r--drivers/net/phy/ti.c138
-rw-r--r--drivers/net/ravb.c13
-rw-r--r--drivers/net/rtl8169.c21
-rw-r--r--drivers/net/sh_eth.c14
-rw-r--r--drivers/net/sh_eth.h59
-rw-r--r--drivers/net/sun8i_emac.c74
-rw-r--r--drivers/net/ti/davinci_emac.c55
-rw-r--r--drivers/nvme/nvme.c4
-rw-r--r--drivers/nvme/nvme_show.c4
-rw-r--r--drivers/pci/Kconfig16
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/pci-rcar-gen3.c411
-rw-r--r--drivers/pci/pci_auto.c3
-rw-r--r--drivers/pci/pci_auto_old.c3
-rw-r--r--drivers/pci/pci_rom.c2
-rw-r--r--drivers/pci/pcie_layerscape_gen4.c572
-rw-r--r--drivers/pci/pcie_layerscape_gen4.h264
-rw-r--r--drivers/pci/pcie_layerscape_gen4_fixup.c249
-rw-r--r--drivers/phy/Kconfig8
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/meson-g12a-usb2.c216
-rw-r--r--drivers/phy/meson-g12a-usb3-pcie.c345
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx8.c1
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c99
-rw-r--r--drivers/pinctrl/renesas/Kconfig12
-rw-r--r--drivers/pinctrl/renesas/Makefile1
-rw-r--r--drivers/pinctrl/renesas/pfc-r7s72100.c146
-rw-r--r--drivers/pinctrl/renesas/pfc.c45
-rw-r--r--drivers/pinctrl/renesas/sh_pfc.h1
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3036.c56
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3128.c62
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3188.c62
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk322x.c100
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3288.c163
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3328.c125
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3368.c111
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3399.c167
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rockchip-core.c276
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rockchip.h69
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rv1108.c103
-rw-r--r--drivers/pwm/rk_pwm.c2
-rw-r--r--drivers/qe/Kconfig33
-rw-r--r--drivers/qe/qe.c2
-rw-r--r--drivers/ram/mpc83xx_sdram.c24
-rw-r--r--drivers/ram/rockchip/dmc-rk3368.c16
-rw-r--r--drivers/ram/rockchip/sdram_rk3128.c6
-rw-r--r--drivers/ram/rockchip/sdram_rk3188.c14
-rw-r--r--drivers/ram/rockchip/sdram_rk322x.c28
-rw-r--r--drivers/ram/rockchip/sdram_rk3288.c14
-rw-r--r--drivers/ram/rockchip/sdram_rk3328.c6
-rw-r--r--drivers/ram/rockchip/sdram_rk3399.c27
-rw-r--r--drivers/ram/stm32mp1/Kconfig37
-rw-r--r--drivers/ram/stm32mp1/Makefile8
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.c368
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.h4
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr_regs.h3
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_interactive.c483
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ram.c18
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_tests.c1426
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_tests.h34
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_tuning.c1380
-rw-r--r--drivers/remoteproc/k3_system_controller.c2
-rw-r--r--drivers/reset/reset-rockchip.c2
-rw-r--r--drivers/reset/reset-socfpga.c4
-rw-r--r--drivers/reset/reset-uclass.c53
-rw-r--r--drivers/rtc/rtc-lib.c2
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/altera_uart.c5
-rw-r--r--drivers/serial/mcfuart.c106
-rw-r--r--drivers/serial/serial_rockchip.c2
-rw-r--r--drivers/serial/serial_sh.c16
-rw-r--r--drivers/serial/serial_sh.h306
-rw-r--r--drivers/serial/serial_sifive.c2
-rw-r--r--drivers/serial/serial_stm32.c3
-rw-r--r--drivers/sound/Kconfig9
-rw-r--r--drivers/sound/Makefile1
-rw-r--r--drivers/sound/rockchip_sound.c2
-rw-r--r--drivers/sound/tegra_ahub.c256
-rw-r--r--drivers/sound/tegra_i2s.c123
-rw-r--r--drivers/sound/tegra_i2s_priv.h29
-rw-r--r--drivers/sound/tegra_sound.c100
-rw-r--r--drivers/spi/Kconfig12
-rw-r--r--drivers/spi/atcspi200_spi.c2
-rw-r--r--drivers/spi/cadence_qspi.c39
-rw-r--r--drivers/spi/cf_spi.c482
-rw-r--r--drivers/spi/designware_spi.c8
-rw-r--r--drivers/spi/renesas_rpc_spi.c12
-rw-r--r--drivers/spi/rk_spi.c167
-rw-r--r--drivers/sysreset/Kconfig20
-rw-r--r--drivers/sysreset/Makefile2
-rw-r--r--drivers/sysreset/sysreset_rockchip.c6
-rw-r--r--drivers/sysreset/sysreset_x86.c101
-rw-r--r--drivers/tee/sandbox.c2
-rw-r--r--drivers/timer/Kconfig7
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/dw-apb-timer.c2
-rw-r--r--drivers/timer/ostm_timer.c92
-rw-r--r--drivers/timer/rockchip_timer.c2
-rw-r--r--drivers/usb/dwc3/Kconfig8
-rw-r--r--drivers/usb/dwc3/Makefile1
-rw-r--r--drivers/usb/dwc3/dwc3-meson-g12a.c456
-rw-r--r--drivers/usb/gadget/f_rockusb.c2
-rw-r--r--drivers/usb/host/Kconfig12
-rw-r--r--drivers/usb/host/ehci-fsl.c10
-rw-r--r--drivers/usb/host/ehci-mx5.c103
-rw-r--r--drivers/usb/host/ohci-da8xx.c139
-rw-r--r--drivers/usb/host/ohci-hcd.c2
-rw-r--r--drivers/usb/musb/musb_hcd.c6
-rw-r--r--drivers/video/imx/mxc_ipuv3_fb.c3
-rw-r--r--drivers/video/rockchip/rk3288_hdmi.c6
-rw-r--r--drivers/video/rockchip/rk3288_mipi.c10
-rw-r--r--drivers/video/rockchip/rk3288_vop.c6
-rw-r--r--drivers/video/rockchip/rk3399_hdmi.c6
-rw-r--r--drivers/video/rockchip/rk3399_mipi.c10
-rw-r--r--drivers/video/rockchip/rk3399_vop.c2
-rw-r--r--drivers/video/rockchip/rk_edp.c6
-rw-r--r--drivers/video/rockchip/rk_hdmi.c5
-rw-r--r--drivers/video/rockchip/rk_lvds.c6
-rw-r--r--drivers/video/rockchip/rk_mipi.c9
-rw-r--r--drivers/video/rockchip/rk_vop.c7
-rw-r--r--drivers/video/rockchip/rk_vop.h2
-rw-r--r--drivers/video/vidconsole-uclass.c17
-rw-r--r--drivers/video/video-uclass.c2
-rw-r--r--drivers/watchdog/Kconfig11
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bcm6345_wdt.c21
-rw-r--r--drivers/watchdog/sp805_wdt.c127
226 files changed, 15214 insertions, 2538 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e6702eced4..96ff4f566a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -14,6 +14,8 @@ source "drivers/block/Kconfig"
source "drivers/bootcount/Kconfig"
+source "drivers/cache/Kconfig"
+
source "drivers/clk/Kconfig"
source "drivers/cpu/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index a7bba3ed56..6635dabd2c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_SPL_CRYPTO_SUPPORT) += crypto/
obj-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/
obj-$(CONFIG_ARMADA_38X) += ddr/marvell/a38x/
obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/
-obj-$(CONFIG_ALTERA_SDRAM) += ddr/altera/
+obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/
obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/
obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/
obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/
@@ -77,6 +77,7 @@ obj-$(CONFIG_BIOSEMU) += bios_emulator/
obj-y += block/
obj-y += board/
obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/
+obj-y += cache/
obj-$(CONFIG_CPU) += cpu/
obj-y += crypto/
obj-$(CONFIG_FASTBOOT) += fastboot/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4e95a68a2d..87636ae30f 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -59,6 +59,16 @@ config DWC_AHCI
Enable this driver to support Sata devices through
Synopsys DWC AHCI module.
+config FSL_AHCI
+ bool "Enable Freescale AHCI driver support"
+ select SCSI_AHCI
+ depends on AHCI
+ depends on DM_SCSI
+ help
+ Enable this driver to support Sata devices found in
+ some Freescale PowerPC SoCs.
+
+
config DWC_AHSATA
bool "Enable DWC AHSATA driver support"
select LIBATA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index a69edb10f7..6e03384f81 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -4,6 +4,7 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o
+obj-$(CONFIG_FSL_AHCI) += fsl_ahci.o
obj-$(CONFIG_AHCI) += ahci-uclass.o
obj-$(CONFIG_AHCI_PCI) += ahci-pci.o
obj-$(CONFIG_SCSI_AHCI) += ahci.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 5fafb63aeb..e3135bb75f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -55,17 +55,6 @@ __weak void __iomem *ahci_port_base(void __iomem *base, u32 port)
return base + 0x100 + (port * 0x80);
}
-
-static void ahci_setup_port(struct ahci_ioports *port, void __iomem *base,
- unsigned int port_idx)
-{
- base = ahci_port_base(base, port_idx);
-
- port->cmd_addr = base;
- port->scr_addr = base + PORT_SCR;
-}
-
-
#define msleep(a) udelay(a * 1000)
static void ahci_dcache_flush_range(unsigned long begin, unsigned long len)
@@ -240,7 +229,6 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
continue;
uc_priv->port[i].port_mmio = ahci_port_base(mmio, i);
port_mmio = (u8 *)uc_priv->port[i].port_mmio;
- ahci_setup_port(&uc_priv->port[i], mmio, i);
/* make sure port is not active */
tmp = readl(port_mmio + PORT_CMD);
@@ -571,15 +559,12 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
return -1;
}
- mem = malloc(AHCI_PORT_PRIV_DMA_SZ + 2048);
+ mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ);
if (!mem) {
free(pp);
printf("%s: No mem for table!\n", __func__);
return -ENOMEM;
}
-
- /* Aligned to 2048-bytes */
- mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ);
memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
/*
diff --git a/drivers/ata/fsl_ahci.c b/drivers/ata/fsl_ahci.c
new file mode 100644
index 0000000000..d04cff3ee7
--- /dev/null
+++ b/drivers/ata/fsl_ahci.c
@@ -0,0 +1,1030 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NXP PPC SATA platform driver
+ *
+ * (C) Copyright 2019 NXP, Inc.
+ *
+ */
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <dm/lists.h>
+#include <dm.h>
+#include <ahci.h>
+#include <scsi.h>
+#include <libata.h>
+#include <sata.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <fis.h>
+
+#include "fsl_sata.h"
+
+struct fsl_ahci_priv {
+ u32 base;
+ u32 flag;
+ u32 number;
+ fsl_sata_t *fsl_sata;
+};
+
+static int fsl_ahci_bind(struct udevice *dev)
+{
+ return device_bind_driver(dev, "fsl_ahci_scsi", "fsl_ahci_scsi", NULL);
+}
+
+static int fsl_ahci_ofdata_to_platdata(struct udevice *dev)
+{
+ struct fsl_ahci_priv *priv = dev_get_priv(dev);
+
+ priv->number = dev_read_u32_default(dev, "sata-number", -1);
+ priv->flag = dev_read_u32_default(dev, "sata-fpdma", -1);
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ata_wait_register(unsigned __iomem *addr, u32 mask,
+ u32 val, u32 timeout_msec)
+{
+ int i;
+
+ for (i = 0; ((in_le32(addr) & mask) != val) && i < timeout_msec; i++)
+ mdelay(1);
+
+ return (i < timeout_msec) ? 0 : -1;
+}
+
+static void fsl_sata_dump_sfis(struct sata_fis_d2h *s)
+{
+ printf("Status FIS dump:\n\r");
+ printf("fis_type: %02x\n\r", s->fis_type);
+ printf("pm_port_i: %02x\n\r", s->pm_port_i);
+ printf("status: %02x\n\r", s->status);
+ printf("error: %02x\n\r", s->error);
+ printf("lba_low: %02x\n\r", s->lba_low);
+ printf("lba_mid: %02x\n\r", s->lba_mid);
+ printf("lba_high: %02x\n\r", s->lba_high);
+ printf("device: %02x\n\r", s->device);
+ printf("lba_low_exp: %02x\n\r", s->lba_low_exp);
+ printf("lba_mid_exp: %02x\n\r", s->lba_mid_exp);
+ printf("lba_high_exp: %02x\n\r", s->lba_high_exp);
+ printf("res1: %02x\n\r", s->res1);
+ printf("sector_count: %02x\n\r", s->sector_count);
+ printf("sector_count_exp: %02x\n\r", s->sector_count_exp);
+}
+
+static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg)
+{
+ printf("\n\rSATA: %08x\n\r", (u32)reg);
+ printf("CQR: %08x\n\r", in_le32(&reg->cqr));
+ printf("CAR: %08x\n\r", in_le32(&reg->car));
+ printf("CCR: %08x\n\r", in_le32(&reg->ccr));
+ printf("CER: %08x\n\r", in_le32(&reg->cer));
+ printf("CQR: %08x\n\r", in_le32(&reg->cqr));
+ printf("DER: %08x\n\r", in_le32(&reg->der));
+ printf("CHBA: %08x\n\r", in_le32(&reg->chba));
+ printf("HStatus: %08x\n\r", in_le32(&reg->hstatus));
+ printf("HControl: %08x\n\r", in_le32(&reg->hcontrol));
+ printf("CQPMP: %08x\n\r", in_le32(&reg->cqpmp));
+ printf("SIG: %08x\n\r", in_le32(&reg->sig));
+ printf("ICC: %08x\n\r", in_le32(&reg->icc));
+ printf("SStatus: %08x\n\r", in_le32(&reg->sstatus));
+ printf("SError: %08x\n\r", in_le32(&reg->serror));
+ printf("SControl: %08x\n\r", in_le32(&reg->scontrol));
+ printf("SNotification: %08x\n\r", in_le32(&reg->snotification));
+ printf("TransCfg: %08x\n\r", in_le32(&reg->transcfg));
+ printf("TransStatus: %08x\n\r", in_le32(&reg->transstatus));
+ printf("LinkCfg: %08x\n\r", in_le32(&reg->linkcfg));
+ printf("LinkCfg1: %08x\n\r", in_le32(&reg->linkcfg1));
+ printf("LinkCfg2: %08x\n\r", in_le32(&reg->linkcfg2));
+ printf("LinkStatus: %08x\n\r", in_le32(&reg->linkstatus));
+ printf("LinkStatus1: %08x\n\r", in_le32(&reg->linkstatus1));
+ printf("PhyCtrlCfg: %08x\n\r", in_le32(&reg->phyctrlcfg));
+ printf("SYSPR: %08x\n\r", in_be32(&reg->syspr));
+}
+
+static int init_sata(struct fsl_ahci_priv *priv)
+{
+ int i;
+ u32 cda;
+ u32 val32;
+ u32 sig;
+ fsl_sata_t *sata;
+ u32 length, align;
+ cmd_hdr_tbl_t *cmd_hdr;
+ fsl_sata_reg_t __iomem *reg;
+
+ int dev = priv->number;
+
+ if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
+ printf("the sata index %d is out of ranges\n\r", dev);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MPC85xx
+ if (dev == 0 && (!is_serdes_configured(SATA1))) {
+ printf("SATA%d [dev = %d] is not enabled\n", dev + 1, dev);
+ return -EINVAL;
+ }
+ if (dev == 1 && (!is_serdes_configured(SATA2))) {
+ printf("SATA%d [dev = %d] is not enabled\n", dev + 1, dev);
+ return -EINVAL;
+ }
+#endif
+
+ /* Allocate SATA device driver struct */
+ sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t));
+ if (!sata) {
+ printf("alloc the sata device struct failed\n\r");
+ return -ENOMEM;
+ }
+ /* Zero all of the device driver struct */
+ memset((void *)sata, 0, sizeof(fsl_sata_t));
+
+ sata->dma_flag = priv->flag;
+ snprintf(sata->name, 12, "SATA%d", dev);
+
+ /* Set the controller register base address to device struct */
+ reg = (fsl_sata_reg_t *)priv->base;
+ sata->reg_base = reg;
+
+ /* Allocate the command header table, 4 bytes aligned */
+ length = sizeof(struct cmd_hdr_tbl);
+ align = SATA_HC_CMD_HDR_TBL_ALIGN;
+ sata->cmd_hdr_tbl_offset = (void *)malloc(length + align);
+ if (!sata->cmd_hdr_tbl_offset) {
+ printf("alloc the command header failed\n\r");
+ return -ENOMEM;
+ }
+
+ cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align)
+ & ~(align - 1));
+ sata->cmd_hdr = cmd_hdr;
+
+ /* Zero all of the command header table */
+ memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align);
+
+ /* Allocate command descriptor for all command */
+ length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD;
+ align = SATA_HC_CMD_DESC_ALIGN;
+ sata->cmd_desc_offset = (void *)malloc(length + align);
+ if (!sata->cmd_desc_offset) {
+ printf("alloc the command descriptor failed\n\r");
+ return -ENOMEM;
+ }
+ sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align)
+ & ~(align - 1));
+ /* Zero all of command descriptor */
+ memset((void *)sata->cmd_desc_offset, 0, length + align);
+
+ /* Link the command descriptor to command header */
+ for (i = 0; i < SATA_HC_MAX_CMD; i++) {
+ cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i)
+ & ~(CMD_HDR_CDA_ALIGN - 1);
+ cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda);
+ }
+
+ /* To have safe state, force the controller offline */
+ val32 = in_le32(&reg->hcontrol);
+ val32 &= ~HCONTROL_ONOFF;
+ val32 |= HCONTROL_FORCE_OFFLINE;
+ out_le32(&reg->hcontrol, val32);
+
+ /* Wait the controller offline */
+ ata_wait_register(&reg->hstatus, HSTATUS_ONOFF, 0, 1000);
+
+ /* Set the command header base address to CHBA register to tell DMA */
+ out_le32(&reg->chba, (u32)cmd_hdr & ~0x3);
+
+ /* Snoop for the command header */
+ val32 = in_le32(&reg->hcontrol);
+ val32 |= HCONTROL_HDR_SNOOP;
+ out_le32(&reg->hcontrol, val32);
+
+ /* Disable all of interrupts */
+ val32 = in_le32(&reg->hcontrol);
+ val32 &= ~HCONTROL_INT_EN_ALL;
+ out_le32(&reg->hcontrol, val32);
+
+ /* Clear all of interrupts */
+ val32 = in_le32(&reg->hstatus);
+ out_le32(&reg->hstatus, val32);
+
+ /* Set the ICC, no interrupt coalescing */
+ out_le32(&reg->icc, 0x01000000);
+
+ /* No PM attatched, the SATA device direct connect */
+ out_le32(&reg->cqpmp, 0);
+
+ /* Clear SError register */
+ val32 = in_le32(&reg->serror);
+ out_le32(&reg->serror, val32);
+
+ /* Clear CER register */
+ val32 = in_le32(&reg->cer);
+ out_le32(&reg->cer, val32);
+
+ /* Clear DER register */
+ val32 = in_le32(&reg->der);
+ out_le32(&reg->der, val32);
+
+ /* No device detection or initialization action requested */
+ out_le32(&reg->scontrol, 0x00000300);
+
+ /* Configure the transport layer, default value */
+ out_le32(&reg->transcfg, 0x08000016);
+
+ /* Configure the link layer, default value */
+ out_le32(&reg->linkcfg, 0x0000ff34);
+
+ /* Bring the controller online */
+ val32 = in_le32(&reg->hcontrol);
+ val32 |= HCONTROL_ONOFF;
+ out_le32(&reg->hcontrol, val32);
+
+ mdelay(100);
+
+ /* print sata device name */
+ printf("%s ", sata->name);
+
+ /* Wait PHY RDY signal changed for 500ms */
+ ata_wait_register(&reg->hstatus, HSTATUS_PHY_RDY,
+ HSTATUS_PHY_RDY, 500);
+
+ /* Check PHYRDY */
+ val32 = in_le32(&reg->hstatus);
+ if (val32 & HSTATUS_PHY_RDY) {
+ sata->link = 1;
+ } else {
+ sata->link = 0;
+ printf("(No RDY)\n\r");
+ return -EINVAL;
+ }
+
+ /* Wait for signature updated, which is 1st D2H */
+ ata_wait_register(&reg->hstatus, HSTATUS_SIGNATURE,
+ HSTATUS_SIGNATURE, 10000);
+
+ if (val32 & HSTATUS_SIGNATURE) {
+ sig = in_le32(&reg->sig);
+ debug("Signature updated, the sig =%08x\n\r", sig);
+ sata->ata_device_type = ata_dev_classify(sig);
+ }
+
+ /* Check the speed */
+ val32 = in_le32(&reg->sstatus);
+ if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1)
+ printf("(1.5 Gbps)\n\r");
+ else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2)
+ printf("(3 Gbps)\n\r");
+
+ priv->fsl_sata = sata;
+
+ return 0;
+}
+
+static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata,
+ struct sata_fis_h2d *cfis,
+ int is_ncq, int tag,
+ u8 *buffer, u32 len)
+{
+ cmd_hdr_entry_t *cmd_hdr;
+ cmd_desc_t *cmd_desc;
+ sata_fis_h2d_t *h2d;
+ prd_entry_t *prde;
+ u32 ext_c_ddc;
+ u32 prde_count;
+ u32 val32;
+ u32 ttl;
+ u32 der;
+ int i;
+
+ fsl_sata_reg_t *reg = sata->reg_base;
+
+ /* Check xfer length */
+ if (len > SATA_HC_MAX_XFER_LEN) {
+ printf("max transfer length is 64MB\n\r");
+ return 0;
+ }
+
+ /* Setup the command descriptor */
+ cmd_desc = sata->cmd_desc + tag;
+
+ /* Get the pointer cfis of command descriptor */
+ h2d = (sata_fis_h2d_t *)cmd_desc->cfis;
+
+ /* Zero the cfis of command descriptor */
+ memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE);
+
+ /* Copy the cfis from user to command descriptor */
+ h2d->fis_type = cfis->fis_type;
+ h2d->pm_port_c = cfis->pm_port_c;
+ h2d->command = cfis->command;
+
+ h2d->features = cfis->features;
+ h2d->features_exp = cfis->features_exp;
+
+ h2d->lba_low = cfis->lba_low;
+ h2d->lba_mid = cfis->lba_mid;
+ h2d->lba_high = cfis->lba_high;
+ h2d->lba_low_exp = cfis->lba_low_exp;
+ h2d->lba_mid_exp = cfis->lba_mid_exp;
+ h2d->lba_high_exp = cfis->lba_high_exp;
+
+ if (!is_ncq) {
+ h2d->sector_count = cfis->sector_count;
+ h2d->sector_count_exp = cfis->sector_count_exp;
+ } else { /* NCQ */
+ h2d->sector_count = (u8)(tag << 3);
+ }
+
+ h2d->device = cfis->device;
+ h2d->control = cfis->control;
+
+ /* Setup the PRD table */
+ prde = (prd_entry_t *)cmd_desc->prdt;
+ memset((void *)prde, 0, sizeof(struct prdt));
+
+ prde_count = 0;
+ ttl = len;
+ for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) {
+ if (!len)
+ break;
+ prde->dba = cpu_to_le32((u32)buffer & ~0x3);
+ debug("dba = %08x\n\r", (u32)buffer);
+
+ if (len < PRD_ENTRY_MAX_XFER_SZ) {
+ ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len;
+ debug("ext_c_ddc1 = %08x, len = %08x\n\r",
+ ext_c_ddc, len);
+ prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);
+ prde_count++;
+ prde++;
+ } else {
+ ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */
+ debug("ext_c_ddc2 = %08x, len = %08x\n\r",
+ ext_c_ddc, len);
+ prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);
+ buffer += PRD_ENTRY_MAX_XFER_SZ;
+ len -= PRD_ENTRY_MAX_XFER_SZ;
+ prde_count++;
+ prde++;
+ }
+ }
+
+ /* Setup the command slot of cmd hdr */
+ cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag];
+
+ cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3);
+
+ val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT;
+ val32 |= sizeof(sata_fis_h2d_t);
+ cmd_hdr->prde_fis_len = cpu_to_le32(val32);
+
+ cmd_hdr->ttl = cpu_to_le32(ttl);
+
+ if (!is_ncq)
+ val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP;
+ else
+ val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP |
+ CMD_HDR_ATTR_FPDMA;
+
+ tag &= CMD_HDR_ATTR_TAG;
+ val32 |= tag;
+
+ debug("attribute = %08x\n\r", val32);
+ cmd_hdr->attribute = cpu_to_le32(val32);
+
+ /* Make sure cmd desc and cmd slot valid before command issue */
+ sync();
+
+ /* PMP*/
+ val32 = (u32)(h2d->pm_port_c & 0x0f);
+ out_le32(&reg->cqpmp, val32);
+
+ /* Wait no active */
+ if (ata_wait_register(&reg->car, (1 << tag), 0, 10000))
+ printf("Wait no active time out\n\r");
+
+ /* Issue command */
+ if (!(in_le32(&reg->cqr) & (1 << tag))) {
+ val32 = 1 << tag;
+ out_le32(&reg->cqr, val32);
+ }
+
+ /* Wait command completed for 10s */
+ if (ata_wait_register(&reg->ccr, (1 << tag), (1 << tag), 10000)) {
+ if (!is_ncq)
+ printf("Non-NCQ command time out\n\r");
+ else
+ printf("NCQ command time out\n\r");
+ }
+
+ val32 = in_le32(&reg->cer);
+
+ if (val32) {
+ fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis);
+ printf("CE at device\n\r");
+ fsl_sata_dump_regs(reg);
+ der = in_le32(&reg->der);
+ out_le32(&reg->cer, val32);
+ out_le32(&reg->der, der);
+ }
+
+ /* Clear complete flags */
+ val32 = in_le32(&reg->ccr);
+ out_le32(&reg->ccr, val32);
+
+ return len;
+}
+
+static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
+ enum cmd_type command_type, int tag, u8 *buffer,
+ u32 len)
+{
+ int rc;
+
+ if (tag > SATA_HC_MAX_CMD || tag < 0) {
+ printf("tag is out of range, tag=%d\n\r", tag);
+ return -1;
+ }
+
+ switch (command_type) {
+ case CMD_ATA:
+ rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len);
+ return rc;
+ case CMD_NCQ:
+ rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len);
+ return rc;
+ case CMD_ATAPI:
+ case CMD_VENDOR_BIST:
+ case CMD_BIST:
+ printf("not support now\n\r");
+ return -1;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+static void fsl_sata_identify(fsl_sata_t *sata, u16 *id)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = ATA_CMD_ID_ATA;
+
+ fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2);
+ ata_swap_buf_le16(id, ATA_ID_WORDS);
+}
+
+static void fsl_sata_xfer_mode(fsl_sata_t *sata, u16 *id)
+{
+ sata->pio = id[ATA_ID_PIO_MODES];
+ sata->mwdma = id[ATA_ID_MWDMA_MODES];
+ sata->udma = id[ATA_ID_UDMA_MODES];
+ debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio,
+ sata->mwdma, sata->udma);
+}
+
+static void fsl_sata_init_wcache(fsl_sata_t *sata, u16 *id)
+{
+ if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
+ sata->wcache = 1;
+ if (ata_id_has_flush(id))
+ sata->flush = 1;
+ if (ata_id_has_flush_ext(id))
+ sata->flush_ext = 1;
+}
+
+static void fsl_sata_set_features(fsl_sata_t *sata)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+ u8 udma_cap;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = ATA_CMD_SET_FEATURES;
+ cfis->features = SETFEATURES_XFER;
+
+ /* First check the device capablity */
+ udma_cap = (u8)(sata->udma & 0xff);
+ debug("udma_cap %02x\n\r", udma_cap);
+
+ if (udma_cap == ATA_UDMA6)
+ cfis->sector_count = XFER_UDMA_6;
+ if (udma_cap == ATA_UDMA5)
+ cfis->sector_count = XFER_UDMA_5;
+ if (udma_cap == ATA_UDMA4)
+ cfis->sector_count = XFER_UDMA_4;
+ if (udma_cap == ATA_UDMA3)
+ cfis->sector_count = XFER_UDMA_3;
+
+ fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
+}
+
+static u32 fsl_sata_rw_cmd(fsl_sata_t *sata, u32 start, u32 blkcnt,
+ u8 *buffer, int is_write)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+ u32 block;
+
+ block = start;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ;
+ cfis->device = ATA_LBA;
+
+ cfis->device |= (block >> 24) & 0xf;
+ cfis->lba_high = (block >> 16) & 0xff;
+ cfis->lba_mid = (block >> 8) & 0xff;
+ cfis->lba_low = block & 0xff;
+ cfis->sector_count = (u8)(blkcnt & 0xff);
+
+ fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer,
+ ATA_SECT_SIZE * blkcnt);
+ return blkcnt;
+}
+
+static void fsl_sata_flush_cache(fsl_sata_t *sata)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = ATA_CMD_FLUSH;
+
+ fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
+}
+
+static u32 fsl_sata_rw_cmd_ext(fsl_sata_t *sata, u32 start,
+ u32 blkcnt, u8 *buffer, int is_write)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+ u64 block;
+
+ block = (u64)start;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+
+ cfis->command = (is_write) ? ATA_CMD_WRITE_EXT
+ : ATA_CMD_READ_EXT;
+
+ cfis->lba_high_exp = (block >> 40) & 0xff;
+ cfis->lba_mid_exp = (block >> 32) & 0xff;
+ cfis->lba_low_exp = (block >> 24) & 0xff;
+ cfis->lba_high = (block >> 16) & 0xff;
+ cfis->lba_mid = (block >> 8) & 0xff;
+ cfis->lba_low = block & 0xff;
+ cfis->device = ATA_LBA;
+ cfis->sector_count_exp = (blkcnt >> 8) & 0xff;
+ cfis->sector_count = blkcnt & 0xff;
+
+ fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer,
+ ATA_SECT_SIZE * blkcnt);
+ return blkcnt;
+}
+
+static u32 fsl_sata_rw_ncq_cmd(fsl_sata_t *sata, u32 start, u32 blkcnt,
+ u8 *buffer,
+ int is_write)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+ int ncq_channel;
+ u64 block;
+
+ if (sata->lba48 != 1) {
+ printf("execute FPDMA command on non-LBA48 hard disk\n\r");
+ return -1;
+ }
+
+ block = (u64)start;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+
+ cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE
+ : ATA_CMD_FPDMA_READ;
+
+ cfis->lba_high_exp = (block >> 40) & 0xff;
+ cfis->lba_mid_exp = (block >> 32) & 0xff;
+ cfis->lba_low_exp = (block >> 24) & 0xff;
+ cfis->lba_high = (block >> 16) & 0xff;
+ cfis->lba_mid = (block >> 8) & 0xff;
+ cfis->lba_low = block & 0xff;
+
+ cfis->device = ATA_LBA;
+ cfis->features_exp = (blkcnt >> 8) & 0xff;
+ cfis->features = blkcnt & 0xff;
+
+ if (sata->queue_depth >= SATA_HC_MAX_CMD)
+ ncq_channel = SATA_HC_MAX_CMD - 1;
+ else
+ ncq_channel = sata->queue_depth - 1;
+
+ /* Use the latest queue */
+ fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer,
+ ATA_SECT_SIZE * blkcnt);
+ return blkcnt;
+}
+
+static void fsl_sata_flush_cache_ext(fsl_sata_t *sata)
+{
+ struct sata_fis_h2d h2d, *cfis = &h2d;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = ATA_CMD_FLUSH_EXT;
+
+ fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
+}
+
+static u32 ata_low_level_rw_lba48(fsl_sata_t *sata, u32 blknr, lbaint_t blkcnt,
+ const void *buffer, int is_write)
+{
+ u32 start, blks;
+ u8 *addr;
+ int max_blks;
+
+ start = blknr;
+ blks = blkcnt;
+ addr = (u8 *)buffer;
+
+ max_blks = ATA_MAX_SECTORS_LBA48;
+ do {
+ if (blks > max_blks) {
+ if (sata->dma_flag != FLAGS_FPDMA)
+ fsl_sata_rw_cmd_ext(sata, start, max_blks,
+ addr, is_write);
+ else
+ fsl_sata_rw_ncq_cmd(sata, start, max_blks,
+ addr, is_write);
+ start += max_blks;
+ blks -= max_blks;
+ addr += ATA_SECT_SIZE * max_blks;
+ } else {
+ if (sata->dma_flag != FLAGS_FPDMA)
+ fsl_sata_rw_cmd_ext(sata, start, blks,
+ addr, is_write);
+ else
+ fsl_sata_rw_ncq_cmd(sata, start, blks,
+ addr, is_write);
+ start += blks;
+ blks = 0;
+ addr += ATA_SECT_SIZE * blks;
+ }
+ } while (blks != 0);
+
+ return blks;
+}
+
+static u32 ata_low_level_rw_lba28(fsl_sata_t *sata, u32 blknr, u32 blkcnt,
+ const void *buffer, int is_write)
+{
+ u32 start, blks;
+ u8 *addr;
+ int max_blks;
+
+ start = blknr;
+ blks = blkcnt;
+ addr = (u8 *)buffer;
+
+ max_blks = ATA_MAX_SECTORS;
+ do {
+ if (blks > max_blks) {
+ fsl_sata_rw_cmd(sata, start, max_blks, addr, is_write);
+ start += max_blks;
+ blks -= max_blks;
+ addr += ATA_SECT_SIZE * max_blks;
+ } else {
+ fsl_sata_rw_cmd(sata, start, blks, addr, is_write);
+ start += blks;
+ blks = 0;
+ addr += ATA_SECT_SIZE * blks;
+ }
+ } while (blks != 0);
+
+ return blks;
+}
+
+/*
+ * SATA interface between low level driver and command layer
+ */
+static int sata_read(fsl_sata_t *sata, ulong blknr, lbaint_t blkcnt,
+ void *buffer)
+{
+ u32 rc;
+
+ if (sata->lba48)
+ rc = ata_low_level_rw_lba48(sata, blknr, blkcnt, buffer,
+ READ_CMD);
+ else
+ rc = ata_low_level_rw_lba28(sata, blknr, blkcnt, buffer,
+ READ_CMD);
+ return rc;
+}
+
+static int sata_write(fsl_sata_t *sata, ulong blknr, lbaint_t blkcnt,
+ const void *buffer)
+{
+ u32 rc;
+
+ if (sata->lba48) {
+ rc = ata_low_level_rw_lba48(sata, blknr, blkcnt, buffer,
+ WRITE_CMD);
+ if (sata->wcache && sata->flush_ext)
+ fsl_sata_flush_cache_ext(sata);
+ } else {
+ rc = ata_low_level_rw_lba28(sata, blknr, blkcnt, buffer,
+ WRITE_CMD);
+ if (sata->wcache && sata->flush)
+ fsl_sata_flush_cache(sata);
+ }
+
+ return rc;
+}
+
+int sata_getinfo(fsl_sata_t *sata, u16 *id)
+{
+ /* if no detected link */
+ if (!sata->link)
+ return -EINVAL;
+
+#ifdef CONFIG_LBA48
+ /* Check if support LBA48 */
+ if (ata_id_has_lba48(id)) {
+ sata->lba48 = 1;
+ debug("Device support LBA48\n\r");
+ } else {
+ debug("Device supports LBA28\n\r");
+ }
+#endif
+
+ /* Get the NCQ queue depth from device */
+ sata->queue_depth = ata_id_queue_depth(id);
+
+ /* Get the xfer mode from device */
+ fsl_sata_xfer_mode(sata, id);
+
+ /* Get the write cache status from device */
+ fsl_sata_init_wcache(sata, id);
+
+ /* Set the xfer mode to highest speed */
+ fsl_sata_set_features(sata);
+
+ return 0;
+}
+
+static int fsl_scsi_exec(fsl_sata_t *sata, struct scsi_cmd *pccb,
+ bool is_write)
+{
+ int ret;
+ u32 temp;
+ u16 blocks = 0;
+ lbaint_t start = 0;
+ u8 *buffer = pccb->pdata;
+
+ /* Retrieve the base LBA number from the ccb structure. */
+ if (pccb->cmd[0] == SCSI_READ16) {
+ memcpy(&start, pccb->cmd + 2, 8);
+ start = be64_to_cpu(start);
+ } else {
+ memcpy(&temp, pccb->cmd + 2, 4);
+ start = be32_to_cpu(temp);
+ }
+
+ if (pccb->cmd[0] == SCSI_READ16)
+ blocks = (((u16)pccb->cmd[13]) << 8) | ((u16)pccb->cmd[14]);
+ else
+ blocks = (((u16)pccb->cmd[7]) << 8) | ((u16)pccb->cmd[8]);
+
+ debug("scsi_ahci: %s %u blocks starting from lba 0x" LBAFU "\n",
+ is_write ? "write" : "read", blocks, start);
+
+ if (is_write)
+ ret = sata_write(sata, start, blocks, buffer);
+ else
+ ret = sata_read(sata, start, blocks, buffer);
+
+ return ret;
+}
+
+static char *fsl_ata_id_strcpy(u16 *target, u16 *src, int len)
+{
+ int i;
+
+ for (i = 0; i < len / 2; i++)
+ target[i] = src[i];
+
+ return (char *)target;
+}
+
+static int fsl_ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb,
+ fsl_sata_t *sata)
+{
+ u8 port;
+ u16 *idbuf;
+
+ ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS);
+
+ /* Clean ccb data buffer */
+ memset(pccb->pdata, 0, pccb->datalen);
+
+ if (pccb->datalen <= 35)
+ return 0;
+
+ /* Read id from sata */
+ port = pccb->target;
+
+ fsl_sata_identify(sata, (u16 *)tmpid);
+
+ if (!uc_priv->ataid[port]) {
+ uc_priv->ataid[port] = malloc(ATA_ID_WORDS * 2);
+ if (!uc_priv->ataid[port]) {
+ printf("%s: No memory for ataid[port]\n", __func__);
+ return -ENOMEM;
+ }
+ }
+
+ idbuf = uc_priv->ataid[port];
+
+ memcpy(idbuf, tmpid, ATA_ID_WORDS * 2);
+
+ memcpy(&pccb->pdata[8], "ATA ", 8);
+ fsl_ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD], 16);
+ fsl_ata_id_strcpy((u16 *)&pccb->pdata[32], &idbuf[ATA_ID_FW_REV], 4);
+
+ sata_getinfo(sata, (u16 *)idbuf);
+#ifdef DEBUG
+ ata_dump_id(idbuf);
+#endif
+ return 0;
+}
+
+/*
+ * SCSI READ CAPACITY10 command operation.
+ */
+static int fsl_ata_scsiop_read_capacity10(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
+{
+ u32 cap;
+ u64 cap64;
+ u32 block_size;
+
+ if (!uc_priv->ataid[pccb->target]) {
+ printf("scsi_ahci: SCSI READ CAPACITY10 command failure.");
+ printf("\tNo ATA info!\n");
+ printf("\tPlease run SCSI command INQUIRY first!\n");
+ return -EPERM;
+ }
+
+ cap64 = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
+ if (cap64 > 0x100000000ULL)
+ cap64 = 0xffffffff;
+
+ cap = cpu_to_be32(cap64);
+ memcpy(pccb->pdata, &cap, sizeof(cap));
+
+ block_size = cpu_to_be32((u32)512);
+ memcpy(&pccb->pdata[4], &block_size, 4);
+
+ return 0;
+}
+
+/*
+ * SCSI READ CAPACITY16 command operation.
+ */
+static int fsl_ata_scsiop_read_capacity16(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
+{
+ u64 cap;
+ u64 block_size;
+
+ if (!uc_priv->ataid[pccb->target]) {
+ printf("scsi_ahci: SCSI READ CAPACITY16 command failure.");
+ printf("\tNo ATA info!\n");
+ printf("\tPlease run SCSI command INQUIRY first!\n");
+ return -EPERM;
+ }
+
+ cap = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
+ cap = cpu_to_be64(cap);
+ memcpy(pccb->pdata, &cap, sizeof(cap));
+
+ block_size = cpu_to_be64((u64)512);
+ memcpy(&pccb->pdata[8], &block_size, 8);
+
+ return 0;
+}
+
+/*
+ * SCSI TEST UNIT READY command operation.
+ */
+static int fsl_ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
+{
+ return (uc_priv->ataid[pccb->target]) ? 0 : -EPERM;
+}
+
+static int fsl_ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
+{
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev->parent);
+ struct fsl_ahci_priv *priv = dev_get_priv(dev->parent);
+ fsl_sata_t *sata = priv->fsl_sata;
+ int ret;
+
+ switch (pccb->cmd[0]) {
+ case SCSI_READ16:
+ case SCSI_READ10:
+ ret = fsl_scsi_exec(sata, pccb, 0);
+ break;
+ case SCSI_WRITE10:
+ ret = fsl_scsi_exec(sata, pccb, 1);
+ break;
+ case SCSI_RD_CAPAC10:
+ ret = fsl_ata_scsiop_read_capacity10(uc_priv, pccb);
+ break;
+ case SCSI_RD_CAPAC16:
+ ret = fsl_ata_scsiop_read_capacity16(uc_priv, pccb);
+ break;
+ case SCSI_TST_U_RDY:
+ ret = fsl_ata_scsiop_test_unit_ready(uc_priv, pccb);
+ break;
+ case SCSI_INQUIRY:
+ ret = fsl_ata_scsiop_inquiry(uc_priv, pccb, sata);
+ break;
+ default:
+ printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
+ return -ENOTSUPP;
+ }
+
+ if (ret) {
+ debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_ahci_probe(struct udevice *dev)
+{
+ struct fsl_ahci_priv *priv = dev_get_priv(dev);
+ struct udevice *child_dev;
+ struct scsi_platdata *uc_plat;
+
+ device_find_first_child(dev, &child_dev);
+ if (!child_dev)
+ return -ENODEV;
+ uc_plat = dev_get_uclass_platdata(child_dev);
+ uc_plat->base = priv->base;
+ uc_plat->max_lun = 1;
+ uc_plat->max_id = 1;
+
+ return init_sata(priv);
+}
+
+struct scsi_ops fsl_scsi_ops = {
+ .exec = fsl_ahci_scsi_exec,
+};
+
+static const struct udevice_id fsl_ahci_ids[] = {
+ { .compatible = "fsl,pq-sata-v2" },
+ { }
+};
+
+U_BOOT_DRIVER(fsl_ahci_scsi) = {
+ .name = "fsl_ahci_scsi",
+ .id = UCLASS_SCSI,
+ .ops = &fsl_scsi_ops,
+};
+
+U_BOOT_DRIVER(fsl_ahci) = {
+ .name = "fsl_ahci",
+ .id = UCLASS_AHCI,
+ .of_match = fsl_ahci_ids,
+ .bind = fsl_ahci_bind,
+ .ofdata_to_platdata = fsl_ahci_ofdata_to_platdata,
+ .probe = fsl_ahci_probe,
+ .priv_auto_alloc_size = sizeof(struct fsl_ahci_priv),
+};
diff --git a/drivers/ata/fsl_sata.h b/drivers/ata/fsl_sata.h
index 1e2da10b02..a4ee83d187 100644
--- a/drivers/ata/fsl_sata.h
+++ b/drivers/ata/fsl_sata.h
@@ -312,6 +312,7 @@ typedef struct fsl_sata {
int wcache;
int flush;
int flush_ext;
+ u32 dma_flag;
} fsl_sata_t;
#define READ_CMD 0
diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c
index 8887be901c..2d496305d0 100644
--- a/drivers/ata/sata_ceva.c
+++ b/drivers/ata/sata_ceva.c
@@ -8,6 +8,7 @@
#include <ahci.h>
#include <scsi.h>
#include <asm/io.h>
+#include <linux/ioport.h>
/* Vendor Specific Register Offsets */
#define AHCI_VEND_PCFG 0xA4
@@ -88,20 +89,16 @@
#define LS1021_CEVA_PHY4_CFG 0x064a080b
#define LS1021_CEVA_PHY5_CFG 0x2aa86470
-/* for ls1088a */
-#define LS1088_ECC_DIS_ADDR_CH2 0x100520
-#define LS1088_ECC_DIS_VAL_CH2 0x40000000
-
-/* ecc addr-val pair */
-#define ECC_DIS_ADDR_CH2 0x20140520
+/* ecc val pair */
+#define ECC_DIS_VAL_CH1 0x00020000
#define ECC_DIS_VAL_CH2 0x80000000
-#define SATA_ECC_REG_ADDR 0x20220520
-#define SATA_ECC_DISABLE 0x00020000
+#define ECC_DIS_VAL_CH3 0x40000000
enum ceva_soc {
CEVA_1V84,
CEVA_LS1012A,
CEVA_LS1021A,
+ CEVA_LS1028A,
CEVA_LS1043A,
CEVA_LS1046A,
CEVA_LS1088A,
@@ -110,12 +107,14 @@ enum ceva_soc {
struct ceva_sata_priv {
ulong base;
+ ulong ecc_base;
enum ceva_soc soc;
ulong flag;
};
static int ceva_init_sata(struct ceva_sata_priv *priv)
{
+ ulong ecc_addr = priv->ecc_base;
ulong base = priv->base;
ulong tmp;
@@ -132,38 +131,42 @@ static int ceva_init_sata(struct ceva_sata_priv *priv)
break;
case CEVA_LS1021A:
- writel(SATA_ECC_DISABLE, SATA_ECC_REG_ADDR);
+ if (!ecc_addr)
+ return -EINVAL;
+ writel(ECC_DIS_VAL_CH1, ecc_addr);
writel(CEVA_PHY1_CFG, base + AHCI_VEND_PPCFG);
writel(LS1021_CEVA_PHY2_CFG, base + AHCI_VEND_PP2C);
writel(LS1021_CEVA_PHY3_CFG, base + AHCI_VEND_PP3C);
writel(LS1021_CEVA_PHY4_CFG, base + AHCI_VEND_PP4C);
writel(LS1021_CEVA_PHY5_CFG, base + AHCI_VEND_PP5C);
writel(CEVA_TRANS_CFG, base + AHCI_VEND_PTC);
- if (priv->flag & FLAG_COHERENT)
- writel(CEVA_AXICC_CFG, base + LS1021_AHCI_VEND_AXICC);
break;
case CEVA_LS1012A:
case CEVA_LS1043A:
case CEVA_LS1046A:
- writel(ECC_DIS_VAL_CH2, ECC_DIS_ADDR_CH2);
+ if (!ecc_addr)
+ return -EINVAL;
+ writel(ECC_DIS_VAL_CH2, ecc_addr);
/* fallthrough */
case CEVA_LS2080A:
writel(CEVA_PHY1_CFG, base + AHCI_VEND_PPCFG);
writel(CEVA_TRANS_CFG, base + AHCI_VEND_PTC);
- if (priv->flag & FLAG_COHERENT)
- writel(CEVA_AXICC_CFG, base + AHCI_VEND_AXICC);
break;
+ case CEVA_LS1028A:
case CEVA_LS1088A:
- writel(LS1088_ECC_DIS_VAL_CH2, LS1088_ECC_DIS_ADDR_CH2);
+ if (!ecc_addr)
+ return -EINVAL;
+ writel(ECC_DIS_VAL_CH3, ecc_addr);
writel(CEVA_PHY1_CFG, base + AHCI_VEND_PPCFG);
writel(CEVA_TRANS_CFG, base + AHCI_VEND_PTC);
- if (priv->flag & FLAG_COHERENT)
- writel(CEVA_AXICC_CFG, base + AHCI_VEND_AXICC);
break;
}
+ if (priv->flag & FLAG_COHERENT)
+ writel(CEVA_AXICC_CFG, base + AHCI_VEND_AXICC);
+
return 0;
}
@@ -187,6 +190,7 @@ static const struct udevice_id sata_ceva_ids[] = {
{ .compatible = "ceva,ahci-1v84", .data = CEVA_1V84 },
{ .compatible = "fsl,ls1012a-ahci", .data = CEVA_LS1012A },
{ .compatible = "fsl,ls1021a-ahci", .data = CEVA_LS1021A },
+ { .compatible = "fsl,ls1028a-ahci", .data = CEVA_LS1028A },
{ .compatible = "fsl,ls1043a-ahci", .data = CEVA_LS1043A },
{ .compatible = "fsl,ls1046a-ahci", .data = CEVA_LS1046A },
{ .compatible = "fsl,ls1088a-ahci", .data = CEVA_LS1088A },
@@ -197,6 +201,8 @@ static const struct udevice_id sata_ceva_ids[] = {
static int sata_ceva_ofdata_to_platdata(struct udevice *dev)
{
struct ceva_sata_priv *priv = dev_get_priv(dev);
+ struct resource res_regs;
+ int ret;
if (dev_read_bool(dev, "dma-coherent"))
priv->flag |= FLAG_COHERENT;
@@ -205,8 +211,18 @@ static int sata_ceva_ofdata_to_platdata(struct udevice *dev)
if (priv->base == FDT_ADDR_T_NONE)
return -EINVAL;
+ ret = dev_read_resource_byname(dev, "ecc-addr", &res_regs);
+ if (ret)
+ priv->ecc_base = 0;
+ else
+ priv->ecc_base = res_regs.start;
+
priv->soc = dev_get_driver_data(dev);
+ debug("ccsr-sata-base %lx\t ecc-base %lx\n",
+ priv->base,
+ priv->ecc_base);
+
return 0;
}
diff --git a/drivers/board/gazerbeam.c b/drivers/board/gazerbeam.c
index 481cce8e80..85de4e440c 100644
--- a/drivers/board/gazerbeam.c
+++ b/drivers/board/gazerbeam.c
@@ -61,7 +61,7 @@ static int _read_board_variant_data(struct udevice *dev)
struct udevice *i2c_bus;
struct udevice *dummy;
char *listname;
- int mc4, mc2, sc, con;
+ int mc4, mc2, sc, mc2_sc, con;
int gpio_num;
int res;
@@ -78,16 +78,16 @@ static int _read_board_variant_data(struct udevice *dev)
return -EIO;
}
- mc2 = !dm_i2c_probe(i2c_bus, MC2_EXPANDER_ADDR, 0, &dummy);
+ mc2_sc = !dm_i2c_probe(i2c_bus, MC2_EXPANDER_ADDR, 0, &dummy);
mc4 = !dm_i2c_probe(i2c_bus, MC4_EXPANDER_ADDR, 0, &dummy);
- if (mc2 && mc4) {
+ if (mc2_sc && mc4) {
debug("%s: Board hardware configuration inconsistent.\n",
dev->name);
return -EINVAL;
}
- listname = mc2 ? "var-gpios-mc2" : "var-gpios-mc4";
+ listname = mc2_sc ? "var-gpios-mc2" : "var-gpios-mc4";
gpio_num = gpio_request_list_by_name(dev, listname, priv->var_gpios,
ARRAY_SIZE(priv->var_gpios),
@@ -105,12 +105,7 @@ static int _read_board_variant_data(struct udevice *dev)
return sc;
}
- con = dm_gpio_get_value(&priv->var_gpios[CON_GPIO_NO]);
- if (con < 0) {
- debug("%s: Error while reading 'con' GPIO (err = %d)",
- dev->name, con);
- return con;
- }
+ mc2 = mc2_sc ? (sc ? 0 : 1) : 0;
if ((sc && mc2) || (sc && mc4) || (!sc && !mc2 && !mc4)) {
debug("%s: Board hardware configuration inconsistent.\n",
@@ -118,6 +113,13 @@ static int _read_board_variant_data(struct udevice *dev)
return -EINVAL;
}
+ con = dm_gpio_get_value(&priv->var_gpios[CON_GPIO_NO]);
+ if (con < 0) {
+ debug("%s: Error while reading 'con' GPIO (err = %d)",
+ dev->name, con);
+ return con;
+ }
+
priv->variant = con ? VAR_CON : VAR_CPU;
priv->multichannel = mc4 ? 4 : (mc2 ? 2 : (sc ? 1 : 0));
diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
new file mode 100644
index 0000000000..24def7ac0f
--- /dev/null
+++ b/drivers/cache/Kconfig
@@ -0,0 +1,25 @@
+#
+# Cache controllers
+#
+
+menu "Cache Controller drivers"
+
+config CACHE
+ bool "Enable Driver Model for Cache controllers"
+ depends on DM
+ help
+ Enable driver model for cache controllers that are found on
+ most CPU's. Cache is memory that the CPU can access directly and
+ is usually located on the same chip. This uclass can be used for
+ configuring settings that be found from a device tree file.
+
+config L2X0_CACHE
+ tristate "PL310 cache driver"
+ select CACHE
+ depends on ARM
+ help
+ This driver is for the PL310 cache controller commonly found on
+ ARMv7(32-bit) devices. The driver configures the cache settings
+ found in the device tree.
+
+endmenu
diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
new file mode 100644
index 0000000000..9deb961d91
--- /dev/null
+++ b/drivers/cache/Makefile
@@ -0,0 +1,4 @@
+
+obj-$(CONFIG_CACHE) += cache-uclass.o
+obj-$(CONFIG_SANDBOX) += sandbox_cache.o
+obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o
diff --git a/drivers/cache/cache-l2x0.c b/drivers/cache/cache-l2x0.c
new file mode 100644
index 0000000000..67c752d076
--- /dev/null
+++ b/drivers/cache/cache-l2x0.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Intel Corporation <www.intel.com>
+ */
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+
+#include <asm/io.h>
+#include <asm/pl310.h>
+
+static void l2c310_of_parse_and_init(struct udevice *dev)
+{
+ u32 tag[3] = { 0, 0, 0 };
+ u32 saved_reg, prefetch;
+ struct pl310_regs *regs = (struct pl310_regs *)dev_read_addr(dev);
+
+ /* Disable the L2 Cache */
+ clrbits_le32(&regs->pl310_ctrl, L2X0_CTRL_EN);
+
+ saved_reg = readl(&regs->pl310_aux_ctrl);
+ if (!dev_read_u32(dev, "prefetch-data", &prefetch)) {
+ if (prefetch)
+ saved_reg |= L310_AUX_CTRL_DATA_PREFETCH_MASK;
+ else
+ saved_reg &= ~L310_AUX_CTRL_DATA_PREFETCH_MASK;
+ }
+
+ if (!dev_read_u32(dev, "prefetch-instr", &prefetch)) {
+ if (prefetch)
+ saved_reg |= L310_AUX_CTRL_INST_PREFETCH_MASK;
+ else
+ saved_reg &= ~L310_AUX_CTRL_INST_PREFETCH_MASK;
+ }
+
+ saved_reg |= dev_read_bool(dev, "arm,shared-override");
+ writel(saved_reg, &regs->pl310_aux_ctrl);
+
+ saved_reg = readl(&regs->pl310_tag_latency_ctrl);
+ if (!dev_read_u32_array(dev, "arm,tag-latency", tag, 3))
+ saved_reg |= L310_LATENCY_CTRL_RD(tag[0] - 1) |
+ L310_LATENCY_CTRL_WR(tag[1] - 1) |
+ L310_LATENCY_CTRL_SETUP(tag[2] - 1);
+ writel(saved_reg, &regs->pl310_tag_latency_ctrl);
+
+ saved_reg = readl(&regs->pl310_data_latency_ctrl);
+ if (!dev_read_u32_array(dev, "arm,data-latency", tag, 3))
+ saved_reg |= L310_LATENCY_CTRL_RD(tag[0] - 1) |
+ L310_LATENCY_CTRL_WR(tag[1] - 1) |
+ L310_LATENCY_CTRL_SETUP(tag[2] - 1);
+ writel(saved_reg, &regs->pl310_data_latency_ctrl);
+
+ /* Enable the L2 cache */
+ setbits_le32(&regs->pl310_ctrl, L2X0_CTRL_EN);
+}
+
+static int l2x0_probe(struct udevice *dev)
+{
+ l2c310_of_parse_and_init(dev);
+
+ return 0;
+}
+
+
+static const struct udevice_id l2x0_ids[] = {
+ { .compatible = "arm,pl310-cache" },
+ {}
+};
+
+U_BOOT_DRIVER(pl310_cache) = {
+ .name = "pl310_cache",
+ .id = UCLASS_CACHE,
+ .of_match = l2x0_ids,
+ .probe = l2x0_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/cache/cache-uclass.c b/drivers/cache/cache-uclass.c
new file mode 100644
index 0000000000..97ce0249a4
--- /dev/null
+++ b/drivers/cache/cache-uclass.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Intel Corporation <www.intel.com>
+ */
+
+#include <common.h>
+#include <cache.h>
+#include <dm.h>
+
+int cache_get_info(struct udevice *dev, struct cache_info *info)
+{
+ struct cache_ops *ops = cache_get_ops(dev);
+
+ if (!ops->get_info)
+ return -ENOSYS;
+
+ return ops->get_info(dev, info);
+}
+
+UCLASS_DRIVER(cache) = {
+ .id = UCLASS_CACHE,
+ .name = "cache",
+ .post_bind = dm_scan_fdt_dev,
+};
diff --git a/drivers/cache/sandbox_cache.c b/drivers/cache/sandbox_cache.c
new file mode 100644
index 0000000000..14cc6b0c0a
--- /dev/null
+++ b/drivers/cache/sandbox_cache.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Intel Corporation <www.intel.com>
+ */
+
+#include <common.h>
+#include <cache.h>
+#include <dm.h>
+#include <errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_get_info(struct udevice *dev, struct cache_info *info)
+{
+ info->base = 0x11223344;
+
+ return 0;
+}
+
+static const struct cache_ops sandbox_cache_ops = {
+ .get_info = sandbox_get_info,
+};
+
+static const struct udevice_id sandbox_cache_ids[] = {
+ { .compatible = "sandbox,cache" },
+ { }
+};
+
+U_BOOT_DRIVER(cache_sandbox) = {
+ .name = "cache_sandbox",
+ .id = UCLASS_CACHE,
+ .of_match = sandbox_cache_ids,
+ .ops = &sandbox_cache_ops,
+};
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 844b87cc33..79b3b0494c 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -54,28 +54,20 @@ static int clk_of_xlate_default(struct clk *clk,
return 0;
}
-static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
- int index, struct clk *clk)
+static int clk_get_by_index_tail(int ret, ofnode node,
+ struct ofnode_phandle_args *args,
+ const char *list_name, int index,
+ struct clk *clk)
{
- int ret;
- struct ofnode_phandle_args args;
struct udevice *dev_clk;
const struct clk_ops *ops;
- debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
-
assert(clk);
clk->dev = NULL;
+ if (ret)
+ goto err;
- ret = dev_read_phandle_with_args(dev, prop_name, "#clock-cells", 0,
- index, &args);
- if (ret) {
- debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
- __func__, ret);
- return ret;
- }
-
- ret = uclass_get_device_by_ofnode(UCLASS_CLK, args.node, &dev_clk);
+ ret = uclass_get_device_by_ofnode(UCLASS_CLK, args->node, &dev_clk);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
@@ -87,20 +79,67 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
ops = clk_dev_ops(dev_clk);
if (ops->of_xlate)
- ret = ops->of_xlate(clk, &args);
+ ret = ops->of_xlate(clk, args);
else
- ret = clk_of_xlate_default(clk, &args);
+ ret = clk_of_xlate_default(clk, args);
if (ret) {
debug("of_xlate() failed: %d\n", ret);
return ret;
}
return clk_request(dev_clk, clk);
+err:
+ debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n",
+ __func__, ofnode_get_name(node), list_name, index, ret);
+ return ret;
+}
+
+static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
+ int index, struct clk *clk)
+{
+ int ret;
+ struct ofnode_phandle_args args;
+
+ debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
+
+ assert(clk);
+ clk->dev = NULL;
+
+ ret = dev_read_phandle_with_args(dev, prop_name, "#clock-cells", 0,
+ index, &args);
+ if (ret) {
+ debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+
+ return clk_get_by_index_tail(ret, dev_ofnode(dev), &args, "clocks",
+ index > 0, clk);
}
int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
{
- return clk_get_by_indexed_prop(dev, "clocks", index, clk);
+ struct ofnode_phandle_args args;
+ int ret;
+
+ ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
+ index, &args);
+
+ return clk_get_by_index_tail(ret, dev_ofnode(dev), &args, "clocks",
+ index > 0, clk);
+}
+
+int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk)
+{
+ struct ofnode_phandle_args args;
+ int ret;
+
+ ret = ofnode_parse_phandle_with_args(node, "clocks", "#clock-cells", 0,
+ index > 0, &args);
+
+ return clk_get_by_index_tail(ret, node, &args, "clocks",
+ index > 0, clk);
}
int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index 24859fd054..6272b00b9e 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -1448,6 +1448,71 @@ static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg)
setbits_le32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL);
}
+static __maybe_unused int pll_set_rate(struct udevice *dev,
+ int pll_id,
+ int div_id,
+ unsigned long clk_rate)
+{
+ struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
+ unsigned int pllcfg[PLLCFG_NB];
+ ofnode plloff;
+ char name[12];
+ const struct stm32mp1_clk_pll *pll = priv->data->pll;
+ enum stm32mp1_plltype type = pll[pll_id].plltype;
+ int divm, divn, divy;
+ int ret;
+ ulong fck_ref;
+ u32 fracv;
+ u64 value;
+
+ if (div_id > _DIV_NB)
+ return -EINVAL;
+
+ sprintf(name, "st,pll@%d", pll_id);
+ plloff = dev_read_subnode(dev, name);
+ if (!ofnode_valid(plloff))
+ return -FDT_ERR_NOTFOUND;
+
+ ret = ofnode_read_u32_array(plloff, "cfg",
+ pllcfg, PLLCFG_NB);
+ if (ret < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ fck_ref = pll_get_fref_ck(priv, pll_id);
+
+ divm = pllcfg[PLLCFG_M];
+ /* select output divider = 0: for _DIV_P, 1:_DIV_Q 2:_DIV_R */
+ divy = pllcfg[PLLCFG_P + div_id];
+
+ /* 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)
+ * / (DIVy + 1) * (DIVM + 1)
+ * value = (DIVN + 1) * 2^13 + FRACV / 2^13
+ * = Fck_pll_y (DIVy + 1) * (DIVM + 1) * 2^13 / Fck_ref
+ */
+ value = ((u64)clk_rate * (divy + 1) * (divm + 1)) << 13;
+ value = lldiv(value, fck_ref);
+
+ divn = (value >> 13) - 1;
+ if (divn < DIVN_MIN ||
+ divn > stm32mp1_pll[type].divn_max) {
+ pr_err("divn invalid = %d", divn);
+ return -EINVAL;
+ }
+ fracv = value - ((divn + 1) << 13);
+ pllcfg[PLLCFG_N] = divn;
+
+ /* reconfigure PLL */
+ pll_stop(priv, pll_id);
+ pll_config(priv, pll_id, pllcfg, fracv);
+ pll_start(priv, pll_id);
+ pll_output(priv, pll_id, pllcfg[PLLCFG_O]);
+
+ return 0;
+}
+
static int set_clksrc(struct stm32mp1_clk_priv *priv, unsigned int clksrc)
{
u32 address = priv->base + (clksrc >> 4);
@@ -1820,6 +1885,11 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
int p;
switch (clk->id) {
+#if defined(STM32MP1_CLOCK_TREE_INIT) && \
+ defined(CONFIG_STM32MP1_DDR_INTERACTIVE)
+ case DDRPHYC:
+ break;
+#endif
case LTDC_PX:
case DSI_PX:
break;
@@ -1833,6 +1903,19 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
return -EINVAL;
switch (p) {
+#if defined(STM32MP1_CLOCK_TREE_INIT) && \
+ defined(CONFIG_STM32MP1_DDR_INTERACTIVE)
+ case _PLL2_R: /* DDRPHYC */
+ {
+ /* only for change DDR clock in interactive mode */
+ ulong result;
+
+ set_clksrc(priv, CLK_AXI_HSI);
+ result = pll_set_rate(clk->dev, _PLL2, _DIV_R, clk_rate);
+ set_clksrc(priv, CLK_AXI_PLL2P);
+ return result;
+ }
+#endif
case _PLL4_Q:
/* for LTDC_PX and DSI_PX case */
return pll_set_output_rate(clk->dev, _PLL4, _DIV_Q, clk_rate);
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 5505ae52e2..eb379c188a 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -3,3 +3,8 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CLK_IMX8) += clk-imx8.o
+
+ifdef CONFIG_CLK_IMX8
+obj-$(CONFIG_IMX8QXP) += clk-imx8qxp.o
+obj-$(CONFIG_IMX8QM) += clk-imx8qm.o
+endif
diff --git a/drivers/clk/imx/clk-imx8.c b/drivers/clk/imx/clk-imx8.c
index d03fcc2fdd..a755e26501 100644
--- a/drivers/clk/imx/clk-imx8.c
+++ b/drivers/clk/imx/clk-imx8.c
@@ -13,302 +13,21 @@
#include <dt-bindings/soc/imx_rsrc.h>
#include <misc.h>
-struct imx8_clks {
- ulong id;
- const char *name;
-};
-
-#if CONFIG_IS_ENABLED(CMD_CLK)
-static struct imx8_clks imx8_clk_names[] = {
- { IMX8QXP_A35_DIV, "A35_DIV" },
- { IMX8QXP_I2C0_CLK, "I2C0" },
- { IMX8QXP_I2C1_CLK, "I2C1" },
- { IMX8QXP_I2C2_CLK, "I2C2" },
- { IMX8QXP_I2C3_CLK, "I2C3" },
- { IMX8QXP_UART0_CLK, "UART0" },
- { IMX8QXP_UART1_CLK, "UART1" },
- { IMX8QXP_UART2_CLK, "UART2" },
- { IMX8QXP_UART3_CLK, "UART3" },
- { IMX8QXP_SDHC0_CLK, "SDHC0" },
- { IMX8QXP_SDHC1_CLK, "SDHC1" },
- { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
- { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
- { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
- { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
- { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
- { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
- { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
- { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
-};
-#endif
+#include "clk-imx8.h"
-static ulong imx8_clk_get_rate(struct clk *clk)
+__weak ulong imx8_clk_get_rate(struct clk *clk)
{
- sc_pm_clk_t pm_clk;
- ulong rate;
- u16 resource;
- int ret;
-
- debug("%s(#%lu)\n", __func__, clk->id);
-
- switch (clk->id) {
- case IMX8QXP_A35_DIV:
- resource = SC_R_A35;
- pm_clk = SC_PM_CLK_CPU;
- break;
- case IMX8QXP_I2C0_CLK:
- resource = SC_R_I2C_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C1_CLK:
- resource = SC_R_I2C_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C2_CLK:
- resource = SC_R_I2C_2;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C3_CLK:
- resource = SC_R_I2C_3;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_SDHC0_IPG_CLK:
- case IMX8QXP_SDHC0_CLK:
- case IMX8QXP_SDHC0_DIV:
- resource = SC_R_SDHC_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_SDHC1_IPG_CLK:
- case IMX8QXP_SDHC1_CLK:
- case IMX8QXP_SDHC1_DIV:
- resource = SC_R_SDHC_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART0_IPG_CLK:
- case IMX8QXP_UART0_CLK:
- resource = SC_R_UART_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART1_CLK:
- resource = SC_R_UART_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART2_CLK:
- resource = SC_R_UART_2;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART3_CLK:
- resource = SC_R_UART_3;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_ENET0_IPG_CLK:
- case IMX8QXP_ENET0_AHB_CLK:
- case IMX8QXP_ENET0_REF_DIV:
- case IMX8QXP_ENET0_PTP_CLK:
- resource = SC_R_ENET_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_ENET1_IPG_CLK:
- case IMX8QXP_ENET1_AHB_CLK:
- case IMX8QXP_ENET1_REF_DIV:
- case IMX8QXP_ENET1_PTP_CLK:
- resource = SC_R_ENET_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- default:
- if (clk->id < IMX8QXP_UART0_IPG_CLK ||
- clk->id >= IMX8QXP_CLK_END) {
- printf("%s(Invalid clk ID #%lu)\n",
- __func__, clk->id);
- return -EINVAL;
- }
- return -ENOTSUPP;
- };
-
- ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
- (sc_pm_clock_rate_t *)&rate);
- if (ret) {
- printf("%s err %d\n", __func__, ret);
- return ret;
- }
-
- return rate;
+ return 0;
}
-static ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
+__weak ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
{
- sc_pm_clk_t pm_clk;
- u32 new_rate = rate;
- u16 resource;
- int ret;
-
- debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
-
- switch (clk->id) {
- case IMX8QXP_I2C0_CLK:
- resource = SC_R_I2C_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C1_CLK:
- resource = SC_R_I2C_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C2_CLK:
- resource = SC_R_I2C_2;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C3_CLK:
- resource = SC_R_I2C_3;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART0_CLK:
- resource = SC_R_UART_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART1_CLK:
- resource = SC_R_UART_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART2_CLK:
- resource = SC_R_UART_2;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART3_CLK:
- resource = SC_R_UART_3;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_SDHC0_IPG_CLK:
- case IMX8QXP_SDHC0_CLK:
- case IMX8QXP_SDHC0_DIV:
- resource = SC_R_SDHC_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_SDHC1_SEL:
- case IMX8QXP_SDHC0_SEL:
- return 0;
- case IMX8QXP_SDHC1_IPG_CLK:
- case IMX8QXP_SDHC1_CLK:
- case IMX8QXP_SDHC1_DIV:
- resource = SC_R_SDHC_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_ENET0_IPG_CLK:
- case IMX8QXP_ENET0_AHB_CLK:
- case IMX8QXP_ENET0_REF_DIV:
- case IMX8QXP_ENET0_PTP_CLK:
- resource = SC_R_ENET_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_ENET1_IPG_CLK:
- case IMX8QXP_ENET1_AHB_CLK:
- case IMX8QXP_ENET1_REF_DIV:
- case IMX8QXP_ENET1_PTP_CLK:
- resource = SC_R_ENET_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- default:
- if (clk->id < IMX8QXP_UART0_IPG_CLK ||
- clk->id >= IMX8QXP_CLK_END) {
- printf("%s(Invalid clk ID #%lu)\n",
- __func__, clk->id);
- return -EINVAL;
- }
- return -ENOTSUPP;
- };
-
- ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
- if (ret) {
- printf("%s err %d\n", __func__, ret);
- return ret;
- }
-
- return new_rate;
+ return 0;
}
-static int __imx8_clk_enable(struct clk *clk, bool enable)
+__weak int __imx8_clk_enable(struct clk *clk, bool enable)
{
- sc_pm_clk_t pm_clk;
- u16 resource;
- int ret;
-
- debug("%s(#%lu)\n", __func__, clk->id);
-
- switch (clk->id) {
- case IMX8QXP_I2C0_CLK:
- resource = SC_R_I2C_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C1_CLK:
- resource = SC_R_I2C_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C2_CLK:
- resource = SC_R_I2C_2;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_I2C3_CLK:
- resource = SC_R_I2C_3;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART0_CLK:
- resource = SC_R_UART_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART1_CLK:
- resource = SC_R_UART_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART2_CLK:
- resource = SC_R_UART_2;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_UART3_CLK:
- resource = SC_R_UART_3;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_SDHC0_IPG_CLK:
- case IMX8QXP_SDHC0_CLK:
- case IMX8QXP_SDHC0_DIV:
- resource = SC_R_SDHC_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_SDHC1_IPG_CLK:
- case IMX8QXP_SDHC1_CLK:
- case IMX8QXP_SDHC1_DIV:
- resource = SC_R_SDHC_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_ENET0_IPG_CLK:
- case IMX8QXP_ENET0_AHB_CLK:
- case IMX8QXP_ENET0_REF_DIV:
- case IMX8QXP_ENET0_PTP_CLK:
- resource = SC_R_ENET_0;
- pm_clk = SC_PM_CLK_PER;
- break;
- case IMX8QXP_ENET1_IPG_CLK:
- case IMX8QXP_ENET1_AHB_CLK:
- case IMX8QXP_ENET1_REF_DIV:
- case IMX8QXP_ENET1_PTP_CLK:
- resource = SC_R_ENET_1;
- pm_clk = SC_PM_CLK_PER;
- break;
- default:
- if (clk->id < IMX8QXP_UART0_IPG_CLK ||
- clk->id >= IMX8QXP_CLK_END) {
- printf("%s(Invalid clk ID #%lu)\n",
- __func__, clk->id);
- return -EINVAL;
- }
- return -ENOTSUPP;
- }
-
- ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
- if (ret) {
- printf("%s err %d\n", __func__, ret);
- return ret;
- }
-
- return 0;
+ return -ENOTSUPP;
}
static int imx8_clk_disable(struct clk *clk)
@@ -336,7 +55,7 @@ int soc_clk_dump(void)
printf("Clk\t\tHz\n");
- for (i = 0; i < ARRAY_SIZE(imx8_clk_names); i++) {
+ for (i = 0; i < num_clks; i++) {
clk.id = imx8_clk_names[i].id;
ret = clk_request(dev, &clk);
if (ret < 0) {
@@ -382,6 +101,7 @@ static int imx8_clk_probe(struct udevice *dev)
static const struct udevice_id imx8_clk_ids[] = {
{ .compatible = "fsl,imx8qxp-clk" },
+ { .compatible = "fsl,imx8qm-clk" },
{ },
};
diff --git a/drivers/clk/imx/clk-imx8.h b/drivers/clk/imx/clk-imx8.h
new file mode 100644
index 0000000000..68ad6755e8
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+struct imx8_clks {
+ ulong id;
+ const char *name;
+};
+
+#if CONFIG_IS_ENABLED(CMD_CLK)
+extern struct imx8_clks imx8_clk_names[];
+extern int num_clks;
+#endif
+
+ulong imx8_clk_get_rate(struct clk *clk);
+ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate);
+int __imx8_clk_enable(struct clk *clk, bool enable);
diff --git a/drivers/clk/imx/clk-imx8qm.c b/drivers/clk/imx/clk-imx8qm.c
new file mode 100644
index 0000000000..6b5561e178
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qm.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 NXP
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/clock.h>
+#include <dt-bindings/clock/imx8qm-clock.h>
+#include <dt-bindings/soc/imx_rsrc.h>
+#include <misc.h>
+
+#include "clk-imx8.h"
+
+#if CONFIG_IS_ENABLED(CMD_CLK)
+struct imx8_clks imx8_clk_names[] = {
+ { IMX8QM_A53_DIV, "A53_DIV" },
+ { IMX8QM_UART0_CLK, "UART0" },
+ { IMX8QM_UART1_CLK, "UART1" },
+ { IMX8QM_UART2_CLK, "UART2" },
+ { IMX8QM_UART3_CLK, "UART3" },
+ { IMX8QM_SDHC0_CLK, "SDHC0" },
+ { IMX8QM_SDHC1_CLK, "SDHC1" },
+ { IMX8QM_SDHC2_CLK, "SDHC2" },
+ { IMX8QM_ENET0_AHB_CLK, "ENET0_AHB" },
+ { IMX8QM_ENET0_IPG_CLK, "ENET0_IPG" },
+ { IMX8QM_ENET0_REF_DIV, "ENET0_REF" },
+ { IMX8QM_ENET0_PTP_CLK, "ENET0_PTP" },
+ { IMX8QM_ENET1_AHB_CLK, "ENET1_AHB" },
+ { IMX8QM_ENET1_IPG_CLK, "ENET1_IPG" },
+ { IMX8QM_ENET1_REF_DIV, "ENET1_REF" },
+ { IMX8QM_ENET1_PTP_CLK, "ENET1_PTP" },
+};
+
+int num_clks = ARRAY_SIZE(imx8_clk_names);
+#endif
+
+ulong imx8_clk_get_rate(struct clk *clk)
+{
+ sc_pm_clk_t pm_clk;
+ ulong rate;
+ u16 resource;
+ int ret;
+
+ debug("%s(#%lu)\n", __func__, clk->id);
+
+ switch (clk->id) {
+ case IMX8QM_A53_DIV:
+ resource = SC_R_A53;
+ pm_clk = SC_PM_CLK_CPU;
+ break;
+ case IMX8QM_I2C0_CLK:
+ resource = SC_R_I2C_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C1_CLK:
+ resource = SC_R_I2C_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C2_CLK:
+ resource = SC_R_I2C_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C3_CLK:
+ resource = SC_R_I2C_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_SDHC0_IPG_CLK:
+ case IMX8QM_SDHC0_CLK:
+ case IMX8QM_SDHC0_DIV:
+ resource = SC_R_SDHC_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_SDHC1_IPG_CLK:
+ case IMX8QM_SDHC1_CLK:
+ case IMX8QM_SDHC1_DIV:
+ resource = SC_R_SDHC_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART0_IPG_CLK:
+ case IMX8QM_UART0_CLK:
+ resource = SC_R_UART_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART1_CLK:
+ resource = SC_R_UART_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART2_CLK:
+ resource = SC_R_UART_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART3_CLK:
+ resource = SC_R_UART_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_ENET0_IPG_CLK:
+ case IMX8QM_ENET0_AHB_CLK:
+ case IMX8QM_ENET0_REF_DIV:
+ case IMX8QM_ENET0_PTP_CLK:
+ resource = SC_R_ENET_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_ENET1_IPG_CLK:
+ case IMX8QM_ENET1_AHB_CLK:
+ case IMX8QM_ENET1_REF_DIV:
+ case IMX8QM_ENET1_PTP_CLK:
+ resource = SC_R_ENET_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ default:
+ if (clk->id < IMX8QM_UART0_IPG_CLK ||
+ clk->id >= IMX8QM_CLK_END) {
+ printf("%s(Invalid clk ID #%lu)\n",
+ __func__, clk->id);
+ return -EINVAL;
+ }
+ return -ENOTSUPP;
+ };
+
+ ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
+ (sc_pm_clock_rate_t *)&rate);
+ if (ret) {
+ printf("%s err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return rate;
+}
+
+ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ sc_pm_clk_t pm_clk;
+ u32 new_rate = rate;
+ u16 resource;
+ int ret;
+
+ debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
+
+ switch (clk->id) {
+ case IMX8QM_I2C0_CLK:
+ resource = SC_R_I2C_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C1_CLK:
+ resource = SC_R_I2C_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C2_CLK:
+ resource = SC_R_I2C_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C3_CLK:
+ resource = SC_R_I2C_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART0_CLK:
+ resource = SC_R_UART_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART1_CLK:
+ resource = SC_R_UART_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART2_CLK:
+ resource = SC_R_UART_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART3_CLK:
+ resource = SC_R_UART_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_SDHC0_IPG_CLK:
+ case IMX8QM_SDHC0_CLK:
+ case IMX8QM_SDHC0_DIV:
+ resource = SC_R_SDHC_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_SDHC1_IPG_CLK:
+ case IMX8QM_SDHC1_CLK:
+ case IMX8QM_SDHC1_DIV:
+ resource = SC_R_SDHC_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_ENET0_IPG_CLK:
+ case IMX8QM_ENET0_AHB_CLK:
+ case IMX8QM_ENET0_REF_DIV:
+ case IMX8QM_ENET0_PTP_CLK:
+ case IMX8QM_ENET0_ROOT_DIV:
+ resource = SC_R_ENET_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_ENET1_IPG_CLK:
+ case IMX8QM_ENET1_AHB_CLK:
+ case IMX8QM_ENET1_REF_DIV:
+ case IMX8QM_ENET1_PTP_CLK:
+ case IMX8QM_ENET1_ROOT_DIV:
+ resource = SC_R_ENET_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ default:
+ if (clk->id < IMX8QM_UART0_IPG_CLK ||
+ clk->id >= IMX8QM_CLK_END) {
+ printf("%s(Invalid clk ID #%lu)\n",
+ __func__, clk->id);
+ return -EINVAL;
+ }
+ return -ENOTSUPP;
+ };
+
+ ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
+ if (ret) {
+ printf("%s err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return new_rate;
+}
+
+int __imx8_clk_enable(struct clk *clk, bool enable)
+{
+ sc_pm_clk_t pm_clk;
+ u16 resource;
+ int ret;
+
+ debug("%s(#%lu)\n", __func__, clk->id);
+
+ switch (clk->id) {
+ case IMX8QM_I2C0_CLK:
+ resource = SC_R_I2C_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C1_CLK:
+ resource = SC_R_I2C_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C2_CLK:
+ resource = SC_R_I2C_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_I2C3_CLK:
+ resource = SC_R_I2C_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART0_CLK:
+ resource = SC_R_UART_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART1_CLK:
+ resource = SC_R_UART_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART2_CLK:
+ resource = SC_R_UART_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_UART3_CLK:
+ resource = SC_R_UART_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_SDHC0_IPG_CLK:
+ case IMX8QM_SDHC0_CLK:
+ case IMX8QM_SDHC0_DIV:
+ resource = SC_R_SDHC_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_SDHC1_IPG_CLK:
+ case IMX8QM_SDHC1_CLK:
+ case IMX8QM_SDHC1_DIV:
+ resource = SC_R_SDHC_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_ENET0_IPG_CLK:
+ case IMX8QM_ENET0_AHB_CLK:
+ case IMX8QM_ENET0_REF_DIV:
+ case IMX8QM_ENET0_PTP_CLK:
+ resource = SC_R_ENET_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QM_ENET1_IPG_CLK:
+ case IMX8QM_ENET1_AHB_CLK:
+ case IMX8QM_ENET1_REF_DIV:
+ case IMX8QM_ENET1_PTP_CLK:
+ resource = SC_R_ENET_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ default:
+ if (clk->id < IMX8QM_UART0_IPG_CLK ||
+ clk->id >= IMX8QM_CLK_END) {
+ printf("%s(Invalid clk ID #%lu)\n",
+ __func__, clk->id);
+ return -EINVAL;
+ }
+ return -ENOTSUPP;
+ }
+
+ ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
+ if (ret) {
+ printf("%s err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
new file mode 100644
index 0000000000..1fca36ac91
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 NXP
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/clock.h>
+#include <dt-bindings/clock/imx8qxp-clock.h>
+#include <dt-bindings/soc/imx_rsrc.h>
+#include <misc.h>
+
+#include "clk-imx8.h"
+
+#if CONFIG_IS_ENABLED(CMD_CLK)
+struct imx8_clks imx8_clk_names[] = {
+ { IMX8QXP_A35_DIV, "A35_DIV" },
+ { IMX8QXP_I2C0_CLK, "I2C0" },
+ { IMX8QXP_I2C1_CLK, "I2C1" },
+ { IMX8QXP_I2C2_CLK, "I2C2" },
+ { IMX8QXP_I2C3_CLK, "I2C3" },
+ { IMX8QXP_UART0_CLK, "UART0" },
+ { IMX8QXP_UART1_CLK, "UART1" },
+ { IMX8QXP_UART2_CLK, "UART2" },
+ { IMX8QXP_UART3_CLK, "UART3" },
+ { IMX8QXP_SDHC0_CLK, "SDHC0" },
+ { IMX8QXP_SDHC1_CLK, "SDHC1" },
+ { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
+ { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
+ { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
+ { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
+ { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
+ { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
+ { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
+ { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
+};
+
+int num_clks = ARRAY_SIZE(imx8_clk_names);
+#endif
+
+ulong imx8_clk_get_rate(struct clk *clk)
+{
+ sc_pm_clk_t pm_clk;
+ ulong rate;
+ u16 resource;
+ int ret;
+
+ debug("%s(#%lu)\n", __func__, clk->id);
+
+ switch (clk->id) {
+ case IMX8QXP_A35_DIV:
+ resource = SC_R_A35;
+ pm_clk = SC_PM_CLK_CPU;
+ break;
+ case IMX8QXP_I2C0_CLK:
+ resource = SC_R_I2C_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C1_CLK:
+ resource = SC_R_I2C_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C2_CLK:
+ resource = SC_R_I2C_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C3_CLK:
+ resource = SC_R_I2C_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_SDHC0_IPG_CLK:
+ case IMX8QXP_SDHC0_CLK:
+ case IMX8QXP_SDHC0_DIV:
+ resource = SC_R_SDHC_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_SDHC1_IPG_CLK:
+ case IMX8QXP_SDHC1_CLK:
+ case IMX8QXP_SDHC1_DIV:
+ resource = SC_R_SDHC_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART0_IPG_CLK:
+ case IMX8QXP_UART0_CLK:
+ resource = SC_R_UART_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART1_CLK:
+ resource = SC_R_UART_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART2_CLK:
+ resource = SC_R_UART_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART3_CLK:
+ resource = SC_R_UART_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_ENET0_IPG_CLK:
+ case IMX8QXP_ENET0_AHB_CLK:
+ case IMX8QXP_ENET0_REF_DIV:
+ case IMX8QXP_ENET0_PTP_CLK:
+ resource = SC_R_ENET_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_ENET1_IPG_CLK:
+ case IMX8QXP_ENET1_AHB_CLK:
+ case IMX8QXP_ENET1_REF_DIV:
+ case IMX8QXP_ENET1_PTP_CLK:
+ resource = SC_R_ENET_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ default:
+ if (clk->id < IMX8QXP_UART0_IPG_CLK ||
+ clk->id >= IMX8QXP_CLK_END) {
+ printf("%s(Invalid clk ID #%lu)\n",
+ __func__, clk->id);
+ return -EINVAL;
+ }
+ return -ENOTSUPP;
+ };
+
+ ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
+ (sc_pm_clock_rate_t *)&rate);
+ if (ret) {
+ printf("%s err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return rate;
+}
+
+ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ sc_pm_clk_t pm_clk;
+ u32 new_rate = rate;
+ u16 resource;
+ int ret;
+
+ debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
+
+ switch (clk->id) {
+ case IMX8QXP_I2C0_CLK:
+ resource = SC_R_I2C_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C1_CLK:
+ resource = SC_R_I2C_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C2_CLK:
+ resource = SC_R_I2C_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C3_CLK:
+ resource = SC_R_I2C_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART0_CLK:
+ resource = SC_R_UART_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART1_CLK:
+ resource = SC_R_UART_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART2_CLK:
+ resource = SC_R_UART_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART3_CLK:
+ resource = SC_R_UART_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_SDHC0_IPG_CLK:
+ case IMX8QXP_SDHC0_CLK:
+ case IMX8QXP_SDHC0_DIV:
+ resource = SC_R_SDHC_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_SDHC1_SEL:
+ case IMX8QXP_SDHC0_SEL:
+ return 0;
+ case IMX8QXP_SDHC1_IPG_CLK:
+ case IMX8QXP_SDHC1_CLK:
+ case IMX8QXP_SDHC1_DIV:
+ resource = SC_R_SDHC_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_ENET0_IPG_CLK:
+ case IMX8QXP_ENET0_AHB_CLK:
+ case IMX8QXP_ENET0_REF_DIV:
+ case IMX8QXP_ENET0_PTP_CLK:
+ resource = SC_R_ENET_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_ENET1_IPG_CLK:
+ case IMX8QXP_ENET1_AHB_CLK:
+ case IMX8QXP_ENET1_REF_DIV:
+ case IMX8QXP_ENET1_PTP_CLK:
+ resource = SC_R_ENET_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ default:
+ if (clk->id < IMX8QXP_UART0_IPG_CLK ||
+ clk->id >= IMX8QXP_CLK_END) {
+ printf("%s(Invalid clk ID #%lu)\n",
+ __func__, clk->id);
+ return -EINVAL;
+ }
+ return -ENOTSUPP;
+ };
+
+ ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
+ if (ret) {
+ printf("%s err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return new_rate;
+}
+
+int __imx8_clk_enable(struct clk *clk, bool enable)
+{
+ sc_pm_clk_t pm_clk;
+ u16 resource;
+ int ret;
+
+ debug("%s(#%lu)\n", __func__, clk->id);
+
+ switch (clk->id) {
+ case IMX8QXP_I2C0_CLK:
+ resource = SC_R_I2C_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C1_CLK:
+ resource = SC_R_I2C_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C2_CLK:
+ resource = SC_R_I2C_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_I2C3_CLK:
+ resource = SC_R_I2C_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART0_CLK:
+ resource = SC_R_UART_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART1_CLK:
+ resource = SC_R_UART_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART2_CLK:
+ resource = SC_R_UART_2;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_UART3_CLK:
+ resource = SC_R_UART_3;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_SDHC0_IPG_CLK:
+ case IMX8QXP_SDHC0_CLK:
+ case IMX8QXP_SDHC0_DIV:
+ resource = SC_R_SDHC_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_SDHC1_IPG_CLK:
+ case IMX8QXP_SDHC1_CLK:
+ case IMX8QXP_SDHC1_DIV:
+ resource = SC_R_SDHC_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_ENET0_IPG_CLK:
+ case IMX8QXP_ENET0_AHB_CLK:
+ case IMX8QXP_ENET0_REF_DIV:
+ case IMX8QXP_ENET0_PTP_CLK:
+ resource = SC_R_ENET_0;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ case IMX8QXP_ENET1_IPG_CLK:
+ case IMX8QXP_ENET1_AHB_CLK:
+ case IMX8QXP_ENET1_REF_DIV:
+ case IMX8QXP_ENET1_PTP_CLK:
+ resource = SC_R_ENET_1;
+ pm_clk = SC_PM_CLK_PER;
+ break;
+ default:
+ if (clk->id < IMX8QXP_UART0_IPG_CLK ||
+ clk->id >= IMX8QXP_CLK_END) {
+ printf("%s(Invalid clk ID #%lu)\n",
+ __func__, clk->id);
+ return -EINVAL;
+ }
+ return -ENOTSUPP;
+ }
+
+ ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
+ if (ret) {
+ printf("%s err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index fedc9eb7dd..112326e553 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -22,6 +22,8 @@ struct meson_clk {
struct regmap *map;
};
+static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
+ ulong rate, ulong current_rate);
static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
#define NUM_CLKS 178
@@ -36,6 +38,8 @@ static struct meson_gate gates[NUM_CLKS] = {
MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26),
MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3),
MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16),
+ MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 25),
+ MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8),
/* Peripheral Gates */
MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23),
@@ -231,6 +235,36 @@ static ulong meson_pll_get_rate(struct clk *clk, unsigned long id)
return ((parent_rate_mhz * m / n) >> od) * 1000000;
}
+static struct parm meson_pcie_pll_parm[3] = {
+ {HHI_PCIE_PLL_CNTL0, 0, 8}, /* pm */
+ {HHI_PCIE_PLL_CNTL0, 10, 5}, /* pn */
+ {HHI_PCIE_PLL_CNTL0, 16, 5}, /* pod */
+};
+
+static ulong meson_pcie_pll_get_rate(struct clk *clk)
+{
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ struct parm *pm, *pn, *pod;
+ unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
+ u16 n, m, od;
+ uint reg;
+
+ pm = &meson_pcie_pll_parm[0];
+ pn = &meson_pcie_pll_parm[1];
+ pod = &meson_pcie_pll_parm[2];
+
+ regmap_read(priv->map, pn->reg_off, &reg);
+ n = PARM_GET(pn->width, pn->shift, reg);
+
+ regmap_read(priv->map, pm->reg_off, &reg);
+ m = PARM_GET(pm->width, pm->shift, reg);
+
+ regmap_read(priv->map, pod->reg_off, &reg);
+ od = PARM_GET(pod->width, pod->shift, reg);
+
+ return ((parent_rate_mhz * m / n) / 2 / od / 2) * 1000000;
+}
+
static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
{
ulong rate;
@@ -263,6 +297,9 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
case CLKID_CLK81:
rate = meson_clk81_get_rate(clk);
break;
+ case CLKID_PCIE_PLL:
+ rate = meson_pcie_pll_get_rate(clk);
+ break;
default:
if (gates[id].reg != 0) {
/* a clock gate */
@@ -281,6 +318,71 @@ static ulong meson_clk_get_rate(struct clk *clk)
return meson_clk_get_rate_by_id(clk, clk->id);
}
+static ulong meson_pcie_pll_set_rate(struct clk *clk, ulong rate)
+{
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x20090496);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x30090496);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL1, 0x00000000);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001100);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL3, 0x10058e00);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x000100c0);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000048);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000068);
+ udelay(20);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x008100c0);
+ udelay(10);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x34090496);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x14090496);
+ udelay(10);
+ regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001000);
+ regmap_update_bits(priv->map, HHI_PCIE_PLL_CNTL0,
+ 0x1f << 16, 9 << 16);
+
+ return 100000000;
+}
+
+static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
+ ulong rate, ulong current_rate)
+{
+ if (current_rate == rate)
+ return 0;
+
+ switch (id) {
+ /* Fixed clocks */
+ case CLKID_PCIE_PLL:
+ return meson_pcie_pll_set_rate(clk, rate);
+
+ default:
+ return -ENOENT;
+ }
+
+ return -EINVAL;
+}
+
+
+static ulong meson_clk_set_rate(struct clk *clk, ulong rate)
+{
+ ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id);
+ int ret;
+
+ if (IS_ERR_VALUE(current_rate))
+ return current_rate;
+
+ debug("%s: setting rate of %ld from %ld to %ld\n",
+ __func__, clk->id, current_rate, rate);
+
+ ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+
+ debug("clock %lu has new rate %lu\n", clk->id,
+ meson_clk_get_rate_by_id(clk, clk->id));
+
+ return 0;
+}
+
static int meson_clk_probe(struct udevice *dev)
{
struct meson_clk *priv = dev_get_priv(dev);
@@ -298,6 +400,7 @@ static struct clk_ops meson_clk_ops = {
.disable = meson_clk_disable,
.enable = meson_clk_enable,
.get_rate = meson_clk_get_rate,
+ .set_rate = meson_clk_set_rate,
};
static const struct udevice_id meson_clk_ids[] = {
diff --git a/drivers/clk/mpc83xx_clk.c b/drivers/clk/mpc83xx_clk.c
index 489004190e..32d2db9eda 100644
--- a/drivers/clk/mpc83xx_clk.c
+++ b/drivers/clk/mpc83xx_clk.c
@@ -275,6 +275,12 @@ static ulong mpc83xx_clk_get_rate(struct clk *clk)
return priv->speed[clk->id];
}
+static int mpc83xx_clk_enable(struct clk *clk)
+{
+ /* MPC83xx clocks are always enabled */
+ return 0;
+}
+
int get_clocks(void)
{
/* Empty implementation to keep the prototype in common.h happy */
@@ -301,6 +307,7 @@ int get_serial_clock(void)
const struct clk_ops mpc83xx_clk_ops = {
.request = mpc83xx_clk_request,
.get_rate = mpc83xx_clk_get_rate,
+ .enable = mpc83xx_clk_enable,
};
static const struct udevice_id mpc83xx_clk_match[] = {
diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c
index 9c4e8901e8..9bf9cedaf8 100644
--- a/drivers/clk/rockchip/clk_rk3036.c
+++ b/drivers/clk/rockchip/clk_rk3036.c
@@ -9,9 +9,9 @@
#include <errno.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3036.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3036.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3036-cru.h>
#include <linux/log2.h>
diff --git a/drivers/clk/rockchip/clk_rk3128.c b/drivers/clk/rockchip/clk_rk3128.c
index 7da785abc6..efda8c830b 100644
--- a/drivers/clk/rockchip/clk_rk3128.c
+++ b/drivers/clk/rockchip/clk_rk3128.c
@@ -9,9 +9,9 @@
#include <errno.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3128.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3128.h>
+#include <asm/arch-rockchip/hardware.h>
#include <bitfield.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3128-cru.h>
diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c
index db7479a237..9bb9959c9d 100644
--- a/drivers/clk/rockchip/clk_rk3188.c
+++ b/drivers/clk/rockchip/clk_rk3188.c
@@ -12,10 +12,10 @@
#include <mapmem.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3188.h>
-#include <asm/arch/grf_rk3188.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3188.h>
+#include <asm/arch-rockchip/grf_rk3188.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dt-bindings/clock/rk3188-cru.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
diff --git a/drivers/clk/rockchip/clk_rk322x.c b/drivers/clk/rockchip/clk_rk322x.c
index 46a569c9ec..f09730c91b 100644
--- a/drivers/clk/rockchip/clk_rk322x.c
+++ b/drivers/clk/rockchip/clk_rk322x.c
@@ -9,9 +9,9 @@
#include <errno.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk322x.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk322x.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3228-cru.h>
#include <linux/log2.h>
@@ -121,10 +121,10 @@ static void rkclk_init(struct rk322x_cru *cru)
assert((aclk_div + 1) * BUS_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f);
pclk_div = BUS_ACLK_HZ / BUS_PCLK_HZ - 1;
- assert((pclk_div + 1) * BUS_PCLK_HZ == GPLL_HZ && pclk_div <= 0x7);
+ assert((pclk_div + 1) * BUS_PCLK_HZ == BUS_ACLK_HZ && pclk_div <= 0x7);
hclk_div = BUS_ACLK_HZ / BUS_HCLK_HZ - 1;
- assert((hclk_div + 1) * BUS_HCLK_HZ == GPLL_HZ && hclk_div <= 0x3);
+ assert((hclk_div + 1) * BUS_HCLK_HZ == BUS_ACLK_HZ && hclk_div <= 0x3);
rk_clrsetreg(&cru->cru_clksel_con[0],
BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
@@ -217,6 +217,7 @@ static ulong rockchip_mmc_get_clk(struct rk322x_cru *cru, uint clk_general_rate,
switch (periph) {
case HCLK_EMMC:
case SCLK_EMMC:
+ case SCLK_EMMC_SAMPLE:
con = readl(&cru->cru_clksel_con[11]);
mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
con = readl(&cru->cru_clksel_con[12]);
@@ -293,6 +294,7 @@ static ulong rockchip_mmc_set_clk(struct rk322x_cru *cru, uint clk_general_rate,
switch (periph) {
case HCLK_EMMC:
case SCLK_EMMC:
+ case SCLK_EMMC_SAMPLE:
rk_clrsetreg(&cru->cru_clksel_con[11],
EMMC_PLL_MASK,
mux << EMMC_PLL_SHIFT);
diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c
index 930c99f4d9..375d7f8acb 100644
--- a/drivers/clk/rockchip/clk_rk3288.c
+++ b/drivers/clk/rockchip/clk_rk3288.c
@@ -13,10 +13,10 @@
#include <mapmem.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3288.h>
-#include <asm/arch/grf_rk3288.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3288.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dt-bindings/clock/rk3288-cru.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c
index 106621fe7c..a89e2ecc4a 100644
--- a/drivers/clk/rockchip/clk_rk3328.c
+++ b/drivers/clk/rockchip/clk_rk3328.c
@@ -9,10 +9,10 @@
#include <dm.h>
#include <errno.h>
#include <syscon.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3328.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/grf_rk3328.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3328.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_rk3328.h>
#include <asm/io.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3328-cru.h>
diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
index 9492cc2a36..89cbae59c5 100644
--- a/drivers/clk/rockchip/clk_rk3368.c
+++ b/drivers/clk/rockchip/clk_rk3368.c
@@ -13,9 +13,9 @@
#include <mapmem.h>
#include <syscon.h>
#include <bitfield.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3368.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3368.h>
+#include <asm/arch-rockchip/hardware.h>
#include <asm/io.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3368-cru.h>
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index cab2bd9943..aa6a8ad1c9 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -13,9 +13,9 @@
#include <syscon.h>
#include <bitfield.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3399.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3399.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3399-cru.h>
@@ -912,7 +912,9 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
rate = rk3399_spi_get_clk(priv->cru, clk->id);
break;
case SCLK_UART0:
+ case SCLK_UART1:
case SCLK_UART2:
+ case SCLK_UART3:
return 24000000;
break;
case PCLK_HDMI_CTRL:
diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c
index 914e2f4b21..3ebb007fab 100644
--- a/drivers/clk/rockchip/clk_rv1108.c
+++ b/drivers/clk/rockchip/clk_rv1108.c
@@ -11,9 +11,9 @@
#include <errno.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rv1108.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rv1108.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rv1108-cru.h>
diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
index 81fc9f8fda..644881b948 100644
--- a/drivers/clk/sifive/Kconfig
+++ b/drivers/clk/sifive/Kconfig
@@ -17,3 +17,10 @@ config CLK_SIFIVE_FU540_PRCI
Supports the Power Reset Clock interface (PRCI) IP block found in
FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
enable this driver.
+
+config CLK_SIFIVE_GEMGXL_MGMT
+ bool "GEMGXL management for SiFive FU540 SoCs"
+ depends on CLK_SIFIVE
+ help
+ Supports the GEMGXL management IP block found in FU540 SoCs to
+ control GEM TX clock operation mode for 10/100/1000 Mbps.
diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
index 1155e07e37..f8263e79b7 100644
--- a/drivers/clk/sifive/Makefile
+++ b/drivers/clk/sifive/Makefile
@@ -3,3 +3,5 @@
obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
+
+obj-$(CONFIG_CLK_SIFIVE_GEMGXL_MGMT) += gemgxl-mgmt.o
diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
index e1b5f8e6a9..2d47ebc6b1 100644
--- a/drivers/clk/sifive/fu540-prci.c
+++ b/drivers/clk/sifive/fu540-prci.c
@@ -28,10 +28,10 @@
* - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
*/
+#include <common.h>
#include <asm/io.h>
#include <clk-uclass.h>
#include <clk.h>
-#include <common.h>
#include <div64.h>
#include <dm.h>
#include <errno.h>
diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c
new file mode 100644
index 0000000000..eb37416b5e
--- /dev/null
+++ b/drivers/clk/sifive/gemgxl-mgmt.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/io.h>
+
+struct gemgxl_mgmt_regs {
+ __u32 tx_clk_sel;
+};
+
+struct gemgxl_mgmt_platdata {
+ struct gemgxl_mgmt_regs *regs;
+};
+
+static int gemgxl_mgmt_ofdata_to_platdata(struct udevice *dev)
+{
+ struct gemgxl_mgmt_platdata *plat = dev_get_platdata(dev);
+
+ plat->regs = (struct gemgxl_mgmt_regs *)dev_read_addr(dev);
+
+ return 0;
+}
+
+static ulong gemgxl_mgmt_set_rate(struct clk *clk, ulong rate)
+{
+ struct gemgxl_mgmt_platdata *plat = dev_get_platdata(clk->dev);
+
+ /*
+ * GEMGXL TX clock operation mode:
+ *
+ * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
+ * and output clock on GMII output signal GTX_CLK
+ * 1 = MII mode. Use MII input signal TX_CLK in TX logic
+ */
+ writel(rate != 125000000, &plat->regs->tx_clk_sel);
+
+ return 0;
+}
+
+const struct clk_ops gemgxl_mgmt_ops = {
+ .set_rate = gemgxl_mgmt_set_rate,
+};
+
+static const struct udevice_id gemgxl_mgmt_match[] = {
+ { .compatible = "sifive,cadencegemgxlmgmt0", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sifive_gemgxl_mgmt) = {
+ .name = "sifive-gemgxl-mgmt",
+ .id = UCLASS_CLK,
+ .of_match = gemgxl_mgmt_match,
+ .ofdata_to_platdata = gemgxl_mgmt_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct gemgxl_mgmt_platdata),
+ .ops = &gemgxl_mgmt_ops,
+};
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 785f5c3acf..c72c6e2673 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -39,7 +39,7 @@ int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
return 0;
}
-int ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
+u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
{
assert(ofnode_valid(node));
ofnode_read_u32(node, propname, &def);
@@ -251,7 +251,7 @@ int ofnode_read_size(ofnode node, const char *propname)
return -EINVAL;
}
-fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
+fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
{
int na, ns;
@@ -260,7 +260,7 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
uint flags;
prop_val = of_get_address(ofnode_to_np(node), index,
- NULL, &flags);
+ (u64 *)size, &flags);
if (!prop_val)
return FDT_ADDR_T_NONE;
@@ -277,12 +277,19 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
return fdtdec_get_addr_size_fixed(gd->fdt_blob,
ofnode_to_offset(node), "reg",
- index, na, ns, NULL, true);
+ index, na, ns, size, true);
}
return FDT_ADDR_T_NONE;
}
+fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
+{
+ fdt_size_t size;
+
+ return ofnode_get_addr_size_index(node, index, &size);
+}
+
fdt_addr_t ofnode_get_addr(ofnode node)
{
return ofnode_get_addr_index(node, 0);
@@ -546,7 +553,7 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
ns = of_n_size_cells(np);
*sizep = of_read_number(prop + na, ns);
- if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0)
+ if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
return of_translate_address(np, prop);
else
return of_read_number(prop, na);
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 8fa096648e..aa5ca4087a 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -342,7 +342,7 @@ int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
{
int ret;
- ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
+ ret = dm_scan_fdt(blob, pre_reloc_only);
if (ret) {
debug("dm_scan_fdt() failed: %d\n", ret);
return ret;
diff --git a/drivers/ddr/altera/Kconfig b/drivers/ddr/altera/Kconfig
index 8f60b56eb8..2b1c1be3b5 100644
--- a/drivers/ddr/altera/Kconfig
+++ b/drivers/ddr/altera/Kconfig
@@ -1,7 +1,8 @@
-config ALTERA_SDRAM
- bool "SoCFPGA DDR SDRAM driver"
- depends on TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10
- select RAM if TARGET_SOCFPGA_GEN5
- select SPL_RAM if TARGET_SOCFPGA_GEN5
+config SPL_ALTERA_SDRAM
+ bool "SoCFPGA DDR SDRAM driver in SPL"
+ depends on SPL
+ depends on TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10 || TARGET_SOCFPGA_STRATIX10
+ select RAM if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_STRATIX10
+ select SPL_RAM if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_STRATIX10
help
Enable DDR SDRAM controller for the SoCFPGA devices.
diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
index 3615b617ec..341ac0d73b 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -6,7 +6,7 @@
# (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
# Copyright (C) 2014 Altera Corporation <www.altera.com>
-ifdef CONFIG_ALTERA_SDRAM
+ifdef CONFIG_$(SPL_)ALTERA_SDRAM
obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o
obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o
obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_s10.o
diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c
index e4d4a02ca2..56cbbac9fe 100644
--- a/drivers/ddr/altera/sdram_s10.c
+++ b/drivers/ddr/altera/sdram_s10.c
@@ -5,17 +5,31 @@
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <div64.h>
#include <fdtdec.h>
-#include <asm/io.h>
+#include <ram.h>
+#include <reset.h>
+#include "sdram_s10.h"
#include <wait_bit.h>
#include <asm/arch/firewall_s10.h>
-#include <asm/arch/sdram_s10.h>
#include <asm/arch/system_manager.h>
#include <asm/arch/reset_manager.h>
+#include <asm/io.h>
#include <linux/sizes.h>
+struct altera_sdram_priv {
+ struct ram_info info;
+ struct reset_ctl_bulk resets;
+};
+
+struct altera_sdram_platdata {
+ void __iomem *hmc;
+ void __iomem *ddr_sch;
+ void __iomem *iomhc;
+};
+
DECLARE_GLOBAL_DATA_PTR;
static const struct socfpga_system_manager *sysmgr_regs =
@@ -51,25 +65,26 @@ u32 ddr_config[] = {
DDR_CONFIG(1, 4, 10, 17),
};
-static u32 hmc_readl(u32 reg)
+static u32 hmc_readl(struct altera_sdram_platdata *plat, u32 reg)
{
- return readl(((void __iomem *)SOCFPGA_HMC_MMR_IO48_ADDRESS + (reg)));
+ return readl(plat->iomhc + reg);
}
-static u32 hmc_ecc_readl(u32 reg)
+static u32 hmc_ecc_readl(struct altera_sdram_platdata *plat, u32 reg)
{
- return readl((void __iomem *)SOCFPGA_SDR_ADDRESS + (reg));
+ return readl(plat->hmc + reg);
}
-static u32 hmc_ecc_writel(u32 data, u32 reg)
+static u32 hmc_ecc_writel(struct altera_sdram_platdata *plat,
+ u32 data, u32 reg)
{
- return writel(data, (void __iomem *)SOCFPGA_SDR_ADDRESS + (reg));
+ return writel(data, plat->hmc + reg);
}
-static u32 ddr_sch_writel(u32 data, u32 reg)
+static u32 ddr_sch_writel(struct altera_sdram_platdata *plat, u32 data,
+ u32 reg)
{
- return writel(data,
- (void __iomem *)SOCFPGA_SDR_SCHEDULER_ADDRESS + (reg));
+ return writel(data, plat->ddr_sch + reg);
}
int match_ddr_conf(u32 ddr_conf)
@@ -83,37 +98,38 @@ int match_ddr_conf(u32 ddr_conf)
return 0;
}
-static int emif_clear(void)
+static int emif_clear(struct altera_sdram_platdata *plat)
{
- hmc_ecc_writel(0, RSTHANDSHAKECTRL);
+ hmc_ecc_writel(plat, 0, RSTHANDSHAKECTRL);
- return wait_for_bit_le32((const void *)(SOCFPGA_SDR_ADDRESS +
+ return wait_for_bit_le32((const void *)(plat->hmc +
RSTHANDSHAKESTAT),
DDR_HMC_RSTHANDSHAKE_MASK,
false, 1000, false);
}
-static int emif_reset(void)
+static int emif_reset(struct altera_sdram_platdata *plat)
{
u32 c2s, s2c, ret;
- c2s = hmc_ecc_readl(RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK;
- s2c = hmc_ecc_readl(RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK;
+ c2s = hmc_ecc_readl(plat, RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK;
+ s2c = hmc_ecc_readl(plat, RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK;
debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n",
- c2s, s2c, hmc_readl(NIOSRESERVED0), hmc_readl(NIOSRESERVED1),
- hmc_readl(NIOSRESERVED2), hmc_readl(DRAMSTS));
+ c2s, s2c, hmc_readl(plat, NIOSRESERVED0),
+ hmc_readl(plat, NIOSRESERVED1), hmc_readl(plat, NIOSRESERVED2),
+ hmc_readl(plat, DRAMSTS));
- if (s2c && emif_clear()) {
+ if (s2c && emif_clear(plat)) {
printf("DDR: emif_clear() failed\n");
return -1;
}
debug("DDR: Triggerring emif reset\n");
- hmc_ecc_writel(DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL);
+ hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL);
/* if seq2core[3] = 0, we are good */
- ret = wait_for_bit_le32((const void *)(SOCFPGA_SDR_ADDRESS +
+ ret = wait_for_bit_le32((const void *)(plat->hmc +
RSTHANDSHAKESTAT),
DDR_HMC_SEQ2CORE_INT_RESP_MASK,
false, 1000, false);
@@ -122,7 +138,7 @@ static int emif_reset(void)
return ret;
}
- ret = emif_clear();
+ ret = emif_clear(plat);
if (ret) {
printf("DDR: emif_clear() failed\n");
return ret;
@@ -241,12 +257,36 @@ static void sdram_size_check(bd_t *bd)
}
/**
+ * sdram_calculate_size() - Calculate SDRAM size
+ *
+ * Calculate SDRAM device size based on SDRAM controller parameters.
+ * Size is specified in bytes.
+ */
+static phys_size_t sdram_calculate_size(struct altera_sdram_platdata *plat)
+{
+ u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
+
+ phys_size_t size = 1 << (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
+ DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
+ DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
+ DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
+ DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw));
+
+ size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) &
+ DDR_HMC_DDRIOCTRL_IOSIZE_MSK));
+
+ return size;
+}
+
+/**
* sdram_mmr_init_full() - Function to initialize SDRAM MMR
*
* Initialize the SDRAM MMR.
*/
-int sdram_mmr_init_full(unsigned int unused)
+static int sdram_mmr_init_full(struct udevice *dev)
{
+ struct altera_sdram_platdata *plat = dev->platdata;
+ struct altera_sdram_priv *priv = dev_get_priv(dev);
u32 update_value, io48_value, ddrioctl;
u32 i;
int ret;
@@ -303,19 +343,16 @@ int sdram_mmr_init_full(unsigned int unused)
return -1;
}
- /* release DDR scheduler from reset */
- socfpga_per_reset(SOCFPGA_RESET(SDR), 0);
-
/* Try 3 times to do a calibration */
for (i = 0; i < 3; i++) {
- ret = wait_for_bit_le32((const void *)(SOCFPGA_SDR_ADDRESS +
+ ret = wait_for_bit_le32((const void *)(plat->hmc +
DDRCALSTAT),
DDR_HMC_DDRCALSTAT_CAL_MSK, true, 1000,
false);
if (!ret)
break;
- emif_reset();
+ emif_reset(plat);
}
if (ret) {
@@ -324,16 +361,16 @@ int sdram_mmr_init_full(unsigned int unused)
}
debug("DDR: Calibration success\n");
- u32 ctrlcfg0 = hmc_readl(CTRLCFG0);
- u32 ctrlcfg1 = hmc_readl(CTRLCFG1);
- u32 dramaddrw = hmc_readl(DRAMADDRW);
- u32 dramtim0 = hmc_readl(DRAMTIMING0);
- u32 caltim0 = hmc_readl(CALTIMING0);
- u32 caltim1 = hmc_readl(CALTIMING1);
- u32 caltim2 = hmc_readl(CALTIMING2);
- u32 caltim3 = hmc_readl(CALTIMING3);
- u32 caltim4 = hmc_readl(CALTIMING4);
- u32 caltim9 = hmc_readl(CALTIMING9);
+ u32 ctrlcfg0 = hmc_readl(plat, CTRLCFG0);
+ u32 ctrlcfg1 = hmc_readl(plat, CTRLCFG1);
+ u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
+ u32 dramtim0 = hmc_readl(plat, DRAMTIMING0);
+ u32 caltim0 = hmc_readl(plat, CALTIMING0);
+ u32 caltim1 = hmc_readl(plat, CALTIMING1);
+ u32 caltim2 = hmc_readl(plat, CALTIMING2);
+ u32 caltim3 = hmc_readl(plat, CALTIMING3);
+ u32 caltim4 = hmc_readl(plat, CALTIMING4);
+ u32 caltim9 = hmc_readl(plat, CALTIMING9);
/*
* Configure the DDR IO size [0xFFCFB008]
@@ -349,12 +386,12 @@ int sdram_mmr_init_full(unsigned int unused)
* bit[9:6] = Minor Release #
* bit[14:10] = Major Release #
*/
- update_value = hmc_readl(NIOSRESERVED0);
- hmc_ecc_writel(((update_value & 0xFF) >> 5), DDRIOCTRL);
- ddrioctl = hmc_ecc_readl(DDRIOCTRL);
+ update_value = hmc_readl(plat, NIOSRESERVED0);
+ hmc_ecc_writel(plat, ((update_value & 0xFF) >> 5), DDRIOCTRL);
+ ddrioctl = hmc_ecc_readl(plat, DDRIOCTRL);
/* enable HPS interface to HMC */
- hmc_ecc_writel(DDR_HMC_HPSINTFCSEL_ENABLE_MASK, HPSINTFCSEL);
+ hmc_ecc_writel(plat, DDR_HMC_HPSINTFCSEL_ENABLE_MASK, HPSINTFCSEL);
/* Set the DDR Configuration */
io48_value = DDR_CONFIG(CTRLCFG1_CFG_ADDR_ORDER(ctrlcfg1),
@@ -365,10 +402,10 @@ int sdram_mmr_init_full(unsigned int unused)
update_value = match_ddr_conf(io48_value);
if (update_value)
- ddr_sch_writel(update_value, DDR_SCH_DDRCONF);
+ ddr_sch_writel(plat, update_value, DDR_SCH_DDRCONF);
/* Configure HMC dramaddrw */
- hmc_ecc_writel(hmc_readl(DRAMADDRW), DRAMADDRWIDTH);
+ hmc_ecc_writel(plat, hmc_readl(plat, DRAMADDRW), DRAMADDRWIDTH);
/*
* Configure DDR timing
@@ -392,7 +429,7 @@ int sdram_mmr_init_full(unsigned int unused)
CALTIMING0_CFG_ACT_TO_RDWR(caltim0) +
CALTIMING4_CFG_PCH_TO_VALID(caltim4));
- ddr_sch_writel(((CALTIMING0_CFG_ACT_TO_ACT(caltim0) <<
+ ddr_sch_writel(plat, ((CALTIMING0_CFG_ACT_TO_ACT(caltim0) <<
DDR_SCH_DDRTIMING_ACTTOACT_OFF) |
(update_value << DDR_SCH_DDRTIMING_RDTOMISS_OFF) |
(io48_value << DDR_SCH_DDRTIMING_WRTOMISS_OFF) |
@@ -406,12 +443,12 @@ int sdram_mmr_init_full(unsigned int unused)
DDR_SCH_DDRTIMING);
/* Configure DDR mode [precharge = 0] */
- ddr_sch_writel(((ddrioctl ? 0 : 1) <<
+ ddr_sch_writel(plat, ((ddrioctl ? 0 : 1) <<
DDR_SCH_DDRMOD_BWRATIOEXTENDED_OFF),
DDR_SCH_DDRMODE);
/* Configure the read latency */
- ddr_sch_writel((DRAMTIMING0_CFG_TCL(dramtim0) >> 1) +
+ ddr_sch_writel(plat, (DRAMTIMING0_CFG_TCL(dramtim0) >> 1) +
DDR_READ_LATENCY_DELAY,
DDR_SCH_READ_LATENCY);
@@ -419,7 +456,7 @@ int sdram_mmr_init_full(unsigned int unused)
* Configuring timing values concerning activate commands
* [FAWBANK alway 1 because always 4 bank DDR]
*/
- ddr_sch_writel(((CALTIMING0_CFG_ACT_TO_ACT_DB(caltim0) <<
+ ddr_sch_writel(plat, ((CALTIMING0_CFG_ACT_TO_ACT_DB(caltim0) <<
DDR_SCH_ACTIVATE_RRD_OFF) |
(CALTIMING9_CFG_4_ACT_TO_ACT(caltim9) <<
DDR_SCH_ACTIVATE_FAW_OFF) |
@@ -431,7 +468,7 @@ int sdram_mmr_init_full(unsigned int unused)
* Configuring timing values concerning device to device data bus
* ownership change
*/
- ddr_sch_writel(((CALTIMING1_CFG_RD_TO_RD_DC(caltim1) <<
+ ddr_sch_writel(plat, ((CALTIMING1_CFG_RD_TO_RD_DC(caltim1) <<
DDR_SCH_DEVTODEV_BUSRDTORD_OFF) |
(CALTIMING1_CFG_RD_TO_WR_DC(caltim1) <<
DDR_SCH_DEVTODEV_BUSRDTOWR_OFF) |
@@ -440,7 +477,7 @@ int sdram_mmr_init_full(unsigned int unused)
DDR_SCH_DEVTODEV);
/* assigning the SDRAM size */
- unsigned long long size = sdram_calculate_size();
+ unsigned long long size = sdram_calculate_size(plat);
/* If the size is invalid, use default Config size */
if (size <= 0)
hw_size = PHYS_SDRAM_1_SIZE;
@@ -462,18 +499,17 @@ int sdram_mmr_init_full(unsigned int unused)
/* Enable or disable the SDRAM ECC */
if (CTRLCFG1_CFG_CTRL_EN_ECC(ctrlcfg1)) {
- setbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL1,
+ setbits_le32(plat->hmc + ECCCTRL1,
(DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK |
DDR_HMC_ECCCTL_CNT_RST_SET_MSK |
DDR_HMC_ECCCTL_ECC_EN_SET_MSK));
- clrbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL1,
+ clrbits_le32(plat->hmc + ECCCTRL1,
(DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK |
DDR_HMC_ECCCTL_CNT_RST_SET_MSK));
- setbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL2,
+ setbits_le32(plat->hmc + ECCCTRL2,
(DDR_HMC_ECCCTL2_RMW_EN_SET_MSK |
DDR_HMC_ECCCTL2_AWB_EN_SET_MSK));
- writel(DDR_HMC_ERRINTEN_INTMASK,
- SOCFPGA_SDR_ADDRESS + ERRINTENS);
+ hmc_ecc_writel(plat, DDR_HMC_ERRINTEN_INTMASK, ERRINTENS);
/* Enable non-secure writes to HMC Adapter for SDRAM ECC */
writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR);
@@ -482,39 +518,98 @@ int sdram_mmr_init_full(unsigned int unused)
if (!cpu_has_been_warmreset())
sdram_init_ecc_bits(&bd);
} else {
- clrbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL1,
+ clrbits_le32(plat->hmc + ECCCTRL1,
(DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK |
DDR_HMC_ECCCTL_CNT_RST_SET_MSK |
DDR_HMC_ECCCTL_ECC_EN_SET_MSK));
- clrbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL2,
+ clrbits_le32(plat->hmc + ECCCTRL2,
(DDR_HMC_ECCCTL2_RMW_EN_SET_MSK |
DDR_HMC_ECCCTL2_AWB_EN_SET_MSK));
}
sdram_size_check(&bd);
+ priv->info.base = bd.bi_dram[0].start;
+ priv->info.size = gd->ram_size;
+
debug("DDR: HMC init success\n");
return 0;
}
-/**
- * sdram_calculate_size() - Calculate SDRAM size
- *
- * Calculate SDRAM device size based on SDRAM controller parameters.
- * Size is specified in bytes.
- */
-phys_size_t sdram_calculate_size(void)
+static int altera_sdram_ofdata_to_platdata(struct udevice *dev)
{
- u32 dramaddrw = hmc_readl(DRAMADDRW);
+ struct altera_sdram_platdata *plat = dev->platdata;
+ fdt_addr_t addr;
- phys_size_t size = 1 << (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
- DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
- DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
- DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
- DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw));
+ addr = dev_read_addr_index(dev, 0);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ plat->ddr_sch = (void __iomem *)addr;
- size *= (2 << (hmc_ecc_readl(DDRIOCTRL) &
- DDR_HMC_DDRIOCTRL_IOSIZE_MSK));
+ addr = dev_read_addr_index(dev, 1);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ plat->iomhc = (void __iomem *)addr;
- return size;
+ addr = dev_read_addr_index(dev, 2);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ plat->hmc = (void __iomem *)addr;
+
+ return 0;
}
+
+static int altera_sdram_probe(struct udevice *dev)
+{
+ int ret;
+ struct altera_sdram_priv *priv = dev_get_priv(dev);
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret) {
+ dev_err(dev, "Can't get reset: %d\n", ret);
+ return -ENODEV;
+ }
+ reset_deassert_bulk(&priv->resets);
+
+ if (sdram_mmr_init_full(dev) != 0) {
+ puts("SDRAM init failed.\n");
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ reset_release_bulk(&priv->resets);
+ return -ENODEV;
+}
+
+static int altera_sdram_get_info(struct udevice *dev,
+ struct ram_info *info)
+{
+ struct altera_sdram_priv *priv = dev_get_priv(dev);
+
+ info->base = priv->info.base;
+ info->size = priv->info.size;
+
+ return 0;
+}
+
+static struct ram_ops altera_sdram_ops = {
+ .get_info = altera_sdram_get_info,
+};
+
+static const struct udevice_id altera_sdram_ids[] = {
+ { .compatible = "altr,sdr-ctl-s10" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(altera_sdram) = {
+ .name = "altr_sdr_ctl",
+ .id = UCLASS_RAM,
+ .of_match = altera_sdram_ids,
+ .ops = &altera_sdram_ops,
+ .ofdata_to_platdata = altera_sdram_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct altera_sdram_platdata),
+ .probe = altera_sdram_probe,
+ .priv_auto_alloc_size = sizeof(struct altera_sdram_priv),
+};
diff --git a/drivers/ddr/altera/sdram_s10.h b/drivers/ddr/altera/sdram_s10.h
new file mode 100644
index 0000000000..096c06cba2
--- /dev/null
+++ b/drivers/ddr/altera/sdram_s10.h
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef _SDRAM_S10_H_
+#define _SDRAM_S10_H_
+
+#define DDR_TWR 15
+#define DDR_READ_LATENCY_DELAY 40
+#define DDR_ACTIVATE_FAWBANK 0x1
+
+/* ECC HMC registers */
+#define DDRIOCTRL 0x8
+#define DDRCALSTAT 0xc
+#define DRAMADDRWIDTH 0xe0
+#define ECCCTRL1 0x100
+#define ECCCTRL2 0x104
+#define ERRINTEN 0x110
+#define ERRINTENS 0x114
+#define INTMODE 0x11c
+#define INTSTAT 0x120
+#define AUTOWB_CORRADDR 0x138
+#define ECC_REG2WRECCDATABUS 0x144
+#define ECC_DIAGON 0x150
+#define ECC_DECSTAT 0x154
+#define HPSINTFCSEL 0x210
+#define RSTHANDSHAKECTRL 0x214
+#define RSTHANDSHAKESTAT 0x218
+
+#define DDR_HMC_DDRIOCTRL_IOSIZE_MSK 0x00000003
+#define DDR_HMC_DDRCALSTAT_CAL_MSK BIT(0)
+#define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK BIT(16)
+#define DDR_HMC_ECCCTL_CNT_RST_SET_MSK BIT(8)
+#define DDR_HMC_ECCCTL_ECC_EN_SET_MSK BIT(0)
+#define DDR_HMC_ECCCTL2_RMW_EN_SET_MSK BIT(8)
+#define DDR_HMC_ECCCTL2_AWB_EN_SET_MSK BIT(0)
+#define DDR_HMC_ECC_DIAGON_ECCDIAGON_EN_SET_MSK BIT(16)
+#define DDR_HMC_ECC_DIAGON_WRDIAGON_EN_SET_MSK BIT(0)
+#define DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK BIT(0)
+#define DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK BIT(1)
+#define DDR_HMC_INTSTAT_SERRPENA_SET_MSK BIT(0)
+#define DDR_HMC_INTSTAT_DERRPENA_SET_MSK BIT(1)
+#define DDR_HMC_INTSTAT_ADDRMTCFLG_SET_MSK BIT(16)
+#define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0)
+#define DDR_HMC_RSTHANDSHAKE_MASK 0x000000ff
+#define DDR_HMC_CORE2SEQ_INT_REQ 0xF
+#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3)
+#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f
+
+#define DDR_HMC_ERRINTEN_INTMASK \
+ (DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK | \
+ DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK)
+
+/* NOC DDR scheduler */
+#define DDR_SCH_ID_COREID 0
+#define DDR_SCH_ID_REVID 0x4
+#define DDR_SCH_DDRCONF 0x8
+#define DDR_SCH_DDRTIMING 0xc
+#define DDR_SCH_DDRMODE 0x10
+#define DDR_SCH_READ_LATENCY 0x14
+#define DDR_SCH_ACTIVATE 0x38
+#define DDR_SCH_DEVTODEV 0x3c
+#define DDR_SCH_DDR4TIMING 0x40
+
+#define DDR_SCH_DDRTIMING_ACTTOACT_OFF 0
+#define DDR_SCH_DDRTIMING_RDTOMISS_OFF 6
+#define DDR_SCH_DDRTIMING_WRTOMISS_OFF 12
+#define DDR_SCH_DDRTIMING_BURSTLEN_OFF 18
+#define DDR_SCH_DDRTIMING_RDTOWR_OFF 21
+#define DDR_SCH_DDRTIMING_WRTORD_OFF 26
+#define DDR_SCH_DDRTIMING_BWRATIO_OFF 31
+#define DDR_SCH_DDRMOD_BWRATIOEXTENDED_OFF 1
+#define DDR_SCH_ACTIVATE_RRD_OFF 0
+#define DDR_SCH_ACTIVATE_FAW_OFF 4
+#define DDR_SCH_ACTIVATE_FAWBANK_OFF 10
+#define DDR_SCH_DEVTODEV_BUSRDTORD_OFF 0
+#define DDR_SCH_DEVTODEV_BUSRDTOWR_OFF 2
+#define DDR_SCH_DEVTODEV_BUSWRTORD_OFF 4
+
+/* HMC MMR IO48 registers */
+#define CTRLCFG0 0x28
+#define CTRLCFG1 0x2c
+#define DRAMTIMING0 0x50
+#define CALTIMING0 0x7c
+#define CALTIMING1 0x80
+#define CALTIMING2 0x84
+#define CALTIMING3 0x88
+#define CALTIMING4 0x8c
+#define CALTIMING9 0xa0
+#define DRAMADDRW 0xa8
+#define DRAMSTS 0xec
+#define NIOSRESERVED0 0x110
+#define NIOSRESERVED1 0x114
+#define NIOSRESERVED2 0x118
+
+#define DRAMADDRW_CFG_COL_ADDR_WIDTH(x) \
+ (((x) >> 0) & 0x1F)
+#define DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) \
+ (((x) >> 5) & 0x1F)
+#define DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) \
+ (((x) >> 10) & 0xF)
+#define DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(x) \
+ (((x) >> 14) & 0x3)
+#define DRAMADDRW_CFG_CS_ADDR_WIDTH(x) \
+ (((x) >> 16) & 0x7)
+
+#define CTRLCFG0_CFG_MEMTYPE(x) \
+ (((x) >> 0) & 0xF)
+#define CTRLCFG0_CFG_DIMM_TYPE(x) \
+ (((x) >> 4) & 0x7)
+#define CTRLCFG0_CFG_AC_POS(x) \
+ (((x) >> 7) & 0x3)
+#define CTRLCFG0_CFG_CTRL_BURST_LEN(x) \
+ (((x) >> 9) & 0x1F)
+
+#define CTRLCFG1_CFG_DBC3_BURST_LEN(x) \
+ (((x) >> 0) & 0x1F)
+#define CTRLCFG1_CFG_ADDR_ORDER(x) \
+ (((x) >> 5) & 0x3)
+#define CTRLCFG1_CFG_CTRL_EN_ECC(x) \
+ (((x) >> 7) & 0x1)
+
+#define DRAMTIMING0_CFG_TCL(x) \
+ (((x) >> 0) & 0x7F)
+
+#define CALTIMING0_CFG_ACT_TO_RDWR(x) \
+ (((x) >> 0) & 0x3F)
+#define CALTIMING0_CFG_ACT_TO_PCH(x) \
+ (((x) >> 6) & 0x3F)
+#define CALTIMING0_CFG_ACT_TO_ACT(x) \
+ (((x) >> 12) & 0x3F)
+#define CALTIMING0_CFG_ACT_TO_ACT_DB(x) \
+ (((x) >> 18) & 0x3F)
+
+#define CALTIMING1_CFG_RD_TO_RD(x) \
+ (((x) >> 0) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_RD_DC(x) \
+ (((x) >> 6) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_RD_DB(x) \
+ (((x) >> 12) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_WR(x) \
+ (((x) >> 18) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_WR_DC(x) \
+ (((x) >> 24) & 0x3F)
+
+#define CALTIMING2_CFG_RD_TO_WR_DB(x) \
+ (((x) >> 0) & 0x3F)
+#define CALTIMING2_CFG_RD_TO_WR_PCH(x) \
+ (((x) >> 6) & 0x3F)
+#define CALTIMING2_CFG_RD_AP_TO_VALID(x) \
+ (((x) >> 12) & 0x3F)
+#define CALTIMING2_CFG_WR_TO_WR(x) \
+ (((x) >> 18) & 0x3F)
+#define CALTIMING2_CFG_WR_TO_WR_DC(x) \
+ (((x) >> 24) & 0x3F)
+
+#define CALTIMING3_CFG_WR_TO_WR_DB(x) \
+ (((x) >> 0) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_RD(x) \
+ (((x) >> 6) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_RD_DC(x) \
+ (((x) >> 12) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_RD_DB(x) \
+ (((x) >> 18) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_PCH(x) \
+ (((x) >> 24) & 0x3F)
+
+#define CALTIMING4_CFG_WR_AP_TO_VALID(x) \
+ (((x) >> 0) & 0x3F)
+#define CALTIMING4_CFG_PCH_TO_VALID(x) \
+ (((x) >> 6) & 0x3F)
+#define CALTIMING4_CFG_PCH_ALL_TO_VALID(x) \
+ (((x) >> 12) & 0x3F)
+#define CALTIMING4_CFG_ARF_TO_VALID(x) \
+ (((x) >> 18) & 0xFF)
+#define CALTIMING4_CFG_PDN_TO_VALID(x) \
+ (((x) >> 26) & 0x3F)
+
+#define CALTIMING9_CFG_4_ACT_TO_ACT(x) \
+ (((x) >> 0) & 0xFF)
+
+/* Firewall DDR scheduler MPFE */
+#define FW_HMC_ADAPTOR_REG_ADDR 0xf8020004
+#define FW_HMC_ADAPTOR_MPU_MASK BIT(0)
+
+#endif /* _SDRAM_S10_H_ */
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index 6d018fde2b..e1f69a1d25 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -23,8 +23,12 @@
* 0x80_8000_0000 ~ 0xff_ffff_ffff
*/
#ifndef CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY
+#ifdef CONFIG_MPC83xx
+#define CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY CONFIG_SYS_SDRAM_BASE
+#else
#define CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY CONFIG_SYS_DDR_SDRAM_BASE
#endif
+#endif
#ifdef CONFIG_PPC
#include <asm/fsl_law.h>
diff --git a/drivers/ddr/imx/imx8m/Kconfig b/drivers/ddr/imx/imx8m/Kconfig
index 71f466f5ec..a83b0f43d7 100644
--- a/drivers/ddr/imx/imx8m/Kconfig
+++ b/drivers/ddr/imx/imx8m/Kconfig
@@ -1,3 +1,6 @@
+menu "i.MX8M DDR controllers"
+ depends on ARCH_IMX8M
+
config IMX8M_DRAM
bool "imx8m dram"
@@ -20,3 +23,4 @@ config SAVED_DRAM_TIMING_BASE
info into memory for low power use. OCRAM_S is used for this
purpose on i.MX8MM.
default 0x180000
+endmenu
diff --git a/drivers/dma/apbh_dma.c b/drivers/dma/apbh_dma.c
index 017cc89a89..ac589feeb7 100644
--- a/drivers/dma/apbh_dma.c
+++ b/drivers/dma/apbh_dma.c
@@ -81,7 +81,7 @@ static int mxs_dma_read_semaphore(int channel)
return tmp;
}
-#ifndef CONFIG_SYS_DCACHE_OFF
+#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
void mxs_dma_flush_desc(struct mxs_dma_desc *desc)
{
uint32_t addr;
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index f78a01aa8f..a5fc7809bc 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -575,14 +575,6 @@ static int udma_get_tchan(struct udma_chan *uc)
pr_debug("chan%d: got tchan%d\n", uc->id, uc->tchan->id);
- if (udma_is_chan_running(uc)) {
- dev_warn(ud->dev, "chan%d: tchan%d is running!\n", uc->id,
- uc->tchan->id);
- udma_stop(uc);
- if (udma_is_chan_running(uc))
- dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
- }
-
return 0;
}
@@ -602,14 +594,6 @@ static int udma_get_rchan(struct udma_chan *uc)
pr_debug("chan%d: got rchan%d\n", uc->id, uc->rchan->id);
- if (udma_is_chan_running(uc)) {
- dev_warn(ud->dev, "chan%d: rchan%d is running!\n", uc->id,
- uc->rchan->id);
- udma_stop(uc);
- if (udma_is_chan_running(uc))
- dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
- }
-
return 0;
}
@@ -652,14 +636,6 @@ static int udma_get_chan_pair(struct udma_chan *uc)
pr_debug("chan%d: got t/rchan%d pair\n", uc->id, chan_id);
- if (udma_is_chan_running(uc)) {
- dev_warn(ud->dev, "chan%d: t/rchan%d pair is running!\n",
- uc->id, chan_id);
- udma_stop(uc);
- if (udma_is_chan_running(uc))
- dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
- }
-
return 0;
}
@@ -1071,6 +1047,15 @@ static int udma_alloc_chan_resources(struct udma_chan *uc)
}
}
+ if (udma_is_chan_running(uc)) {
+ dev_warn(ud->dev, "chan%d: is running!\n", uc->id);
+ udma_stop(uc);
+ if (udma_is_chan_running(uc)) {
+ dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
+ goto err_free_res;
+ }
+ }
+
/* PSI-L pairing */
ret = udma_navss_psil_pair(ud, uc->src_thread, uc->dst_thread);
if (ret) {
@@ -1492,7 +1477,7 @@ static int udma_send(struct dma *dma, void *src, size_t len, void *metadata)
u32 tc_ring_id;
int ret;
- if (!metadata)
+ if (metadata)
packet_data = *((struct ti_udma_drv_packet_data *)metadata);
if (dma->id >= (ud->rchan_cnt + ud->tchan_cnt)) {
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 1196ce0712..303aa6a631 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -158,7 +158,7 @@ static inline int ti_sci_get_response(struct ti_sci_info *info,
int ret;
/* Receive the response */
- ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_ms);
+ ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_ms * 1000);
if (ret) {
dev_err(info->dev, "%s: Message receive failed. ret = %d\n",
__func__, ret);
@@ -257,7 +257,8 @@ static int ti_sci_cmd_get_revision(struct ti_sci_handle *handle)
info = handle_to_ti_sci_info(handle);
- xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, 0x0,
+ xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
(u32 *)&hdr, sizeof(struct ti_sci_msg_hdr),
sizeof(*rev_info));
if (IS_ERR(xfer)) {
@@ -499,8 +500,8 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
info = handle_to_ti_sci_info(handle);
- /* Response is expected, so need of any flags */
- xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, 0,
+ xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
(u32 *)&req, sizeof(req), sizeof(*resp));
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
@@ -2574,8 +2575,8 @@ static int ti_sci_cmd_change_fwl_owner(const struct ti_sci_handle *handle,
info = handle_to_ti_sci_info(handle);
- xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_GET,
- TISCI_MSG_FWL_CHANGE_OWNER,
+ xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_CHANGE_OWNER,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
(u32 *)&req, sizeof(req), sizeof(*resp));
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c
index 114dd910ab..285280e507 100644
--- a/drivers/fpga/socfpga_arria10.c
+++ b/drivers/fpga/socfpga_arria10.c
@@ -1,8 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2017 Intel Corporation <www.intel.com>
+ * Copyright (C) 2017-2019 Intel Corporation <www.intel.com>
*/
-
#include <asm/io.h>
#include <asm/arch/fpga_manager.h>
#include <asm/arch/reset_manager.h>
@@ -10,8 +9,11 @@
#include <asm/arch/sdram.h>
#include <asm/arch/misc.h>
#include <altera.h>
+#include <asm/arch/pinmux.h>
#include <common.h>
+#include <dm/ofnode.h>
#include <errno.h>
+#include <fs_loader.h>
#include <wait_bit.h>
#include <watchdog.h>
@@ -21,6 +23,9 @@
#define COMPRESSION_OFFSET 229
#define FPGA_TIMEOUT_MSEC 1000 /* timeout in ms */
#define FPGA_TIMEOUT_CNT 0x1000000
+#define DEFAULT_DDR_LOAD_ADDRESS 0x400
+
+DECLARE_GLOBAL_DATA_PTR;
static const struct socfpga_fpga_manager *fpga_manager_base =
(void *)SOCFPGA_FPGAMGRREGS_ADDRESS;
@@ -64,7 +69,7 @@ static int wait_for_user_mode(void)
1, FPGA_TIMEOUT_MSEC, false);
}
-static int is_fpgamgr_early_user_mode(void)
+int is_fpgamgr_early_user_mode(void)
{
return (readl(&fpga_manager_base->imgcfg_stat) &
ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK) != 0;
@@ -94,7 +99,7 @@ int fpgamgr_wait_early_user_mode(void)
i++;
}
- debug("Additional %i sync word needed\n", i);
+ debug("FPGA: Additional %i sync word needed\n", i);
/* restoring original CDRATIO */
fpgamgr_set_cd_ratio(cd_ratio);
@@ -172,9 +177,10 @@ static int fpgamgr_set_cdratio_cdwidth(unsigned int cfg_width, u32 *rbf_data,
compress = (rbf_data[COMPRESSION_OFFSET] >> 1) & 1;
compress = !compress;
- debug("header word %d = %08x\n", 69, rbf_data[69]);
- debug("header word %d = %08x\n", 229, rbf_data[229]);
- debug("read from rbf header: encrypt=%d compress=%d\n", encrypt, compress);
+ debug("FPGA: Header word %d = %08x.\n", 69, rbf_data[69]);
+ debug("FPGA: Header word %d = %08x.\n", 229, rbf_data[229]);
+ debug("FPGA: Read from rbf header: encrypt=%d compress=%d.\n", encrypt,
+ compress);
/*
* from the register map description of cdratio in imgcfg_ctrl_02:
@@ -359,6 +365,7 @@ static int fpgamgr_program_poll_cd(void)
printf("nstatus == 0 while waiting for condone\n");
return -EPERM;
}
+ WATCHDOG_RESET();
}
if (i == FPGA_TIMEOUT_CNT)
@@ -432,7 +439,6 @@ int fpgamgr_program_finish(void)
printf("FPGA: Poll CD failed with error code %d\n", status);
return -EPERM;
}
- WATCHDOG_RESET();
/* Ensure the FPGA entering user mode */
status = fpgamgr_program_poll_usermode();
@@ -447,27 +453,493 @@ int fpgamgr_program_finish(void)
return 0;
}
-/*
- * FPGA Manager to program the FPGA. This is the interface used by FPGA driver.
- * Return 0 for sucess, non-zero for error.
- */
+ofnode get_fpga_mgr_ofnode(ofnode from)
+{
+ return ofnode_by_compatible(from, "altr,socfpga-a10-fpga-mgr");
+}
+
+const char *get_fpga_filename(void)
+{
+ const char *fpga_filename = NULL;
+
+ ofnode fpgamgr_node = get_fpga_mgr_ofnode(ofnode_null());
+
+ if (ofnode_valid(fpgamgr_node))
+ fpga_filename = ofnode_read_string(fpgamgr_node,
+ "altr,bitstream");
+
+ return fpga_filename;
+}
+
+static void get_rbf_image_info(struct rbf_info *rbf, u16 *buffer)
+{
+ /*
+ * Magic ID starting at:
+ * -> 1st dword[15:0] in periph.rbf
+ * -> 2nd dword[15:0] in core.rbf
+ * Note: dword == 32 bits
+ */
+ u32 word_reading_max = 2;
+ u32 i;
+
+ for (i = 0; i < word_reading_max; i++) {
+ if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
+ rbf->security = unencrypted;
+ } else if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
+ rbf->security = encrypted;
+ } else if (*(buffer + i + 1) ==
+ FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
+ rbf->security = unencrypted;
+ } else if (*(buffer + i + 1) ==
+ FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
+ rbf->security = encrypted;
+ } else {
+ rbf->security = invalid;
+ continue;
+ }
+
+ /* PERIPH RBF(buffer + i + 1), CORE RBF(buffer + i + 2) */
+ if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
+ rbf->section = periph_section;
+ break;
+ } else if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_CORE) {
+ rbf->section = core_section;
+ break;
+ } else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
+ rbf->section = periph_section;
+ break;
+ } else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_CORE) {
+ rbf->section = core_section;
+ break;
+ }
+
+ rbf->section = unknown;
+ break;
+
+ WATCHDOG_RESET();
+ }
+}
+
+#ifdef CONFIG_FS_LOADER
+static int first_loading_rbf_to_buffer(struct udevice *dev,
+ struct fpga_loadfs_info *fpga_loadfs,
+ u32 *buffer, size_t *buffer_bsize)
+{
+ u32 *buffer_p = (u32 *)*buffer;
+ u32 *loadable = buffer_p;
+ size_t buffer_size = *buffer_bsize;
+ size_t fit_size;
+ int ret, i, count, confs_noffset, images_noffset, rbf_offset, rbf_size;
+ const char *fpga_node_name = NULL;
+ const char *uname = NULL;
+
+ /* Load image header into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, sizeof(struct image_header),
+ 0);
+ if (ret < 0) {
+ debug("FPGA: Failed to read image header from flash.\n");
+ return -ENOENT;
+ }
+
+ if (image_get_magic((struct image_header *)buffer_p) != FDT_MAGIC) {
+ debug("FPGA: No FDT magic was found.\n");
+ return -EBADF;
+ }
+
+ fit_size = fdt_totalsize(buffer_p);
+
+ if (fit_size > buffer_size) {
+ debug("FPGA: FIT image is larger than available buffer.\n");
+ debug("Please use FIT external data or increasing buffer.\n");
+ return -ENOMEM;
+ }
+
+ /* Load entire FIT into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, fit_size, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = fit_check_format(buffer_p);
+ if (!ret) {
+ debug("FPGA: No valid FIT image was found.\n");
+ return -EBADF;
+ }
+
+ confs_noffset = fdt_path_offset(buffer_p, FIT_CONFS_PATH);
+ images_noffset = fdt_path_offset(buffer_p, FIT_IMAGES_PATH);
+ if (confs_noffset < 0 || images_noffset < 0) {
+ debug("FPGA: No Configurations or images nodes were found.\n");
+ return -ENOENT;
+ }
+
+ /* Get default configuration unit name from default property */
+ confs_noffset = fit_conf_get_node(buffer_p, NULL);
+ if (confs_noffset < 0) {
+ debug("FPGA: No default configuration was found in config.\n");
+ return -ENOENT;
+ }
+
+ count = fit_conf_get_prop_node_count(buffer_p, confs_noffset,
+ FIT_FPGA_PROP);
+ if (count < 0) {
+ debug("FPGA: Invalid configuration format for FPGA node.\n");
+ return count;
+ }
+ debug("FPGA: FPGA node count: %d\n", count);
+
+ for (i = 0; i < count; i++) {
+ images_noffset = fit_conf_get_prop_node_index(buffer_p,
+ confs_noffset,
+ FIT_FPGA_PROP, i);
+ uname = fit_get_name(buffer_p, images_noffset, NULL);
+ if (uname) {
+ debug("FPGA: %s\n", uname);
+
+ if (strstr(uname, "fpga-periph") &&
+ (!is_fpgamgr_early_user_mode() ||
+ is_fpgamgr_user_mode())) {
+ fpga_node_name = uname;
+ printf("FPGA: Start to program ");
+ printf("peripheral/full bitstream ...\n");
+ break;
+ } else if (strstr(uname, "fpga-core") &&
+ (is_fpgamgr_early_user_mode() &&
+ !is_fpgamgr_user_mode())) {
+ fpga_node_name = uname;
+ printf("FPGA: Start to program core ");
+ printf("bitstream ...\n");
+ break;
+ }
+ }
+ WATCHDOG_RESET();
+ }
+
+ if (!fpga_node_name) {
+ debug("FPGA: No suitable bitstream was found, count: %d.\n", i);
+ return 1;
+ }
+
+ images_noffset = fit_image_get_node(buffer_p, fpga_node_name);
+ if (images_noffset < 0) {
+ debug("FPGA: No node '%s' was found in FIT.\n",
+ fpga_node_name);
+ return -ENOENT;
+ }
+
+ if (!fit_image_get_data_position(buffer_p, images_noffset,
+ &rbf_offset)) {
+ debug("FPGA: Data position was found.\n");
+ } else if (!fit_image_get_data_offset(buffer_p, images_noffset,
+ &rbf_offset)) {
+ /*
+ * For FIT with external data, figure out where
+ * the external images start. This is the base
+ * for the data-offset properties in each image.
+ */
+ rbf_offset += ((fdt_totalsize(buffer_p) + 3) & ~3);
+ debug("FPGA: Data offset was found.\n");
+ } else {
+ debug("FPGA: No data position/offset was found.\n");
+ return -ENOENT;
+ }
+
+ ret = fit_image_get_data_size(buffer_p, images_noffset, &rbf_size);
+ if (ret < 0) {
+ debug("FPGA: No data size was found (err=%d).\n", ret);
+ return -ENOENT;
+ }
+
+ if (gd->ram_size < rbf_size) {
+ debug("FPGA: Using default OCRAM buffer and size.\n");
+ } else {
+ ret = fit_image_get_load(buffer_p, images_noffset,
+ (ulong *)loadable);
+ if (ret < 0) {
+ buffer_p = (u32 *)DEFAULT_DDR_LOAD_ADDRESS;
+ debug("FPGA: No loadable was found.\n");
+ debug("FPGA: Using default DDR load address: 0x%x .\n",
+ DEFAULT_DDR_LOAD_ADDRESS);
+ } else {
+ buffer_p = (u32 *)*loadable;
+ debug("FPGA: Found loadable address = 0x%x.\n",
+ *loadable);
+ }
+
+ buffer_size = rbf_size;
+ }
+
+ debug("FPGA: External data: offset = 0x%x, size = 0x%x.\n",
+ rbf_offset, rbf_size);
+
+ fpga_loadfs->remaining = rbf_size;
+
+ /*
+ * Determine buffer size vs bitstream size, and calculating number of
+ * chunk by chunk transfer is required due to smaller buffer size
+ * compare to bitstream
+ */
+ if (rbf_size <= buffer_size) {
+ /* Loading whole bitstream into buffer */
+ buffer_size = rbf_size;
+ fpga_loadfs->remaining = 0;
+ } else {
+ fpga_loadfs->remaining -= buffer_size;
+ }
+
+ fpga_loadfs->offset = rbf_offset;
+ /* Loading bitstream into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, buffer_size,
+ fpga_loadfs->offset);
+ if (ret < 0) {
+ debug("FPGA: Failed to read bitstream from flash.\n");
+ return -ENOENT;
+ }
+
+ /* Getting info about bitstream types */
+ get_rbf_image_info(&fpga_loadfs->rbfinfo, (u16 *)buffer_p);
+
+ /* Update next reading bitstream offset */
+ fpga_loadfs->offset += buffer_size;
+
+ /* Update the final addr for bitstream */
+ *buffer = (u32)buffer_p;
+
+ /* Update the size of bitstream to be programmed into FPGA */
+ *buffer_bsize = buffer_size;
+
+ return 0;
+}
+
+static int subsequent_loading_rbf_to_buffer(struct udevice *dev,
+ struct fpga_loadfs_info *fpga_loadfs,
+ u32 *buffer, size_t *buffer_bsize)
+{
+ int ret = 0;
+ u32 *buffer_p = (u32 *)*buffer;
+
+ /* Read the bitstream chunk by chunk. */
+ if (fpga_loadfs->remaining > *buffer_bsize) {
+ fpga_loadfs->remaining -= *buffer_bsize;
+ } else {
+ *buffer_bsize = fpga_loadfs->remaining;
+ fpga_loadfs->remaining = 0;
+ }
+
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, *buffer_bsize,
+ fpga_loadfs->offset);
+ if (ret < 0) {
+ debug("FPGA: Failed to read bitstream from flash.\n");
+ return -ENOENT;
+ }
+
+ /* Update next reading bitstream offset */
+ fpga_loadfs->offset += *buffer_bsize;
+
+ return 0;
+}
+
+int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize,
+ u32 offset)
+{
+ struct fpga_loadfs_info fpga_loadfs;
+ struct udevice *dev;
+ int status, ret, size;
+ u32 buffer = (uintptr_t)buf;
+ size_t buffer_sizebytes = bsize;
+ size_t buffer_sizebytes_ori = bsize;
+ size_t total_sizeof_image = 0;
+ ofnode node;
+ const fdt32_t *phandle_p;
+ u32 phandle;
+
+ node = get_fpga_mgr_ofnode(ofnode_null());
+
+ if (ofnode_valid(node)) {
+ phandle_p = ofnode_get_property(node, "firmware-loader", &size);
+ if (!phandle_p) {
+ node = ofnode_path("/chosen");
+ if (!ofnode_valid(node)) {
+ debug("FPGA: /chosen node was not found.\n");
+ return -ENOENT;
+ }
+
+ phandle_p = ofnode_get_property(node, "firmware-loader",
+ &size);
+ if (!phandle_p) {
+ debug("FPGA: firmware-loader property was not");
+ debug(" found.\n");
+ return -ENOENT;
+ }
+ }
+ } else {
+ debug("FPGA: FPGA manager node was not found.\n");
+ return -ENOENT;
+ }
+
+ phandle = fdt32_to_cpu(*phandle_p);
+ ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
+ phandle, &dev);
+ if (ret)
+ return ret;
+
+ memset(&fpga_loadfs, 0, sizeof(fpga_loadfs));
+
+ fpga_loadfs.fpga_fsinfo = fpga_fsinfo;
+ fpga_loadfs.offset = offset;
+
+ printf("FPGA: Checking FPGA configuration setting ...\n");
+
+ /*
+ * Note: Both buffer and buffer_sizebytes values can be altered by
+ * function below.
+ */
+ ret = first_loading_rbf_to_buffer(dev, &fpga_loadfs, &buffer,
+ &buffer_sizebytes);
+ if (ret == 1) {
+ printf("FPGA: Skipping configuration ...\n");
+ return 0;
+ } else if (ret) {
+ return ret;
+ }
+
+ if (fpga_loadfs.rbfinfo.section == core_section &&
+ !(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
+ debug("FPGA : Must be in Early Release mode to program ");
+ debug("core bitstream.\n");
+ return -EPERM;
+ }
+
+ /* Disable all signals from HPS peripheral controller to FPGA */
+ writel(0, &system_manager_base->fpgaintf_en_global);
+
+ /* Disable all axi bridges (hps2fpga, lwhps2fpga & fpga2hps) */
+ socfpga_bridges_reset();
+
+ if (fpga_loadfs.rbfinfo.section == periph_section) {
+ /* Initialize the FPGA Manager */
+ status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes);
+ if (status) {
+ debug("FPGA: Init with peripheral bitstream failed.\n");
+ return -EPERM;
+ }
+ }
+
+ /* Transfer bitstream to FPGA Manager */
+ fpgamgr_program_write((void *)buffer, buffer_sizebytes);
+
+ total_sizeof_image += buffer_sizebytes;
+
+ while (fpga_loadfs.remaining) {
+ ret = subsequent_loading_rbf_to_buffer(dev,
+ &fpga_loadfs,
+ &buffer,
+ &buffer_sizebytes_ori);
+
+ if (ret)
+ return ret;
+
+ /* Transfer data to FPGA Manager */
+ fpgamgr_program_write((void *)buffer,
+ buffer_sizebytes_ori);
+
+ total_sizeof_image += buffer_sizebytes_ori;
+
+ WATCHDOG_RESET();
+ }
+
+ if (fpga_loadfs.rbfinfo.section == periph_section) {
+ if (fpgamgr_wait_early_user_mode() != -ETIMEDOUT) {
+ config_pins(gd->fdt_blob, "shared");
+ puts("FPGA: Early Release Succeeded.\n");
+ } else {
+ debug("FPGA: Failed to see Early Release.\n");
+ return -EIO;
+ }
+
+ /* For monolithic bitstream */
+ if (is_fpgamgr_user_mode()) {
+ /* Ensure the FPGA entering config done */
+ status = fpgamgr_program_finish();
+ if (status)
+ return status;
+
+ config_pins(gd->fdt_blob, "fpga");
+ puts("FPGA: Enter user mode.\n");
+ }
+ } else if (fpga_loadfs.rbfinfo.section == core_section) {
+ /* Ensure the FPGA entering config done */
+ status = fpgamgr_program_finish();
+ if (status)
+ return status;
+
+ config_pins(gd->fdt_blob, "fpga");
+ puts("FPGA: Enter user mode.\n");
+ } else {
+ debug("FPGA: Config Error: Unsupported bitstream type.\n");
+ return -ENOEXEC;
+ }
+
+ return (int)total_sizeof_image;
+}
+
+void fpgamgr_program(const void *buf, size_t bsize, u32 offset)
+{
+ fpga_fs_info fpga_fsinfo;
+
+ fpga_fsinfo.filename = get_fpga_filename();
+
+ if (fpga_fsinfo.filename)
+ socfpga_loadfs(&fpga_fsinfo, buf, bsize, offset);
+}
+#endif
+
+/* This function is used to load the core bitstream from the OCRAM. */
int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
- int status;
+ unsigned long status;
+ struct rbf_info rbfinfo;
- /* disable all signals from hps peripheral controller to fpga */
+ memset(&rbfinfo, 0, sizeof(rbfinfo));
+
+ /* Disable all signals from hps peripheral controller to fpga */
writel(0, &system_manager_base->fpgaintf_en_global);
- /* disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
+ /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
socfpga_bridges_reset();
- /* Initialize the FPGA Manager */
- status = fpgamgr_program_init((u32 *)rbf_data, rbf_size);
- if (status)
- return status;
+ /* Getting info about bitstream types */
+ get_rbf_image_info(&rbfinfo, (u16 *)rbf_data);
+
+ if (rbfinfo.section == periph_section) {
+ /* Initialize the FPGA Manager */
+ status = fpgamgr_program_init((u32 *)rbf_data, rbf_size);
+ if (status)
+ return status;
+ }
- /* Write the RBF data to FPGA Manager */
+ if (rbfinfo.section == core_section &&
+ !(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
+ debug("FPGA : Must be in early release mode to program ");
+ debug("core bitstream.\n");
+ return -EPERM;
+ }
+
+ /* Write the bitstream to FPGA Manager */
fpgamgr_program_write(rbf_data, rbf_size);
- return fpgamgr_program_finish();
+ status = fpgamgr_program_finish();
+ if (status) {
+ config_pins(gd->fdt_blob, "fpga");
+ puts("FPGA: Enter user mode.\n");
+ }
+
+ return status;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b3e4ecc50e..e36a8abc42 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -169,6 +169,12 @@ config RCAR_GPIO
help
This driver supports the GPIO banks on Renesas RCar SoCs.
+config RZA1_GPIO
+ bool "Renesas RZ/A1 GPIO driver"
+ depends on DM_GPIO && RZA1
+ help
+ This driver supports the GPIO banks on Renesas RZ/A1 R7S72100 SoCs.
+
config ROCKCHIP_GPIO
bool "Rockchip GPIO driver"
depends on DM_GPIO
@@ -351,7 +357,7 @@ config MPC8XXX_GPIO
config MT7621_GPIO
bool "MediaTek MT7621 GPIO driver"
- depends on DM_GPIO && ARCH_MT7620
+ depends on DM_GPIO && SOC_MT7628
default y
help
Say yes here to support MediaTek MT7621 compatible GPIOs.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 3be325044f..7337153e0e 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_PCA953X) += pca953x.o
obj-$(CONFIG_PCA9698) += pca9698.o
obj-$(CONFIG_ROCKCHIP_GPIO) += rk_gpio.o
obj-$(CONFIG_RCAR_GPIO) += gpio-rcar.o
+obj-$(CONFIG_RZA1_GPIO) += gpio-rza1.o
obj-$(CONFIG_S5P) += s5p_gpio.o
obj-$(CONFIG_SANDBOX_GPIO) += sandbox.o
obj-$(CONFIG_SPEAR_GPIO) += spear_gpio.o
diff --git a/drivers/gpio/dwapb_gpio.c b/drivers/gpio/dwapb_gpio.c
index e55fb4ac73..2eb1547b4f 100644
--- a/drivers/gpio/dwapb_gpio.c
+++ b/drivers/gpio/dwapb_gpio.c
@@ -17,8 +17,6 @@
#include <errno.h>
#include <reset.h>
-DECLARE_GLOBAL_DATA_PTR;
-
#define GPIO_SWPORT_DR(p) (0x00 + (p) * 0xc)
#define GPIO_SWPORT_DDR(p) (0x04 + (p) * 0xc)
#define GPIO_INTEN 0x30
@@ -150,10 +148,10 @@ static int gpio_dwapb_probe(struct udevice *dev)
static int gpio_dwapb_bind(struct udevice *dev)
{
struct gpio_dwapb_platdata *plat = dev_get_platdata(dev);
- const void *blob = gd->fdt_blob;
struct udevice *subdev;
fdt_addr_t base;
- int ret, node, bank = 0;
+ int ret, bank = 0;
+ ofnode node;
/* If this is a child device, there is nothing to do here */
if (plat)
@@ -165,10 +163,9 @@ static int gpio_dwapb_bind(struct udevice *dev)
return -ENXIO;
}
- for (node = fdt_first_subnode(blob, dev_of_offset(dev));
- node > 0;
- node = fdt_next_subnode(blob, node)) {
- if (!fdtdec_get_bool(blob, node, "gpio-controller"))
+ for (node = dev_read_first_subnode(dev); ofnode_valid(node);
+ node = dev_read_next_subnode(node)) {
+ if (!ofnode_read_bool(node, "gpio-controller"))
continue;
plat = devm_kcalloc(dev, 1, sizeof(*plat), GFP_KERNEL);
@@ -177,23 +174,22 @@ static int gpio_dwapb_bind(struct udevice *dev)
plat->base = base;
plat->bank = bank;
- plat->pins = fdtdec_get_int(blob, node, "snps,nr-gpios", 0);
- plat->name = fdt_stringlist_get(blob, node, "bank-name", 0,
- NULL);
- if (!plat->name) {
+ plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0);
+
+ if (ofnode_read_string_index(node, "bank-name", 0,
+ &plat->name)) {
/*
* Fall back to node name. This means accessing pins
* via bank name won't work.
*/
- plat->name = fdt_get_name(blob, node, NULL);
+ plat->name = ofnode_get_name(node);
}
- ret = device_bind(dev, dev->driver, plat->name,
- plat, -1, &subdev);
+ ret = device_bind_ofnode(dev, dev->driver, plat->name,
+ plat, node, &subdev);
if (ret)
return ret;
- dev_set_of_offset(subdev, node);
bank++;
}
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 6fd1270640..594e0a470a 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <clk.h>
#include <dm.h>
+#include <dm/pinctrl.h>
#include <errno.h>
#include <asm/gpio.h>
#include <asm/io.h>
@@ -117,19 +118,17 @@ static int rcar_gpio_get_function(struct udevice *dev, unsigned offset)
static int rcar_gpio_request(struct udevice *dev, unsigned offset,
const char *label)
{
- struct rcar_gpio_priv *priv = dev_get_priv(dev);
- struct udevice *pctldev;
- int ret;
-
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
- if (ret)
- return ret;
+ return pinctrl_gpio_request(dev, offset);
+}
- return sh_pfc_config_mux_for_gpio(pctldev, priv->pfc_offset + offset);
+static int rcar_gpio_free(struct udevice *dev, unsigned offset)
+{
+ return pinctrl_gpio_free(dev, offset);
}
static const struct dm_gpio_ops rcar_gpio_ops = {
.request = rcar_gpio_request,
+ .free = rcar_gpio_free,
.direction_input = rcar_gpio_direction_input,
.direction_output = rcar_gpio_direction_output,
.get_value = rcar_gpio_get_value,
diff --git a/drivers/gpio/gpio-rza1.c b/drivers/gpio/gpio-rza1.c
new file mode 100644
index 0000000000..ce2453e2ba
--- /dev/null
+++ b/drivers/gpio/gpio-rza1.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#define P(bank) (0x0000 + (bank) * 4)
+#define PSR(bank) (0x0100 + (bank) * 4)
+#define PPR(bank) (0x0200 + (bank) * 4)
+#define PM(bank) (0x0300 + (bank) * 4)
+#define PMC(bank) (0x0400 + (bank) * 4)
+#define PFC(bank) (0x0500 + (bank) * 4)
+#define PFCE(bank) (0x0600 + (bank) * 4)
+#define PNOT(bank) (0x0700 + (bank) * 4)
+#define PMSR(bank) (0x0800 + (bank) * 4)
+#define PMCSR(bank) (0x0900 + (bank) * 4)
+#define PFCAE(bank) (0x0A00 + (bank) * 4)
+#define PIBC(bank) (0x4000 + (bank) * 4)
+#define PBDC(bank) (0x4100 + (bank) * 4)
+#define PIPC(bank) (0x4200 + (bank) * 4)
+
+#define RZA1_MAX_GPIO_PER_BANK 16
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct r7s72100_gpio_priv {
+ void __iomem *regs;
+ int bank;
+};
+
+static int r7s72100_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ return !!(readw(priv->regs + PPR(priv->bank)) & BIT(offset));
+}
+
+static int r7s72100_gpio_set_value(struct udevice *dev, unsigned line,
+ int value)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ writel(BIT(line + 16) | (value ? BIT(line) : 0),
+ priv->regs + PSR(priv->bank));
+
+ return 0;
+}
+
+static void r7s72100_gpio_set_direction(struct udevice *dev, unsigned line,
+ bool output)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ writel(BIT(line + 16), priv->regs + PMCSR(priv->bank));
+ writel(BIT(line + 16) | (output ? 0 : BIT(line)),
+ priv->regs + PMSR(priv->bank));
+
+ clrsetbits_le16(priv->regs + PIBC(priv->bank), BIT(line),
+ output ? 0 : BIT(line));
+}
+
+static int r7s72100_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ r7s72100_gpio_set_direction(dev, offset, false);
+ return 0;
+}
+
+static int r7s72100_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ r7s72100_gpio_set_value(dev, offset, value);
+ r7s72100_gpio_set_direction(dev, offset, true);
+
+ return 0;
+}
+
+static int r7s72100_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+
+ if (readw(priv->regs + PM(priv->bank)) & BIT(offset))
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops r7s72100_gpio_ops = {
+ .direction_input = r7s72100_gpio_direction_input,
+ .direction_output = r7s72100_gpio_direction_output,
+ .get_value = r7s72100_gpio_get_value,
+ .set_value = r7s72100_gpio_set_value,
+ .get_function = r7s72100_gpio_get_function,
+};
+
+static int r7s72100_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct r7s72100_gpio_priv *priv = dev_get_priv(dev);
+ struct fdtdec_phandle_args args;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ fdt_addr_t addr_base;
+
+ uc_priv->bank_name = dev->name;
+ dev = dev_get_parent(dev);
+ addr_base = devfdt_get_addr(dev);
+ if (addr_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = (void __iomem *)addr_base;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
+ NULL, 3, 0, &args);
+ priv->bank = ret == 0 ? (args.args[1] / RZA1_MAX_GPIO_PER_BANK) : -1;
+ uc_priv->gpio_count = ret == 0 ? args.args[2] : RZA1_MAX_GPIO_PER_BANK;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(r7s72100_gpio) = {
+ .name = "r7s72100-gpio",
+ .id = UCLASS_GPIO,
+ .ops = &r7s72100_gpio_ops,
+ .priv_auto_alloc_size = sizeof(struct r7s72100_gpio_priv),
+ .probe = r7s72100_gpio_probe,
+};
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
index 21df227717..3d96678a45 100644
--- a/drivers/gpio/rk_gpio.c
+++ b/drivers/gpio/rk_gpio.c
@@ -12,7 +12,8 @@
#include <linux/errno.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/gpio.h>
#include <dm/pinctrl.h>
#include <dt-bindings/clock/rk3288-cru.h>
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 215624020f..095a9bc6a4 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -161,7 +161,10 @@ config SYS_I2C_MXC
channels and operating on standard mode up to 100 kbits/s and fast
mode up to 400 kbits/s.
-if SYS_I2C_MXC
+# These settings are not used with DM_I2C, however SPL doesn't use
+# DM_I2C even if DM_I2C is enabled, and so might use these settings even
+# when main u-boot does not!
+if SYS_I2C_MXC && (!DM_I2C || SPL)
config SYS_I2C_MXC_I2C1
bool "NXP MXC I2C1"
help
diff --git a/drivers/i2c/ihs_i2c.c b/drivers/i2c/ihs_i2c.c
index 0922fe9bb1..f7b59d36f9 100644
--- a/drivers/i2c/ihs_i2c.c
+++ b/drivers/i2c/ihs_i2c.c
@@ -8,8 +8,7 @@
#include <i2c.h>
#ifdef CONFIG_DM_I2C
#include <dm.h>
-#include <fpgamap.h>
-#include "../misc/gdsys_soc.h"
+#include <regmap.h>
#else
#include <gdsys_fpga.h>
#endif
@@ -18,18 +17,24 @@
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv {
uint speed;
- phys_addr_t addr;
+ struct regmap *map;
};
-enum {
- REG_INTERRUPT_STATUS = 0x00,
- REG_INTERRUPT_ENABLE_CONTROL = 0x02,
- REG_WRITE_MAILBOX_EXT = 0x04,
- REG_WRITE_MAILBOX = 0x06,
- REG_READ_MAILBOX_EXT = 0x08,
- REG_READ_MAILBOX = 0x0A,
+struct ihs_i2c_regs {
+ u16 interrupt_status;
+ u16 interrupt_enable_control;
+ u16 write_mailbox_ext;
+ u16 write_mailbox;
+ u16 read_mailbox_ext;
+ u16 read_mailbox;
};
+#define ihs_i2c_set(map, member, val) \
+ regmap_set(map, struct ihs_i2c_regs, member, val)
+
+#define ihs_i2c_get(map, member, valp) \
+ regmap_get(map, struct ihs_i2c_regs, member, valp)
+
#else /* !CONFIG_DM_I2C */
DECLARE_GLOBAL_DATA_PTR;
@@ -92,14 +97,10 @@ static int wait_for_int(bool read)
uint ctr = 0;
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv *priv = dev_get_priv(dev);
- struct udevice *fpga;
-
- gdsys_soc_get_fpga(dev, &fpga);
#endif
#ifdef CONFIG_DM_I2C
- fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
- FPGAMAP_SIZE_16);
+ ihs_i2c_get(priv->map, interrupt_status, &val);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
@@ -107,17 +108,18 @@ static int wait_for_int(bool read)
while (!(val & (I2CINT_ERROR_EV
| (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
udelay(10);
- if (ctr++ > 5000)
- return 1;
+ if (ctr++ > 5000) {
+ debug("%s: timed out\n", __func__);
+ return -ETIMEDOUT;
+ }
#ifdef CONFIG_DM_I2C
- fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
- FPGAMAP_SIZE_16);
+ ihs_i2c_get(priv->map, interrupt_status, &val);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
}
- return (val & I2CINT_ERROR_EV) ? 1 : 0;
+ return (val & I2CINT_ERROR_EV) ? -EIO : 0;
}
#ifdef CONFIG_DM_I2C
@@ -130,20 +132,16 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
{
u16 val;
u16 data;
+ int res;
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv *priv = dev_get_priv(dev);
- struct udevice *fpga;
-
- gdsys_soc_get_fpga(dev, &fpga);
#endif
/* Clear interrupt status */
data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
#ifdef CONFIG_DM_I2C
- fpgamap_write(fpga, priv->addr + REG_INTERRUPT_STATUS, &data,
- FPGAMAP_SIZE_16);
- fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
- FPGAMAP_SIZE_16);
+ ihs_i2c_set(priv->map, interrupt_status, data);
+ ihs_i2c_get(priv->map, interrupt_status, &val);
#else
I2C_SET_REG(interrupt_status, data);
I2C_GET_REG(interrupt_status, &val);
@@ -156,8 +154,7 @@ 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_write(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, &val,
- FPGAMAP_SIZE_16);
+ ihs_i2c_set(priv->map, write_mailbox_ext, val);
#else
I2C_SET_REG(write_mailbox_ext, val);
#endif
@@ -170,24 +167,27 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
| (is_last ? 0 : I2CMB_HOLD_BUS);
#ifdef CONFIG_DM_I2C
- fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX, &data,
- FPGAMAP_SIZE_16);
+ ihs_i2c_set(priv->map, write_mailbox, data);
#else
I2C_SET_REG(write_mailbox, data);
#endif
#ifdef CONFIG_DM_I2C
- if (wait_for_int(dev, read))
+ res = wait_for_int(dev, read);
#else
- if (wait_for_int(read))
+ res = wait_for_int(read);
#endif
- return 1;
+ if (res) {
+ if (res == -ETIMEDOUT)
+ debug("%s: time out while waiting for event\n", __func__);
+
+ return res;
+ }
/* If we want to read, get the bytes from the mailbox */
if (read) {
#ifdef CONFIG_DM_I2C
- fpgamap_read(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val,
- FPGAMAP_SIZE_16);
+ ihs_i2c_get(priv->map, read_mailbox_ext, &val);
#else
I2C_GET_REG(read_mailbox_ext, &val);
#endif
@@ -206,19 +206,21 @@ static int ihs_i2c_send_buffer(uchar chip, u8 *data, int len, bool hold_bus,
int read)
#endif
{
+ int res;
+
while (len) {
int transfer = min(len, 2);
bool is_last = len <= transfer;
#ifdef CONFIG_DM_I2C
- if (ihs_i2c_transfer(dev, chip, data, transfer, read,
- hold_bus ? false : is_last))
- return 1;
+ res = ihs_i2c_transfer(dev, chip, data, transfer, read,
+ hold_bus ? false : is_last);
#else
- if (ihs_i2c_transfer(chip, data, transfer, read,
- hold_bus ? false : is_last))
- return 1;
+ res = ihs_i2c_transfer(chip, data, transfer, read,
+ hold_bus ? false : is_last);
#endif
+ if (res)
+ return res;
data += transfer;
len -= transfer;
@@ -249,14 +251,19 @@ static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, u8 *addr,
int alen, uchar *buffer, int len, int read)
#endif
{
+ int res;
+
/* Don't hold the bus if length of data to send/receive is zero */
+ if (len <= 0)
+ return -EINVAL;
+
#ifdef CONFIG_DM_I2C
- if (len <= 0 || ihs_i2c_address(dev, chip, addr, alen, len))
- return 1;
+ res = ihs_i2c_address(dev, chip, addr, alen, len);
#else
- if (len <= 0 || ihs_i2c_address(chip, addr, alen, len))
- return 1;
+ res = ihs_i2c_address(chip, addr, alen, len);
#endif
+ if (res)
+ return res;
#ifdef CONFIG_DM_I2C
return ihs_i2c_send_buffer(dev, chip, buffer, len, false, read);
@@ -270,11 +277,8 @@ static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, u8 *addr,
int ihs_i2c_probe(struct udevice *bus)
{
struct ihs_i2c_priv *priv = dev_get_priv(bus);
- int addr;
-
- addr = dev_read_u32_default(bus, "reg", -1);
- priv->addr = addr;
+ regmap_init_mem(dev_ofnode(bus), &priv->map);
return 0;
}
@@ -284,7 +288,7 @@ static int ihs_i2c_set_bus_speed(struct udevice *bus, uint speed)
struct ihs_i2c_priv *priv = dev_get_priv(bus);
if (speed != priv->speed && priv->speed != 0)
- return 1;
+ return -EINVAL;
priv->speed = speed;
@@ -301,8 +305,8 @@ static int ihs_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
* actucal data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
- debug("%s: Only one or two messages are supported.", __func__);
- return -1;
+ debug("%s: Only one or two messages are supported\n", __func__);
+ return -ENOTSUPP;
}
omsg = nmsgs == 1 ? &dummy : msg;
@@ -322,9 +326,11 @@ static int ihs_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
uchar buffer[2];
+ int res;
- if (ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true))
- return 1;
+ res = ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true);
+ if (res)
+ return res;
return 0;
}
@@ -366,9 +372,11 @@ static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar buffer[2];
+ int res;
- if (ihs_i2c_transfer(chip, buffer, 0, I2COP_READ, true))
- return 1;
+ res = ihs_i2c_transfer(chip, buffer, 0, I2COP_READ, true);
+ if (res)
+ return res;
return 0;
}
@@ -399,7 +407,7 @@ static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
if (speed != adap->speed)
- return 1;
+ return -EINVAL;
return speed;
}
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
index 74ac0a4aa7..0a2dafcec6 100644
--- a/drivers/i2c/mvtwsi.c
+++ b/drivers/i2c/mvtwsi.c
@@ -271,6 +271,17 @@ static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
do {
control = readl(&twsi->control);
if (control & MVTWSI_CONTROL_IFLG) {
+ /*
+ * On Armada 38x it seems that the controller works as
+ * if it first set the MVTWSI_CONTROL_IFLAG in the
+ * control register and only after that it changed the
+ * status register.
+ * This sometimes caused weird bugs which only appeared
+ * on selected I2C speeds and even then only sometimes.
+ * We therefore add here a simple ndealy(100), which
+ * seems to fix this weird bug.
+ */
+ ndelay(100);
status = readl(&twsi->status);
if (status == expected_status)
return 0;
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 5420afbc8e..23119cce65 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -482,8 +482,13 @@ static int i2c_write_data(struct mxc_i2c_bus *i2c_bus, u8 chip, const u8 *buf,
return ret;
}
+/* Will generate a STOP after the last byte if "last" is true, i.e. this is the
+ * final message of a transaction. If not, it switches the bus back to TX mode
+ * and does not send a STOP, leaving the bus in a state where a repeated start
+ * and address can be sent for another message.
+ */
static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf,
- int len)
+ int len, bool last)
{
int ret;
unsigned int temp;
@@ -513,17 +518,31 @@ static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf,
return ret;
}
- /*
- * It must generate STOP before read I2DR to prevent
- * controller from generating another clock cycle
- */
if (i == (len - 1)) {
- i2c_imx_stop(i2c_bus);
+ /* Final byte has already been received by master! When
+ * we read it from I2DR, the master will start another
+ * cycle. We must program it first to send a STOP or
+ * switch to TX to avoid this.
+ */
+ if (last) {
+ i2c_imx_stop(i2c_bus);
+ } else {
+ /* Final read, no stop, switch back to tx */
+ temp = readb(base + (I2CR << reg_shift));
+ temp |= I2CR_MTX | I2CR_TX_NO_AK;
+ writeb(temp, base + (I2CR << reg_shift));
+ }
} else if (i == (len - 2)) {
+ /* Master has already recevied penultimate byte. When
+ * we read it from I2DR, master will start RX of final
+ * byte. We must set TX_NO_AK now so it does not ACK
+ * that final byte.
+ */
temp = readb(base + (I2CR << reg_shift));
temp |= I2CR_TX_NO_AK;
writeb(temp, base + (I2CR << reg_shift));
}
+
writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
buf[i] = readb(base + (I2DR << reg_shift));
}
@@ -533,13 +552,34 @@ static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf,
debug(" 0x%02x", buf[ret]);
debug("\n");
- i2c_imx_stop(i2c_bus);
+ /* It is not clear to me that this is necessary */
+ if (last)
+ i2c_imx_stop(i2c_bus);
return 0;
}
#ifndef CONFIG_DM_I2C
/*
* Read data from I2C device
+ *
+ * The transactions use the syntax defined in the Linux kernel I2C docs.
+ *
+ * If alen is > 0, then this function will send a transaction of the form:
+ * S Chip Wr [A] Addr [A] S Chip Rd [A] [data] A ... NA P
+ * This is a normal I2C register read: writing the register address, then doing
+ * a repeated start and reading the data.
+ *
+ * If alen == 0, then we get this transaction:
+ * S Chip Wr [A] S Chip Rd [A] [data] A ... NA P
+ * This is somewhat unusual, though valid, transaction. It addresses the chip
+ * in write mode, but doesn't actually write any register address or data, then
+ * does a repeated start and reads data.
+ *
+ * If alen < 0, then we get this transaction:
+ * S Chip Rd [A] [data] A ... NA P
+ * The chip is addressed in read mode and then data is read. No register
+ * address is written first. This is perfectly valid on most devices and
+ * required on some (usually those that don't act like an array of registers).
*/
static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
int alen, u8 *buf, int len)
@@ -566,7 +606,7 @@ static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
return ret;
}
- ret = i2c_read_data(i2c_bus, chip, buf, len);
+ ret = i2c_read_data(i2c_bus, chip, buf, len, true);
i2c_imx_stop(i2c_bus);
return ret;
@@ -574,6 +614,20 @@ static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
/*
* Write data to I2C device
+ *
+ * If alen > 0, we get this transaction:
+ * S Chip Wr [A] addr [A] data [A] ... [A] P
+ * An ordinary write register command.
+ *
+ * If alen == 0, then we get this:
+ * S Chip Wr [A] data [A] ... [A] P
+ * This is a simple I2C write.
+ *
+ * If alen < 0, then we get this:
+ * S data [A] ... [A] P
+ * This is most likely NOT something that should be used. It doesn't send the
+ * chip address first, so in effect, the first byte of data will be used as the
+ * address.
*/
static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
int alen, const u8 *buf, int len)
@@ -881,6 +935,7 @@ static int mxc_i2c_probe(struct udevice *bus)
return 0;
}
+/* Sends: S Addr Wr [A|NA] P */
static int mxc_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
@@ -905,42 +960,54 @@ static int mxc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
ulong base = i2c_bus->base;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
+ int read_mode;
- /*
- * Here the 3rd parameter addr and the 4th one alen are set to 0,
- * because here we only want to send out chip address. The register
- * address is wrapped in msg.
+ /* Here address len is set to -1 to not send any address at first.
+ * Otherwise i2c_init_transfer will send the chip address with write
+ * mode set. This is wrong if the 1st message is read.
*/
- ret = i2c_init_transfer(i2c_bus, msg->addr, 0, 0);
+ ret = i2c_init_transfer(i2c_bus, msg->addr, 0, -1);
if (ret < 0) {
debug("i2c_init_transfer error: %d\n", ret);
return ret;
}
+ read_mode = -1; /* So it's always different on the first message */
for (; nmsgs > 0; nmsgs--, msg++) {
- bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
- debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
- if (msg->flags & I2C_M_RD)
- ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
- msg->len);
- else {
- ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
- msg->len);
- if (ret)
- break;
- if (next_is_read) {
- /* Reuse ret */
+ const int msg_is_read = !!(msg->flags & I2C_M_RD);
+
+ debug("i2c_xfer: chip=0x%x, len=0x%x, dir=%c\n", msg->addr,
+ msg->len, msg_is_read ? 'R' : 'W');
+
+ if (msg_is_read != read_mode) {
+ /* Send repeated start if not 1st message */
+ if (read_mode != -1) {
+ debug("i2c_xfer: [RSTART]\n");
ret = readb(base + (I2CR << reg_shift));
ret |= I2CR_RSTA;
writeb(ret, base + (I2CR << reg_shift));
-
- ret = tx_byte(i2c_bus, (msg->addr << 1) | 1);
- if (ret < 0) {
- i2c_imx_stop(i2c_bus);
- break;
- }
}
+ debug("i2c_xfer: [ADDR %02x | %c]\n", msg->addr,
+ msg_is_read ? 'R' : 'W');
+ ret = tx_byte(i2c_bus, (msg->addr << 1) | msg_is_read);
+ if (ret < 0) {
+ debug("i2c_xfer: [STOP]\n");
+ i2c_imx_stop(i2c_bus);
+ break;
+ }
+ read_mode = msg_is_read;
}
+
+ if (msg->flags & I2C_M_RD)
+ ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+ msg->len, nmsgs == 1 ||
+ (msg->flags & I2C_M_STOP));
+ else
+ ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+ msg->len);
+
+ if (ret < 0)
+ break;
}
if (ret)
diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c
index f9a5796b96..cdd94bb05a 100644
--- a/drivers/i2c/rk_i2c.c
+++ b/drivers/i2c/rk_i2c.c
@@ -12,9 +12,9 @@
#include <errno.h>
#include <i2c.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/i2c.h>
-#include <asm/arch/periph.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/i2c.h>
+#include <asm/arch-rockchip/periph.h>
#include <dm/pinctrl.h>
#include <linux/sizes.h>
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
index 3872364d6b..50c4fd0de2 100644
--- a/drivers/i2c/stm32f7_i2c.c
+++ b/drivers/i2c/stm32f7_i2c.c
@@ -500,7 +500,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
af_delay_max = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
- sdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min -
+ sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
@@ -540,8 +540,12 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
p_prev = p;
list_add_tail(&v->node, solutions);
+ break;
}
}
+
+ if (p_prev == p)
+ break;
}
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0e645f58be..cb8b5c04db 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -13,6 +13,24 @@ config MISC
set of generic read, write and ioctl methods may be used to
access the device.
+config SPL_MISC
+ bool "Enable Driver Model for Misc drivers in SPL"
+ depends on SPL_DM
+ help
+ Enable driver model for miscellaneous devices. This class is
+ used only for those do not fit other more general classes. A
+ set of generic read, write and ioctl methods may be used to
+ access the device.
+
+config TPL_MISC
+ bool "Enable Driver Model for Misc drivers in TPL"
+ depends on TPL_DM
+ help
+ Enable driver model for miscellaneous devices. This class is
+ used only for those do not fit other more general classes. A
+ set of generic read, write and ioctl methods may be used to
+ access the device.
+
config ALTERA_SYSID
bool "Altera Sysid support"
depends on MISC
@@ -68,6 +86,24 @@ config CROS_EC
control access to the battery and main PMIC depending on the
device. You can use the 'crosec' command to access it.
+config SPL_CROS_EC
+ bool "Enable Chrome OS EC in SPL"
+ help
+ Enable access to the Chrome OS EC in SPL. This is a separate
+ microcontroller typically available on a SPI bus on Chromebooks. It
+ provides access to the keyboard, some internal storage and may
+ control access to the battery and main PMIC depending on the
+ device. You can use the 'crosec' command to access it.
+
+config TPL_CROS_EC
+ bool "Enable Chrome OS EC in TPL"
+ help
+ Enable access to the Chrome OS EC in TPL. This is a separate
+ microcontroller typically available on a SPI bus on Chromebooks. It
+ provides access to the keyboard, some internal storage and may
+ control access to the battery and main PMIC depending on the
+ device. You can use the 'crosec' command to access it.
+
config CROS_EC_I2C
bool "Enable Chrome OS EC I2C driver"
depends on CROS_EC
@@ -86,6 +122,24 @@ config CROS_EC_LPC
through a legacy port interface, so on x86 machines the main
function of the EC is power and thermal management.
+config SPL_CROS_EC_LPC
+ bool "Enable Chrome OS EC LPC driver in SPL"
+ depends on CROS_EC
+ help
+ Enable I2C access to the Chrome OS EC. This is used on x86
+ Chromebooks such as link and falco. The keyboard is provided
+ through a legacy port interface, so on x86 machines the main
+ function of the EC is power and thermal management.
+
+config TPL_CROS_EC_LPC
+ bool "Enable Chrome OS EC LPC driver in TPL"
+ depends on CROS_EC
+ help
+ Enable I2C access to the Chrome OS EC. This is used on x86
+ Chromebooks such as link and falco. The keyboard is provided
+ through a legacy port interface, so on x86 machines the main
+ function of the EC is power and thermal management.
+
config CROS_EC_SANDBOX
bool "Enable Chrome OS EC sandbox driver"
depends on CROS_EC && SANDBOX
@@ -95,6 +149,24 @@ config CROS_EC_SANDBOX
EC flash read/write/erase support and a few other things. It is
enough to perform a Chrome OS verified boot on sandbox.
+config SPL_CROS_EC_SANDBOX
+ bool "Enable Chrome OS EC sandbox driver in SPL"
+ depends on SPL_CROS_EC && SANDBOX
+ help
+ Enable a sandbox emulation of the Chrome OS EC in SPL. This supports
+ keyboard (use the -l flag to enable the LCD), verified boot context,
+ EC flash read/write/erase support and a few other things. It is
+ enough to perform a Chrome OS verified boot on sandbox.
+
+config TPL_CROS_EC_SANDBOX
+ bool "Enable Chrome OS EC sandbox driver in TPL"
+ depends on TPL_CROS_EC && SANDBOX
+ help
+ Enable a sandbox emulation of the Chrome OS EC in TPL. This supports
+ keyboard (use the -l flag to enable the LCD), verified boot context,
+ EC flash read/write/erase support and a few other things. It is
+ enough to perform a Chrome OS verified boot on sandbox.
+
config CROS_EC_SPI
bool "Enable Chrome OS EC SPI driver"
depends on CROS_EC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6bdf5054f4..509c588582 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -4,11 +4,13 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_MISC) += misc-uclass.o
+
+obj-$(CONFIG_$(SPL_TPL_)CROS_EC) += cros_ec.o
+obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o
+obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o
+
ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_CROS_EC) += cros_ec.o
-obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
-obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
endif
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 565de040fe..382f826286 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -1482,7 +1482,7 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable)
UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
- .name = "cros_ec",
+ .name = "cros-ec",
.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
.post_bind = dm_scan_fdt_dev,
.flags = DM_UC_FLAG_ALLOC_PRIV_DMA,
diff --git a/drivers/misc/gdsys_rxaui_ctrl.c b/drivers/misc/gdsys_rxaui_ctrl.c
index 9a63c329bc..c56abce4d4 100644
--- a/drivers/misc/gdsys_rxaui_ctrl.c
+++ b/drivers/misc/gdsys_rxaui_ctrl.c
@@ -29,6 +29,7 @@ struct gdsys_rxaui_ctrl_regs {
struct gdsys_rxaui_ctrl_priv {
struct regmap *map;
+ bool state;
};
int gdsys_rxaui_set_polarity_inversion(struct udevice *dev, bool val)
@@ -36,6 +37,8 @@ int gdsys_rxaui_set_polarity_inversion(struct udevice *dev, bool val)
struct gdsys_rxaui_ctrl_priv *priv = dev_get_priv(dev);
u16 state;
+ priv->state = !priv->state;
+
rxaui_ctrl_get(priv->map, ctrl_1, &state);
if (val)
@@ -45,7 +48,7 @@ int gdsys_rxaui_set_polarity_inversion(struct udevice *dev, bool val)
rxaui_ctrl_set(priv->map, ctrl_1, state);
- return 0;
+ return !priv->state;
}
static const struct misc_ops gdsys_rxaui_ctrl_ops = {
@@ -56,7 +59,9 @@ int gdsys_rxaui_ctrl_probe(struct udevice *dev)
{
struct gdsys_rxaui_ctrl_priv *priv = dev_get_priv(dev);
- regmap_init_mem(dev, &priv->map);
+ regmap_init_mem(dev_ofnode(dev), &priv->map);
+
+ priv->state = false;
return 0;
}
diff --git a/drivers/misc/imx8/Makefile b/drivers/misc/imx8/Makefile
index ee05893cbb..48fdb5b61c 100644
--- a/drivers/misc/imx8/Makefile
+++ b/drivers/misc/imx8/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += scu_api.o scu.o
+obj-$(CONFIG_CMD_FUSE) += fuse.o
diff --git a/drivers/misc/imx8/fuse.c b/drivers/misc/imx8/fuse.c
new file mode 100644
index 0000000000..29d2256a22
--- /dev/null
+++ b/drivers/misc/imx8/fuse.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <console.h>
+#include <errno.h>
+#include <fuse.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define FSL_ECC_WORD_START_1 0x10
+#define FSL_ECC_WORD_END_1 0x10F
+
+#ifdef CONFIG_IMX8QXP
+#define FSL_ECC_WORD_START_2 0x220
+#define FSL_ECC_WORD_END_2 0x31F
+
+#define FSL_QXP_FUSE_GAP_START 0x110
+#define FSL_QXP_FUSE_GAP_END 0x21F
+#endif
+
+#define FSL_SIP_OTP_READ 0xc200000A
+#define FSL_SIP_OTP_WRITE 0xc200000B
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ return fuse_sense(bank, word, val);
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ unsigned long ret = 0, value = 0;
+
+ if (bank != 0) {
+ printf("Invalid bank argument, ONLY bank 0 is supported\n");
+ return -EINVAL;
+ }
+
+ ret = call_imx_sip_ret2(FSL_SIP_OTP_READ, (unsigned long)word, &value,
+ 0, 0);
+ *val = (u32)value;
+
+ return ret;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ if (bank != 0) {
+ printf("Invalid bank argument, ONLY bank 0 is supported\n");
+ return -EINVAL;
+ }
+
+ if (IS_ENABLED(CONFIG_IMX8QXP)) {
+ if (word >= FSL_QXP_FUSE_GAP_START &&
+ word <= FSL_QXP_FUSE_GAP_END) {
+ printf("Invalid word argument for this SoC\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((word >= FSL_ECC_WORD_START_1 && word <= FSL_ECC_WORD_END_1) ||
+ (word >= FSL_ECC_WORD_START_2 && word <= FSL_ECC_WORD_END_2)) {
+ puts("Warning: Words in this index range have ECC protection\n"
+ "and can only be programmed once per word. Individual bit\n"
+ "operations will be rejected after the first one.\n"
+ "\n\n Really program this word? <y/N>\n");
+
+ if (!confirm_yesno()) {
+ puts("Word programming aborted\n");
+ return -EPERM;
+ }
+ }
+
+ return call_imx_sip(FSL_SIP_OTP_WRITE, (unsigned long)word,
+ (unsigned long)val, 0);
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ printf("Override fuse to i.MX8 in u-boot is forbidden\n");
+ return -EPERM;
+}
diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c
index 1b9c49c99c..9ec00457b8 100644
--- a/drivers/misc/imx8/scu.c
+++ b/drivers/misc/imx8/scu.c
@@ -219,11 +219,21 @@ static int imx8_scu_bind(struct udevice *dev)
int ret;
struct udevice *child;
int node;
+ char *clk_compatible, *iomuxc_compatible;
+
+ if (IS_ENABLED(CONFIG_IMX8QXP)) {
+ clk_compatible = "fsl,imx8qxp-clk";
+ iomuxc_compatible = "fsl,imx8qxp-iomuxc";
+ } else if (IS_ENABLED(CONFIG_IMX8QM)) {
+ clk_compatible = "fsl,imx8qm-clk";
+ iomuxc_compatible = "fsl,imx8qm-iomuxc";
+ } else {
+ return -EINVAL;
+ }
debug("%s(dev=%p)\n", __func__, dev);
- node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
- "fsl,imx8qxp-clk");
+ node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, clk_compatible);
if (node < 0)
panic("No clk node found\n");
@@ -234,7 +244,7 @@ static int imx8_scu_bind(struct udevice *dev)
plat->clk = child;
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
- "fsl,imx8qxp-iomuxc");
+ iomuxc_compatible);
if (node < 0)
panic("No iomuxc node found\n");
diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c
index f84fe88db1..1b945e9727 100644
--- a/drivers/misc/mxc_ocotp.c
+++ b/drivers/misc/mxc_ocotp.c
@@ -321,6 +321,11 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
struct ocotp_regs *regs;
int ret;
+ if (is_imx8mq() && is_soc_rev(CHIP_REV_2_1)) {
+ printf("mxc_ocotp %s(): fuse sense is disabled\n", __func__);
+ return -EPERM;
+ }
+
ret = prepare_read(&regs, bank, word, val, __func__);
if (ret)
return ret;
@@ -354,13 +359,17 @@ static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word,
/* Only bank 0 and 1 are redundancy mode, others are ECC mode */
if (bank != 0 && bank != 1) {
- ret = fuse_sense(bank, word, &val);
- if (ret)
- return ret;
-
- if (val != 0) {
- printf("mxc_ocotp: The word has been programmed, no more write\n");
- return -EPERM;
+ if ((soc_rev() < CHIP_REV_2_0) ||
+ ((soc_rev() >= CHIP_REV_2_0) &&
+ bank != 9 && bank != 10 && bank != 28)) {
+ ret = fuse_sense(bank, word, &val);
+ if (ret)
+ return ret;
+
+ if (val != 0) {
+ printf("mxc_ocotp: The word has been programmed, no more write\n");
+ return -EPERM;
+ }
}
}
#endif
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c34dd5d187..c23299ea96 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -78,6 +78,12 @@ config SUPPORT_EMMC_RPMB
Enable support for reading, writing and programming the
key for the Replay Protection Memory Block partition in eMMC.
+config SUPPORT_EMMC_BOOT
+ bool "Support some additional features of the eMMC boot partitions"
+ help
+ Enable support for eMMC boot partitions. This also enables
+ extensions within the mmc command.
+
config MMC_IO_VOLTAGE
bool "Support IO voltage configuration"
help
@@ -385,6 +391,20 @@ config MMC_SDHCI_SDMA
This enables support for the SDMA (Single Operation DMA) defined
in the SD Host Controller Standard Specification Version 1.00 .
+config MMC_SDHCI_ADMA
+ bool "Support SDHCI ADMA2"
+ depends on MMC_SDHCI
+ help
+ This enables support for the ADMA (Advanced DMA) defined
+ in the SD Host Controller Standard Specification Version 3.00
+
+config SPL_MMC_SDHCI_ADMA
+ bool "Support SDHCI ADMA2 in SPL"
+ depends on MMC_SDHCI
+ help
+ This enables support for the ADMA (Advanced DMA) defined
+ in the SD Host Controller Standard Specification Version 3.00 in SPL.
+
config MMC_SDHCI_ATMEL
bool "Atmel SDHCI controller support"
depends on ARCH_AT91
diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c
index 443ae8d481..eef46f3af1 100644
--- a/drivers/mmc/bcmstb_sdhci.c
+++ b/drivers/mmc/bcmstb_sdhci.c
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018 Cisco Systems, Inc.
+ * (C) Copyright 2019 Synamedia
*
* Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
*/
#include <common.h>
+#include <dm.h>
#include <mach/sdhci.h>
#include <malloc.h>
#include <sdhci.h>
@@ -36,32 +38,67 @@
*/
#define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY 400000
-static char *BCMSTB_SDHCI_NAME = "bcmstb-sdhci";
-
/*
* This driver has only been tested with eMMC devices; SD devices may
* not work.
*/
-int bcmstb_sdhci_init(phys_addr_t regbase)
+struct sdhci_bcmstb_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+static int sdhci_bcmstb_bind(struct udevice *dev)
{
- struct sdhci_host *host = NULL;
+ struct sdhci_bcmstb_plat *plat = dev_get_platdata(dev);
- host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
- if (!host) {
- printf("%s: Failed to allocate memory\n", __func__);
- return 1;
- }
- memset(host, 0, sizeof(*host));
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static int sdhci_bcmstb_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct sdhci_bcmstb_plat *plat = dev_get_platdata(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ fdt_addr_t base;
+ int ret;
- host->name = BCMSTB_SDHCI_NAME;
- host->ioaddr = (void *)regbase;
- host->quirks = 0;
+ base = devfdt_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
- host->cfg.part_type = PART_TYPE_DOS;
+ host->name = dev->name;
+ host->ioaddr = (void *)base;
- host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ ret = mmc_of_parse(dev, &plat->cfg);
+ if (ret)
+ return ret;
- return add_sdhci(host,
- BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY,
- BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY);
+ ret = sdhci_setup_cfg(&plat->cfg, host,
+ BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY,
+ BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY);
+ if (ret)
+ return ret;
+
+ upriv->mmc = &plat->mmc;
+ host->mmc = &plat->mmc;
+ host->mmc->priv = host;
+
+ return sdhci_probe(dev);
}
+
+static const struct udevice_id sdhci_bcmstb_match[] = {
+ { .compatible = "brcm,bcm7425-sdhci" },
+ { .compatible = "brcm,sdhci-brcmstb" },
+ { }
+};
+
+U_BOOT_DRIVER(sdhci_bcmstb) = {
+ .name = "sdhci-bcmstb",
+ .id = UCLASS_MMC,
+ .of_match = sdhci_bcmstb_match,
+ .ops = &sdhci_ops,
+ .bind = sdhci_bcmstb_bind,
+ .probe = sdhci_bcmstb_probe,
+ .priv_auto_alloc_size = sizeof(struct sdhci_host),
+ .platdata_auto_alloc_size = sizeof(struct sdhci_bcmstb_plat),
+};
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 93a836eac3..1992d61182 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -74,15 +74,15 @@ static void dwmci_prepare_data(struct dwmci_host *host,
dwmci_set_idma_desc(cur_idmac, flags, cnt,
(ulong)bounce_buffer + (i * PAGE_SIZE));
+ cur_idmac++;
if (blk_cnt <= 8)
break;
blk_cnt -= 8;
- cur_idmac++;
i++;
} while(1);
data_end = (ulong)cur_idmac;
- flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN);
+ flush_dcache_range(data_start, roundup(data_end, ARCH_DMA_MINALIGN));
ctrl = dwmci_readl(host, DWMCI_CTRL);
ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN;
@@ -114,22 +114,40 @@ static int dwmci_fifo_ready(struct dwmci_host *host, u32 bit, u32 *len)
return 0;
}
+static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size)
+{
+ unsigned int timeout;
+
+ timeout = size * 8 * 1000; /* counting in bits and msec */
+ timeout *= 2; /* wait twice as long */
+ timeout /= mmc->clock;
+ timeout /= mmc->bus_width;
+ timeout /= mmc->ddr_mode ? 2 : 1;
+ timeout = (timeout < 1000) ? 1000 : timeout;
+
+ return timeout;
+}
+
static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
{
+ struct mmc *mmc = host->mmc;
int ret = 0;
- u32 timeout = 240000;
- u32 mask, size, i, len = 0;
+ u32 timeout, mask, size, i, len = 0;
u32 *buf = NULL;
ulong start = get_timer(0);
u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
RX_WMARK_SHIFT) + 1) * 2;
- size = data->blocksize * data->blocks / 4;
+ size = data->blocksize * data->blocks;
if (data->flags == MMC_DATA_READ)
buf = (unsigned int *)data->dest;
else
buf = (unsigned int *)data->src;
+ timeout = dwmci_get_timeout(mmc, size);
+
+ size /= 4;
+
for (;;) {
mask = dwmci_readl(host, DWMCI_RINTSTS);
/* Error during data transfer. */
@@ -252,14 +270,20 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
} else {
if (data->flags == MMC_DATA_READ) {
- bounce_buffer_start(&bbstate, (void*)data->dest,
+ ret = bounce_buffer_start(&bbstate,
+ (void*)data->dest,
data->blocksize *
data->blocks, GEN_BB_WRITE);
} else {
- bounce_buffer_start(&bbstate, (void*)data->src,
+ ret = bounce_buffer_start(&bbstate,
+ (void*)data->src,
data->blocksize *
data->blocks, GEN_BB_READ);
}
+
+ if (ret)
+ return ret;
+
dwmci_prepare_data(host, data, cur_idmac,
bbstate.bounce_buffer);
}
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 9e34557d16..672691fa6a 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -297,6 +297,13 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
return -ETIMEDOUT;
}
+ } else {
+#ifdef CONFIG_DM_GPIO
+ if (dm_gpio_is_valid(&priv->wp_gpio) && dm_gpio_get_value(&priv->wp_gpio)) {
+ printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
+ return -ETIMEDOUT;
+ }
+#endif
}
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
@@ -1428,7 +1435,9 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd)
#endif
#if CONFIG_IS_ENABLED(DM_MMC)
+#ifndef CONFIG_PPC
#include <asm/arch/clock.h>
+#endif
__weak void init_clk_usdhc(u32 index)
{
}
@@ -1453,8 +1462,11 @@ static int fsl_esdhc_probe(struct udevice *dev)
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
-
+#ifdef CONFIG_PPC
+ priv->esdhc_regs = (struct fsl_esdhc *)lower_32_bits(addr);
+#else
priv->esdhc_regs = (struct fsl_esdhc *)addr;
+#endif
priv->dev = dev;
priv->mode = -1;
if (data) {
@@ -1489,14 +1501,15 @@ static int fsl_esdhc_probe(struct udevice *dev)
#endif
}
- priv->wp_enable = 1;
-
+ if (dev_read_prop(dev, "fsl,wp-controller", NULL)) {
+ priv->wp_enable = 1;
+ } else {
+ priv->wp_enable = 0;
#ifdef CONFIG_DM_GPIO
- ret = gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
+ gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
GPIOD_IS_IN);
- if (ret)
- priv->wp_enable = 0;
#endif
+ }
priv->vs18_enable = 0;
@@ -1560,7 +1573,11 @@ static int fsl_esdhc_probe(struct udevice *dev)
priv->sdhc_clk = clk_get_rate(&priv->per_clk);
} else {
+#ifndef CONFIG_PPC
priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq);
+#else
+ priv->sdhc_clk = gd->arch.sdhc_clk;
+#endif
if (priv->sdhc_clk <= 0) {
dev_err(dev, "Unable to get clk for %s\n", dev->name);
return -EINVAL;
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 6c51ccc294..7c53aa221e 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -23,24 +23,126 @@
/* 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_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_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_RVSREQ_RVSERR BIT(2)
#define RENESAS_SDHI_SCC_SMPCMP 0x818
-#define RENESAS_SDHI_SCC_TMPPORT2 0x81c
-#define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
-#define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
+#define RENESAS_SDHI_SCC_TMPPORT2 0x81c
+#define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
+#define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
+#define RENESAS_SDHI_SCC_TMPPORT3 0x828
+#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_0 3
+#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_1 2
+#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_2 1
+#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_3 0
+#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_MASK 0x3
+#define RENESAS_SDHI_SCC_TMPPORT4 0x82c
+#define RENESAS_SDHI_SCC_TMPPORT4_DLL_ACC_START BIT(0)
+#define RENESAS_SDHI_SCC_TMPPORT5 0x830
+#define RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R BIT(8)
+#define RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W (0 << 8)
+#define RENESAS_SDHI_SCC_TMPPORT5_DLL_ADR_MASK 0x3F
+#define RENESAS_SDHI_SCC_TMPPORT6 0x834
+#define RENESAS_SDHI_SCC_TMPPORT7 0x838
+#define RENESAS_SDHI_SCC_TMPPORT_DISABLE_WP_CODE 0xa5000000
+#define RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK 0x1f
+#define RENESAS_SDHI_SCC_TMPPORT_MANUAL_MODE BIT(7)
#define RENESAS_SDHI_MAX_TAP 3
+static u32 sd_scc_tmpport_read32(struct tmio_sd_priv *priv, u32 addr)
+{
+ /* read mode */
+ tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R |
+ (RENESAS_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr),
+ RENESAS_SDHI_SCC_TMPPORT5);
+
+ /* access start and stop */
+ tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT4_DLL_ACC_START,
+ RENESAS_SDHI_SCC_TMPPORT4);
+ tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT4);
+
+ return tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT7);
+}
+
+static void sd_scc_tmpport_write32(struct tmio_sd_priv *priv, u32 addr, u32 val)
+{
+ /* write mode */
+ tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W |
+ (RENESAS_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr),
+ RENESAS_SDHI_SCC_TMPPORT5);
+ tmio_sd_writel(priv, val, RENESAS_SDHI_SCC_TMPPORT6);
+
+ /* access start and stop */
+ tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT4_DLL_ACC_START,
+ RENESAS_SDHI_SCC_TMPPORT4);
+ tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT4);
+}
+
+static void renesas_sdhi_adjust_hs400_mode_enable(struct tmio_sd_priv *priv)
+{
+ u32 calib_code;
+
+ if (!priv->adjust_hs400_enable)
+ return;
+
+ if (!priv->needs_adjust_hs400)
+ return;
+
+ /*
+ * Enabled Manual adjust HS400 mode
+ *
+ * 1) Disabled Write Protect
+ * W(addr=0x00, WP_DISABLE_CODE)
+ * 2) Read Calibration code and adjust
+ * R(addr=0x26) - adjust value
+ * 3) Enabled Manual Calibration
+ * W(addr=0x22, manual mode | Calibration code)
+ * 4) Set Offset value to TMPPORT3 Reg
+ */
+ sd_scc_tmpport_write32(priv, 0x00,
+ RENESAS_SDHI_SCC_TMPPORT_DISABLE_WP_CODE);
+ calib_code = sd_scc_tmpport_read32(priv, 0x26);
+ calib_code &= RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK;
+ if (calib_code > priv->adjust_hs400_calibrate)
+ calib_code -= priv->adjust_hs400_calibrate;
+ else
+ calib_code = 0;
+ sd_scc_tmpport_write32(priv, 0x22,
+ RENESAS_SDHI_SCC_TMPPORT_MANUAL_MODE |
+ calib_code);
+ tmio_sd_writel(priv, priv->adjust_hs400_offset,
+ RENESAS_SDHI_SCC_TMPPORT3);
+
+ /* Clear flag */
+ priv->needs_adjust_hs400 = false;
+}
+
+static void renesas_sdhi_adjust_hs400_mode_disable(struct tmio_sd_priv *priv)
+{
+
+ /* Disabled Manual adjust HS400 mode
+ *
+ * 1) Disabled Write Protect
+ * W(addr=0x00, WP_DISABLE_CODE)
+ * 2) Disabled Manual Calibration
+ * W(addr=0x22, 0)
+ * 3) Clear offset value to TMPPORT3 Reg
+ */
+ sd_scc_tmpport_write32(priv, 0x00,
+ RENESAS_SDHI_SCC_TMPPORT_DISABLE_WP_CODE);
+ sd_scc_tmpport_write32(priv, 0x22, 0);
+ tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT3);
+}
+
static unsigned int renesas_sdhi_init_tuning(struct tmio_sd_priv *priv)
{
u32 reg;
@@ -96,6 +198,9 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv)
RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL);
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2);
+ /* Disable HS400 mode adjustment */
+ renesas_sdhi_adjust_hs400_mode_disable(priv);
+
reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
reg |= TMIO_SD_CLKCTL_SCLKEN;
tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
@@ -137,6 +242,10 @@ static int renesas_sdhi_hs400(struct udevice *dev)
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2);
+ /* Disable HS400 mode adjustment */
+ if (!hs400)
+ renesas_sdhi_adjust_hs400_mode_disable(priv);
+
tmio_sd_writel(priv, (0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) |
RENESAS_SDHI_SCC_DTCNTL_TAPEN,
RENESAS_SDHI_SCC_DTCNTL);
@@ -159,6 +268,10 @@ static int renesas_sdhi_hs400(struct udevice *dev)
reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
+ /* Execute adjust hs400 offset after setting to HS400 mode */
+ if (hs400)
+ priv->needs_adjust_hs400 = true;
+
return 0;
}
@@ -188,6 +301,8 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv,
bool select = false;
u32 reg;
+ priv->needs_adjust_hs400 = false;
+
/* Clear SCC_RVSREQ */
tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
@@ -405,8 +520,29 @@ static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, int timeout)
}
#endif
+static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ int ret;
+
+ ret = tmio_sd_send_cmd(dev, cmd, data);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
+ CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
+ CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+
+ if (cmd->cmdidx == MMC_CMD_SEND_STATUS)
+ renesas_sdhi_adjust_hs400_mode_enable(priv);
+#endif
+
+ return 0;
+}
+
static const struct dm_mmc_ops renesas_sdhi_ops = {
- .send_cmd = tmio_sd_send_cmd,
+ .send_cmd = renesas_sdhi_send_cmd,
.set_ios = renesas_sdhi_set_ios,
.get_cd = tmio_sd_get_cd,
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
@@ -451,14 +587,37 @@ static void renesas_sdhi_filter_caps(struct udevice *dev)
if (!(priv->caps & TMIO_SD_CAP_RCAR_GEN3))
return;
- /* HS400 is not supported on H3 ES1.x and M3W ES1.0,ES1.1 */
+ /* HS400 is not supported on H3 ES1.x and M3W ES1.0,ES1.1,ES1.2 */
if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
(rmobile_get_cpu_rev_integer() <= 1)) ||
((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
(rmobile_get_cpu_rev_integer() == 1) &&
- (rmobile_get_cpu_rev_fraction() <= 1)))
+ (rmobile_get_cpu_rev_fraction() <= 2)))
plat->cfg.host_caps &= ~MMC_MODE_HS400;
+ /* M3W ES1.x for x>2 can use HS400 with manual adjustment */
+ if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
+ (rmobile_get_cpu_rev_integer() == 1) &&
+ (rmobile_get_cpu_rev_fraction() > 2)) {
+ priv->adjust_hs400_enable = true;
+ priv->adjust_hs400_offset = 0;
+ priv->adjust_hs400_calibrate = 0x9;
+ }
+
+ /* M3N can use HS400 with manual adjustment */
+ if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965) {
+ priv->adjust_hs400_enable = true;
+ priv->adjust_hs400_offset = 0;
+ priv->adjust_hs400_calibrate = 0x0;
+ }
+
+ /* E3 can use HS400 with manual adjustment */
+ if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77990) {
+ priv->adjust_hs400_enable = true;
+ priv->adjust_hs400_offset = 0;
+ priv->adjust_hs400_calibrate = 0x2;
+ }
+
/* H3 ES2.0 uses 4 tuning taps */
if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
(rmobile_get_cpu_rev_integer() == 2))
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index bf2d83a52c..b2a1201631 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -13,8 +13,8 @@
#include <pwrseq.h>
#include <syscon.h>
#include <asm/gpio.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/periph.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/periph.h>
#include <linux/err.h>
struct rockchip_mmc_plat {
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index cdeba914f9..e2bb90abbd 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -67,17 +67,123 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
}
}
-static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
- unsigned int start_addr)
+#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
+static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len,
+ bool end)
+{
+ struct sdhci_adma_desc *desc;
+ u8 attr;
+
+ desc = &host->adma_desc_table[host->desc_slot];
+
+ attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
+ if (!end)
+ host->desc_slot++;
+ else
+ attr |= ADMA_DESC_ATTR_END;
+
+ desc->attr = attr;
+ desc->len = len;
+ desc->reserved = 0;
+ desc->addr_lo = (dma_addr_t)buf;
+#ifdef CONFIG_DMA_ADDR_T_64BIT
+ desc->addr_hi = (u64)buf >> 32;
+#endif
+}
+
+static void sdhci_prepare_adma_table(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ uint trans_bytes = data->blocksize * data->blocks;
+ uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN);
+ int i = desc_count;
+ char *buf;
+
+ host->desc_slot = 0;
+
+ if (data->flags & MMC_DATA_READ)
+ buf = data->dest;
+ else
+ buf = (char *)data->src;
+
+ while (--i) {
+ sdhci_adma_desc(host, buf, ADMA_MAX_LEN, false);
+ buf += ADMA_MAX_LEN;
+ trans_bytes -= ADMA_MAX_LEN;
+ }
+
+ sdhci_adma_desc(host, buf, trans_bytes, true);
+
+ flush_cache((dma_addr_t)host->adma_desc_table,
+ ROUND(desc_count * sizeof(struct sdhci_adma_desc),
+ ARCH_DMA_MINALIGN));
+}
+#elif defined(CONFIG_MMC_SDHCI_SDMA)
+static void sdhci_prepare_adma_table(struct sdhci_host *host,
+ struct mmc_data *data)
+{}
+#endif
+#if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA))
+static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
+ int *is_aligned, int trans_bytes)
{
- unsigned int stat, rdy, mask, timeout, block = 0;
- bool transfer_done = false;
-#ifdef CONFIG_MMC_SDHCI_SDMA
unsigned char ctrl;
+
+ if (data->flags == MMC_DATA_READ)
+ host->start_addr = (dma_addr_t)data->dest;
+ else
+ host->start_addr = (dma_addr_t)data->src;
+
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if (host->flags & USE_ADMA64)
+ ctrl |= SDHCI_CTRL_ADMA64;
+ else if (host->flags & USE_ADMA)
+ ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ if (host->flags & USE_SDMA) {
+ if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+ (host->start_addr & 0x7) != 0x0) {
+ *is_aligned = 0;
+ host->start_addr = (unsigned long)aligned_buffer;
+ if (data->flags != MMC_DATA_READ)
+ memcpy(aligned_buffer, data->src, trans_bytes);
+ }
+
+#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
+ /*
+ * Always use this bounce-buffer when
+ * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
+ */
+ *is_aligned = 0;
+ host->start_addr = (unsigned long)aligned_buffer;
+ if (data->flags != MMC_DATA_READ)
+ memcpy(aligned_buffer, data->src, trans_bytes);
+#endif
+ sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS);
+
+ } else if (host->flags & (USE_ADMA | USE_ADMA64)) {
+ sdhci_prepare_adma_table(host, data);
+
+ sdhci_writel(host, (u32)host->adma_addr, SDHCI_ADMA_ADDRESS);
+ if (host->flags & USE_ADMA64)
+ sdhci_writel(host, (u64)host->adma_addr >> 32,
+ SDHCI_ADMA_ADDRESS_HI);
+ }
+
+ flush_cache(host->start_addr, ROUND(trans_bytes, ARCH_DMA_MINALIGN));
+}
+#else
+static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
+ int *is_aligned, int trans_bytes)
+{}
#endif
+static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
+{
+ dma_addr_t start_addr = host->start_addr;
+ unsigned int stat, rdy, mask, timeout, block = 0;
+ bool transfer_done = false;
timeout = 1000000;
rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
@@ -104,14 +210,17 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
continue;
}
}
-#ifdef CONFIG_MMC_SDHCI_SDMA
- if (!transfer_done && (stat & SDHCI_INT_DMA_END)) {
+ if ((host->flags & USE_DMA) && !transfer_done &&
+ (stat & SDHCI_INT_DMA_END)) {
sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS);
- start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
- start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
- sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
+ if (host->flags & USE_SDMA) {
+ start_addr &=
+ ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
+ start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
+ sdhci_writel(host, start_addr,
+ SDHCI_DMA_ADDRESS);
+ }
}
-#endif
if (timeout-- > 0)
udelay(10);
else {
@@ -149,10 +258,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
int ret = 0;
int trans_bytes = 0, is_aligned = 1;
u32 mask, flags, mode;
- unsigned int time = 0, start_addr = 0;
+ unsigned int time = 0;
int mmc_dev = mmc_get_blk_desc(mmc)->devnum;
ulong start = get_timer(0);
+ host->start_addr = 0;
/* Timeout unit - ms */
static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT;
@@ -218,33 +328,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (data->flags == MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
-#ifdef CONFIG_MMC_SDHCI_SDMA
- if (data->flags == MMC_DATA_READ)
- start_addr = (unsigned long)data->dest;
- else
- start_addr = (unsigned long)data->src;
- if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
- (start_addr & 0x7) != 0x0) {
- is_aligned = 0;
- start_addr = (unsigned long)aligned_buffer;
- if (data->flags != MMC_DATA_READ)
- memcpy(aligned_buffer, data->src, trans_bytes);
+ if (host->flags & USE_DMA) {
+ mode |= SDHCI_TRNS_DMA;
+ sdhci_prepare_dma(host, data, &is_aligned, trans_bytes);
}
-#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
- /*
- * Always use this bounce-buffer when
- * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
- */
- is_aligned = 0;
- start_addr = (unsigned long)aligned_buffer;
- if (data->flags != MMC_DATA_READ)
- memcpy(aligned_buffer, data->src, trans_bytes);
-#endif
-
- sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
- mode |= SDHCI_TRNS_DMA;
-#endif
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
data->blocksize),
SDHCI_BLOCK_SIZE);
@@ -255,12 +343,6 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
}
sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
-#ifdef CONFIG_MMC_SDHCI_SDMA
- if (data) {
- trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE);
- flush_cache(start_addr, trans_bytes);
- }
-#endif
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
start = get_timer(0);
do {
@@ -286,7 +368,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
ret = -1;
if (!ret && data)
- ret = sdhci_transfer_data(host, data, start_addr);
+ ret = sdhci_transfer_data(host, data);
if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
udelay(1000);
@@ -570,6 +652,24 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
__func__);
return -EINVAL;
}
+
+ host->flags |= USE_SDMA;
+#endif
+#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
+ if (!(caps & SDHCI_CAN_DO_ADMA2)) {
+ printf("%s: Your controller doesn't support SDMA!!\n",
+ __func__);
+ return -EINVAL;
+ }
+ host->adma_desc_table = (struct sdhci_adma_desc *)
+ memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ);
+
+ host->adma_addr = (dma_addr_t)host->adma_desc_table;
+#ifdef CONFIG_DMA_ADDR_T_64BIT
+ host->flags |= USE_ADMA64;
+#else
+ host->flags |= USE_ADMA;
+#endif
#endif
if (host->quirks & SDHCI_QUIRK_REG32_RW)
host->version =
diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h
index 58ce3d65b0..51607de142 100644
--- a/drivers/mmc/tmio-common.h
+++ b/drivers/mmc/tmio-common.h
@@ -139,6 +139,10 @@ struct tmio_sd_priv {
#if CONFIG_IS_ENABLED(RENESAS_SDHI)
u8 tap_set;
u8 nrtaps;
+ bool needs_adjust_hs400;
+ bool adjust_hs400_enable;
+ u8 adjust_hs400_offset;
+ u8 adjust_hs400_calibrate;
#endif
ulong (*clk_get_rate)(struct tmio_sd_priv *);
};
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index e6a84a52b4..cfa9b535c8 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -730,43 +730,6 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1;
}
-static void nand_flash_init(void)
-{
- /* This is for DM6446 EVM and *very* similar. DO NOT GROW THIS!
- * Instead, have your board_init() set EMIF timings, based on its
- * knowledge of the clocks and what devices are hooked up ... and
- * don't even do that unless no UBL handled it.
- */
-#ifdef CONFIG_SOC_DM644X
- u_int32_t acfg1 = 0x3ffffffc;
-
- /*------------------------------------------------------------------*
- * NAND FLASH CHIP TIMEOUT @ 459 MHz *
- * *
- * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz *
- * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns *
- * *
- *------------------------------------------------------------------*/
- acfg1 = 0
- | (0 << 31) /* selectStrobe */
- | (0 << 30) /* extWait */
- | (1 << 26) /* writeSetup 10 ns */
- | (3 << 20) /* writeStrobe 40 ns */
- | (1 << 17) /* writeHold 10 ns */
- | (1 << 13) /* readSetup 10 ns */
- | (5 << 7) /* readStrobe 60 ns */
- | (1 << 4) /* readHold 10 ns */
- | (3 << 2) /* turnAround ?? ns */
- | (0 << 0) /* asyncSize 8-bit bus */
- ;
-
- __raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */
-
- /* NAND flash on CS2 */
- __raw_writel(0x00000101, &davinci_emif_regs->nandfcr);
-#endif
-}
-
void davinci_nand_init(struct nand_chip *nand)
{
#if defined CONFIG_KEYSTONE_RBL_NAND
@@ -820,8 +783,6 @@ void davinci_nand_init(struct nand_chip *nand)
nand->write_buf = nand_davinci_write_buf;
nand->dev_ready = nand_davinci_dev_ready;
-
- nand_flash_init();
}
int board_nand_init(struct nand_chip *chip) __attribute__((weak));
diff --git a/drivers/mtd/nand/raw/fsl_elbc_spl.c b/drivers/mtd/nand/raw/fsl_elbc_spl.c
index 30c3308940..099d86427c 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_spl.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_spl.c
@@ -14,6 +14,10 @@
#include <asm/fsl_lbc.h>
#include <nand.h>
+#ifdef CONFIG_MPC83xx
+#include "../../../arch/powerpc/cpu/mpc83xx/elbc/elbc.h"
+#endif
+
#define WINDOW_SIZE 8192
static void nand_wait(void)
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index be4ee2c7f8..b93d77a395 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -50,7 +50,7 @@ struct nand_ecclayout fake_ecc_layout;
/*
* Cache management functions
*/
-#ifndef CONFIG_SYS_DCACHE_OFF
+#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
static void mxs_nand_flush_data_buf(struct mxs_nand_info *info)
{
uint32_t addr = (uint32_t)info->data_buf;
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index c4e2f6a08f..1acff745d1 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -116,7 +116,6 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(len, buf, 1));
- size_t remaining = len;
int ret;
/* get transfer protocols. */
@@ -127,22 +126,16 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
op.addr.nbytes = 0;
- while (remaining) {
- op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
- ret = spi_mem_adjust_op_size(nor->spi, &op);
- if (ret)
- return ret;
-
- ret = spi_mem_exec_op(nor->spi, &op);
- if (ret)
- return ret;
+ ret = spi_mem_adjust_op_size(nor->spi, &op);
+ if (ret)
+ return ret;
+ op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
- op.addr.val += op.data.nbytes;
- remaining -= op.data.nbytes;
- op.data.buf.out += op.data.nbytes;
- }
+ ret = spi_mem_exec_op(nor->spi, &op);
+ if (ret)
+ return ret;
- return len;
+ return op.data.nbytes;
}
/*
@@ -1101,10 +1094,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
goto write_err;
*retlen += written;
i += written;
- if (written != page_remain) {
- ret = -EIO;
- goto write_err;
- }
}
write_err:
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index cf84783356..2b17eae947 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -9,7 +9,6 @@ config CONFIG_UBI_SILENCE_MSG
config MTD_UBI
bool "Enable UBI - Unsorted block images"
- select CRC32
select RBTREE
select MTD_PARTITIONS
help
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6e436b56ab..e6a4fdf30e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -195,6 +195,12 @@ config FEC_MXC
This driver supports the 10/100 Fast Ethernet controller for
NXP i.MX processors.
+config FMAN_ENET
+ bool "Freescale FMan ethernet support"
+ depends on ARM || PPC
+ help
+ This driver support the Freescale FMan Ethernet controller
+
config FTMAC100
bool "Ftmac100 Ethernet Support"
help
@@ -269,7 +275,7 @@ config MACB_ZYNQ
config MT7628_ETH
bool "MediaTek MT7628 Ethernet Interface"
- depends on ARCH_MT7620
+ depends on SOC_MT7628
help
The MediaTek MT7628 ethernet interface is used on MT7628 and
MT7688 based boards.
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 9f1c5af46e..590e756f5c 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -241,7 +241,7 @@ struct eqos_tegra186_regs {
*/
#if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN
#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \
- !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86)
+ !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86)
#warning Cache line size is larger than descriptor size
#endif
#endif
diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c
index e19d7777dc..0a43dfe74e 100644
--- a/drivers/net/fm/fm.c
+++ b/drivers/net/fm/fm.c
@@ -459,7 +459,7 @@ int fm_init_common(int index, struct ccsr_fman *reg)
printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
CONFIG_SYS_FMAN_FW_ADDR, rc);
}
-#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
+#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_SPIFLASH)
struct spi_flash *ucode_flash;
void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
int ret = 0;
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
index c01ae758c7..26a6121175 100644
--- a/drivers/net/gmac_rockchip.c
+++ b/drivers/net/gmac_rockchip.c
@@ -11,15 +11,15 @@
#include <phy.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/periph.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/grf_rk322x.h>
-#include <asm/arch/grf_rk3288.h>
-#include <asm/arch/grf_rk3328.h>
-#include <asm/arch/grf_rk3368.h>
-#include <asm/arch/grf_rk3399.h>
-#include <asm/arch/grf_rv1108.h>
+#include <asm/arch-rockchip/periph.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_rk322x.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rockchip/grf_rk3328.h>
+#include <asm/arch-rockchip/grf_rk3368.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/grf_rv1108.h>
#include <dm/pinctrl.h>
#include <dt-bindings/clock/rk3288-cru.h>
#include "designware.h"
diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c
index 73b7ba29df..34253e3924 100644
--- a/drivers/net/ldpaa_eth/ldpaa_eth.c
+++ b/drivers/net/ldpaa_eth/ldpaa_eth.c
@@ -1074,6 +1074,7 @@ int ldpaa_eth_init(int dpmac_id, phy_interface_t enet_if)
priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv));
if (!priv) {
printf("ldpaa_eth_priv malloc() failed\n");
+ free(net_dev);
return -ENOMEM;
}
memset(priv, 0, sizeof(struct ldpaa_eth_priv));
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 72614164e9..c5560a7111 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -488,15 +488,58 @@ static int macb_phy_find(struct macb_device *macb, const char *name)
/**
* macb_linkspd_cb - Linkspeed change callback function
- * @regs: Base Register of MACB devices
+ * @dev/@regs: MACB udevice (DM version) or
+ * Base Register of MACB devices (non-DM version)
* @speed: Linkspeed
* Returns 0 when operation success and negative errno number
* when operation failed.
*/
+#ifdef CONFIG_DM_ETH
+int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed)
+{
+#ifdef CONFIG_CLK
+ struct clk tx_clk;
+ ulong rate;
+ int ret;
+
+ /*
+ * "tx_clk" is an optional clock source for MACB.
+ * Ignore if it does not exist in DT.
+ */
+ ret = clk_get_by_name(dev, "tx_clk", &tx_clk);
+ if (ret)
+ return 0;
+
+ switch (speed) {
+ case _10BASET:
+ rate = 2500000; /* 2.5 MHz */
+ break;
+ case _100BASET:
+ rate = 25000000; /* 25 MHz */
+ break;
+ case _1000BASET:
+ rate = 125000000; /* 125 MHz */
+ break;
+ default:
+ /* does not change anything */
+ return 0;
+ }
+
+ if (tx_clk.dev) {
+ ret = clk_set_rate(&tx_clk, rate);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+#else
int __weak macb_linkspd_cb(void *regs, unsigned int speed)
{
return 0;
}
+#endif
#ifdef CONFIG_DM_ETH
static int macb_phy_init(struct udevice *dev, const char *name)
@@ -589,7 +632,11 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
macb_writel(macb, NCFGR, ncfgr);
+#ifdef CONFIG_DM_ETH
+ ret = macb_linkspd_cb(dev, _1000BASET);
+#else
ret = macb_linkspd_cb(macb->regs, _1000BASET);
+#endif
if (ret)
return ret;
@@ -614,9 +661,17 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE));
if (speed) {
ncfgr |= MACB_BIT(SPD);
+#ifdef CONFIG_DM_ETH
+ ret = macb_linkspd_cb(dev, _100BASET);
+#else
ret = macb_linkspd_cb(macb->regs, _100BASET);
+#endif
} else {
+#ifdef CONFIG_DM_ETH
+ ret = macb_linkspd_cb(dev, _10BASET);
+#else
ret = macb_linkspd_cb(macb->regs, _10BASET);
+#endif
}
if (ret)
diff --git a/drivers/net/mscc_eswitch/Kconfig b/drivers/net/mscc_eswitch/Kconfig
index 6359d0b610..80dd22f98b 100644
--- a/drivers/net/mscc_eswitch/Kconfig
+++ b/drivers/net/mscc_eswitch/Kconfig
@@ -29,3 +29,10 @@ config MSCC_SERVALT_SWITCH
select PHYLIB
help
This driver supports the Servalt network switch device.
+
+config MSCC_SERVAL_SWITCH
+ bool "Serval switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Serval network switch device.
diff --git a/drivers/net/mscc_eswitch/Makefile b/drivers/net/mscc_eswitch/Makefile
index bffd8ec77b..02f39a76bb 100644
--- a/drivers/net/mscc_eswitch/Makefile
+++ b/drivers/net/mscc_eswitch/Makefile
@@ -1,5 +1,6 @@
-obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
-obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
+obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o
+obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o
obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o
obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o
+obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o
diff --git a/drivers/net/mscc_eswitch/luton_switch.c b/drivers/net/mscc_eswitch/luton_switch.c
index 6667614966..94852b06e7 100644
--- a/drivers/net/mscc_eswitch/luton_switch.c
+++ b/drivers/net/mscc_eswitch/luton_switch.c
@@ -15,10 +15,21 @@
#include <net.h>
#include <wait_bit.h>
-#include "mscc_miim.h"
#include "mscc_xfer.h"
#include "mscc_mac_table.h"
+#define GCB_MIIM_MII_STATUS 0x0
+#define GCB_MIIM_STAT_BUSY BIT(3)
+#define GCB_MIIM_MII_CMD 0x8
+#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
+#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
+#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
+#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
+#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
+#define GCB_MIIM_MII_CMD_VLD BIT(31)
+#define GCB_MIIM_DATA 0xC
+#define GCB_MIIM_DATA_ERROR (0x2 << 16)
+
#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
@@ -136,61 +147,53 @@
#define PGID_UNICAST 29
#define PGID_SRC 80
-enum luton_target {
- PORT0,
- PORT1,
- PORT2,
- PORT3,
- PORT4,
- PORT5,
- PORT6,
- PORT7,
- PORT8,
- PORT9,
- PORT10,
- PORT11,
- PORT12,
- PORT13,
- PORT14,
- PORT15,
- PORT16,
- PORT17,
- PORT18,
- PORT19,
- PORT20,
- PORT21,
- PORT22,
- PORT23,
- SYS,
+static const char * const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+ "port8", "port9", "port10", "port11", "port12", "port13", "port14",
+ "port15", "port16", "port17", "port18", "port19", "port20", "port21",
+ "port22", "port23",
+ "sys", "ana", "rew", "gcb", "qs", "hsio",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 24
+
+enum luton_ctrl_regs {
+ SYS = MAX_PORT,
ANA,
REW,
GCB,
QS,
- HSIO,
- TARGET_MAX,
+ HSIO
};
-#define MAX_PORT (PORT23 - PORT0 + 1)
+#define MIN_INT_PORT 0
+#define PORT10 10
+#define PORT11 11
+#define MAX_INT_PORT 12
+#define MIN_EXT_PORT MAX_INT_PORT
+#define MAX_EXT_PORT MAX_PORT
-#define MIN_INT_PORT PORT0
-#define MAX_INT_PORT (PORT11 - PORT0 + 1)
-#define MIN_EXT_PORT PORT12
-#define MAX_EXT_PORT MAX_PORT
+#define LUTON_MIIM_BUS_COUNT 2
-enum luton_mdio_target {
- MIIM,
- TARGET_MDIO_MAX,
+struct luton_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
};
-enum luton_phy_id {
- INTERNAL,
- EXTERNAL,
- NUM_PHY,
+struct luton_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
+ struct luton_phy_port_t ports[MAX_PORT];
};
-struct luton_private {
- void __iomem *regs[TARGET_MAX];
- struct mii_dev *bus[NUM_PHY];
+struct mscc_miim_dev {
+ void __iomem *regs;
+ phys_addr_t miim_base;
+ unsigned long miim_size;
+ struct mii_dev *bus;
};
static const unsigned long luton_regs_qs[] = {
@@ -207,53 +210,85 @@ static const unsigned long luton_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
};
-static struct mscc_miim_dev miim[NUM_PHY];
+static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
+static int miim_count = -1;
-static struct mii_dev *luton_mdiobus_init(struct udevice *dev,
- int mdiobus_id)
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+ return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+ GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ u32 val;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+ miim->regs + GCB_MIIM_MII_CMD);
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ val = readl(miim->regs + GCB_MIIM_DATA);
+ if (val & GCB_MIIM_DATA_ERROR) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = val & 0xFFFF;
+ out:
+ return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret < 0)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+ GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+ out:
+ return ret;
+}
+
+static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
+ unsigned long miim_size)
{
- unsigned long phy_size[NUM_PHY];
- phys_addr_t phy_base[NUM_PHY];
- struct ofnode_phandle_args phandle;
- ofnode eth_node, node, mdio_node;
- struct resource res;
struct mii_dev *bus;
- fdt32_t faddr;
- int i;
bus = mdio_alloc();
if (!bus)
return NULL;
- /* gather only the first mdio bus */
- eth_node = dev_read_first_subnode(dev);
- node = ofnode_first_subnode(eth_node);
- ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
- &phandle);
- mdio_node = ofnode_get_parent(phandle.node);
-
- for (i = 0; i < TARGET_MDIO_MAX; i++) {
- if (ofnode_read_resource(mdio_node, i, &res)) {
- pr_err("%s: get OF resource failed\n", __func__);
- return NULL;
- }
-
- faddr = cpu_to_fdt32(res.start);
- phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
- phy_size[i] = res.end - res.start;
- }
+ ++miim_count;
+ sprintf(bus->name, "miim-bus%d", miim_count);
- strcpy(bus->name, "miim-internal");
- miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id],
- phy_size[mdiobus_id]);
- bus->priv = &miim[mdiobus_id];
+ miim[miim_count].regs = ioremap(miim_base, miim_size);
+ miim[miim_count].miim_base = miim_base;
+ miim[miim_count].miim_size = miim_size;
+ bus->priv = &miim[miim_count];
bus->read = mscc_miim_read;
bus->write = mscc_miim_write;
if (mdio_register(bus))
return NULL;
- else
- return bus;
+
+ miim[miim_count].bus = bus;
+ return bus;
}
static void luton_stop(struct udevice *dev)
@@ -324,10 +359,10 @@ static void luton_gmii_port_init(struct luton_private *priv, int port)
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
- priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable switching to/from port */
- setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
SYS_SWITCH_PORT_MODE_PORT_ENA);
}
@@ -346,10 +381,10 @@ static void luton_port_init(struct luton_private *priv, int port)
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
- priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable switching to/from port */
- setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
SYS_SWITCH_PORT_MODE_PORT_ENA);
}
@@ -393,35 +428,34 @@ static void luton_ext_port_init(struct luton_private *priv, int port)
writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID,
- priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+ priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable switching to/from port */
- setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+ setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
SYS_SWITCH_PORT_MODE_PORT_ENA);
}
-static void serdes6g_write(struct luton_private *priv, u32 addr)
+static void serdes6g_write(void __iomem *base, u32 addr)
{
u32 data;
writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
HSIO_MCB_SERDES6G_CFG_ADDR(addr),
- priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
+ base + HSIO_MCB_SERDES6G_CFG);
do {
- data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
+ data = readl(base + HSIO_MCB_SERDES6G_CFG);
} while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
-
- mdelay(100);
}
-static void serdes6g_cfg(struct luton_private *priv)
+static void serdes6g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
{
writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
HSIO_RCOMP_CFG_CFG0_RUN_CAL,
- priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0);
+ base + HSIO_RCOMP_CFG_CFG0);
- while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) &
+ while (readl(base + HSIO_RCOMP_STATUS) &
HSIO_RCOMP_STATUS_BUSY)
;
@@ -430,50 +464,64 @@ static void serdes6g_cfg(struct luton_private *priv)
HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG);
+ base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
+ base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG);
+ base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
+ base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG);
+ base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
+ base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+ base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
/*
* There are 4 serdes6g, configure all except serdes6g0, therefore
* the address is b1110
*/
- serdes6g_write(priv, 0xe);
+ serdes6g_write(base, addr);
- writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
+ writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
- priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
- serdes6g_write(priv, 0xe);
+ base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+ serdes6g_write(base, addr);
- clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
+ clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
- priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
- serdes6g_write(priv, 0xe);
+ base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
+ serdes6g_write(base, addr);
+}
+
+static void serdes_setup(struct luton_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
+ }
}
static int luton_switch_init(struct luton_private *priv)
@@ -495,8 +543,8 @@ static int luton_switch_init(struct luton_private *priv)
setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_CORE_ENA);
- /* Setup the Serdes6g macros */
- serdes6g_cfg(priv);
+ /* Setup the Serdes macros */
+ serdes_setup(priv);
return 0;
}
@@ -525,7 +573,7 @@ static int luton_initialize(struct luton_private *priv)
writel(2000000000 / 4,
priv->regs[SYS] + SYS_FRM_AGING);
- for (i = PORT0; i < MAX_PORT; i++) {
+ for (i = 0; i < MAX_PORT; i++) {
if (i < PORT10)
luton_gmii_port_init(priv, i);
else
@@ -608,56 +656,51 @@ static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
return byte_cnt;
}
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct luton_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
static int luton_probe(struct udevice *dev)
{
struct luton_private *priv = dev_get_priv(dev);
- int i;
-
- struct {
- enum luton_target id;
- char *name;
- } reg[] = {
- { PORT0, "port0" },
- { PORT1, "port1" },
- { PORT2, "port2" },
- { PORT3, "port3" },
- { PORT4, "port4" },
- { PORT5, "port5" },
- { PORT6, "port6" },
- { PORT7, "port7" },
- { PORT8, "port8" },
- { PORT9, "port9" },
- { PORT10, "port10" },
- { PORT11, "port11" },
- { PORT12, "port12" },
- { PORT13, "port13" },
- { PORT14, "port14" },
- { PORT15, "port15" },
- { PORT16, "port16" },
- { PORT17, "port17" },
- { PORT18, "port18" },
- { PORT19, "port19" },
- { PORT20, "port20" },
- { PORT21, "port21" },
- { PORT22, "port22" },
- { PORT23, "port23" },
- { SYS, "sys" },
- { ANA, "ana" },
- { REW, "rew" },
- { GCB, "gcb" },
- { QS, "qs" },
- { HSIO, "hsio" },
- };
+ int i, ret;
+ struct resource res;
+ fdt32_t faddr;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
if (!priv)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(reg); i++) {
- priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
- if (!priv->regs[reg[i].id]) {
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
debug
("Error can't get regs base addresses for %s\n",
- reg[i].name);
+ regs_names[i]);
return -ENOMEM;
}
}
@@ -666,7 +709,7 @@ static int luton_probe(struct udevice *dev)
writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
/* Ports with ext phy don't need to reset clk */
- for (i = PORT0; i < MAX_INT_PORT; i++) {
+ for (i = 0; i < MAX_INT_PORT; i++) {
if (i < PORT10)
clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
DEV_GMII_PORT_MODE_CLK_PHY_RST);
@@ -680,20 +723,76 @@ static int luton_probe(struct udevice *dev)
GCB_MISC_STAT_PHY_READY, true, 500, false))
return -EACCES;
- priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL);
- for (i = 0; i < MAX_INT_PORT; i++) {
- phy_connect(priv->bus[INTERNAL], i, dev,
- PHY_INTERFACE_MODE_NONE);
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+ 0, 0, &phandle);
+ if (ret)
+ continue;
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+ faddr = cpu_to_fdt32(res.start);
+
+ addr_base = ofnode_translate_address(mdio_node, &faddr);
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ serval_mdiobus_init(addr_base, addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
+ else
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy && i >= MAX_INT_PORT)
+ board_phy_config(phy);
}
/*
* coma_mode is need on only one phy, because all the other phys
* will be affected.
*/
- mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10);
- mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800);
- mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0);
+ mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
+ mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
+ mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
return 0;
}
@@ -703,7 +802,7 @@ static int luton_remove(struct udevice *dev)
struct luton_private *priv = dev_get_priv(dev);
int i;
- for (i = 0; i < NUM_PHY; i++) {
+ for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
mdio_unregister(priv->bus[i]);
mdio_free(priv->bus[i]);
}
diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c
index 815c2da264..5c7e6961be 100644
--- a/drivers/net/mscc_eswitch/ocelot_switch.c
+++ b/drivers/net/mscc_eswitch/ocelot_switch.c
@@ -15,7 +15,6 @@
#include <net.h>
#include <wait_bit.h>
-#include "mscc_miim.h"
#include "mscc_xfer.h"
#include "mscc_mac_table.h"
@@ -26,6 +25,20 @@
#define PHY_STAT 0x4
#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
+#define GCB_MIIM_MII_STATUS 0x0
+#define GCB_MIIM_STAT_BUSY BIT(3)
+#define GCB_MIIM_MII_CMD 0x8
+#define GCB_MIIM_MII_CMD_SCAN BIT(0)
+#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
+#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
+#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3)
+#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
+#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
+#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
+#define GCB_MIIM_MII_CMD_VLD BIT(31)
+#define GCB_MIIM_DATA 0xC
+#define GCB_MIIM_DATA_ERROR (0x3 << 16)
+
#define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x))
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
@@ -33,6 +46,41 @@
#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
#define ANA_PGID(x) (0x8c00 + 4 * (x))
+#define HSIO_ANA_SERDES1G_DES_CFG 0x4c
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
+#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG 0x50
+#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
+#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG 0x54
+#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
+#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG 0x58
+#define HSIO_ANA_SERDES1G_COMMON_CFG 0x5c
+#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG 0x60
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0 0x68
+#define HSIO_DIG_SERDES1G_MISC_CFG 0x7c
+#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES1G_CFG 0x88
+#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
+#define HSIO_HW_CFGSTAT_HW_CFG 0x10c
+
#define SYS_FRM_AGING 0x574
#define SYS_FRM_AGING_ENA BIT(20)
@@ -83,49 +131,58 @@
#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
#define IFH_INJ_BYPASS BIT(31)
-#define IFH_TAG_TYPE_C 0
-#define MAC_VID 1
+#define IFH_TAG_TYPE_C 0
+#define MAC_VID 1
#define CPU_PORT 11
-#define INTERNAL_PORT_MSK 0xF
+#define INTERNAL_PORT_MSK 0x2FF
#define IFH_LEN 4
#define ETH_ALEN 6
-#define PGID_BROADCAST 13
-#define PGID_UNICAST 14
-#define PGID_SRC 80
+#define PGID_BROADCAST 13
+#define PGID_UNICAST 14
+#define PGID_SRC 80
-enum ocelot_target {
- ANA,
- QS,
- QSYS,
+static const char * const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+ "port8", "port9", "port10", "sys", "rew", "qs", "hsio", "qsys", "ana",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 11
+
+enum ocelot_ctrl_regs {
+ SYS = MAX_PORT,
REW,
- SYS,
+ QS,
HSIO,
- PORT0,
- PORT1,
- PORT2,
- PORT3,
- TARGET_MAX,
+ QSYS,
+ ANA,
};
-#define MAX_PORT (PORT3 - PORT0)
+#define OCELOT_MIIM_BUS_COUNT 2
-enum ocelot_mdio_target {
- MIIM,
- PHY,
- TARGET_MDIO_MAX,
+struct ocelot_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
};
-enum ocelot_phy_id {
- INTERNAL,
- EXTERNAL,
- NUM_PHY,
+struct ocelot_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[OCELOT_MIIM_BUS_COUNT];
+ struct ocelot_phy_port_t ports[MAX_PORT];
};
-struct ocelot_private {
- void __iomem *regs[TARGET_MAX];
- struct mii_dev *bus[NUM_PHY];
+struct mscc_miim_dev {
+ void __iomem *regs;
+ phys_addr_t miim_base;
+ unsigned long miim_size;
+ struct mii_dev *bus;
};
+static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
static const unsigned long ocelot_regs_qs[] = {
[MSCC_QS_XTR_RD] = 0x8,
[MSCC_QS_XTR_FLUSH] = 0x18,
@@ -140,65 +197,95 @@ static const unsigned long ocelot_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACACCESS] = 0x8b3c,
};
-static struct mscc_miim_dev miim[NUM_PHY];
-
static void mscc_phy_reset(void)
{
- writel(0, miim[INTERNAL].phy_regs + PHY_CFG);
+ writel(0, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
- | PHY_CFG_ENA, miim[INTERNAL].phy_regs + PHY_CFG);
- if (wait_for_bit_le32(miim[INTERNAL].phy_regs + PHY_STAT,
- PHY_STAT_SUPERVISOR_COMPLETE,
+ | PHY_CFG_ENA, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
+ if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + PERF_PHY_CFG) +
+ PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE,
true, 2000, false)) {
pr_err("Timeout in phy reset\n");
}
}
-/* For now only setup the internal mdio bus */
-static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+ return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+ GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ u32 val;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+ miim->regs + GCB_MIIM_MII_CMD);
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ val = readl(miim->regs + GCB_MIIM_DATA);
+ if (val & GCB_MIIM_DATA_ERROR) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = val & 0xFFFF;
+ out:
+ return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret < 0)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+ GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+ out:
+ return ret;
+}
+
+static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base,
+ unsigned long miim_size)
{
- unsigned long phy_size[TARGET_MAX];
- phys_addr_t phy_base[TARGET_MAX];
- struct ofnode_phandle_args phandle;
- ofnode eth_node, node, mdio_node;
- struct resource res;
struct mii_dev *bus;
- fdt32_t faddr;
- int i;
bus = mdio_alloc();
if (!bus)
return NULL;
- /* gathered only the first mdio bus */
- eth_node = dev_read_first_subnode(dev);
- node = ofnode_first_subnode(eth_node);
- ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
- &phandle);
- mdio_node = ofnode_get_parent(phandle.node);
-
- for (i = 0; i < TARGET_MDIO_MAX; i++) {
- if (ofnode_read_resource(mdio_node, i, &res)) {
- pr_err("%s: get OF resource failed\n", __func__);
- return NULL;
- }
- faddr = cpu_to_fdt32(res.start);
- phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
- phy_size[i] = res.end - res.start;
- }
+ ++miim_count;
+ sprintf(bus->name, "miim-bus%d", miim_count);
- strcpy(bus->name, "miim-internal");
- miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
- miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
- bus->priv = &miim[INTERNAL];
+ miim[miim_count].regs = ioremap(miim_base, miim_size);
+ miim[miim_count].miim_base = miim_base;
+ miim[miim_count].miim_size = miim_size;
+ bus->priv = &miim[miim_count];
bus->read = mscc_miim_read;
bus->write = mscc_miim_write;
if (mdio_register(bus))
return NULL;
- else
- return bus;
+
+ miim[miim_count].bus = bus;
+ return bus;
}
__weak void mscc_switch_reset(void)
@@ -291,13 +378,87 @@ static void ocelot_port_init(struct ocelot_private *priv, int port)
/* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
- MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable the port in the core */
- setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0),
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
QSYS_SWITCH_PORT_MODE_PORT_ENA);
}
+static void serdes1g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES1G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES1G_CFG);
+ } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(0x34, base + HSIO_HW_CFGSTAT_HW_CFG);
+
+ writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+ writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
+ HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+ HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+ base + HSIO_ANA_SERDES1G_IB_CFG);
+ writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+ HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+ HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES1G_DES_CFG);
+ writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+ HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+ HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+ HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+ base + HSIO_ANA_SERDES1G_OB_CFG);
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
+ HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+ base + HSIO_ANA_SERDES1G_PLL_CFG);
+ writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES1G_MISC_CFG);
+
+ serdes1g_write(base, addr);
+
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ serdes1g_write(base, addr);
+
+ writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
+ serdes1g_write(base, addr);
+}
+
+static void serdes_setup(struct ocelot_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ serdes1g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ }
+}
+
static int ocelot_switch_init(struct ocelot_private *priv)
{
/* Reset switch & memories */
@@ -315,6 +476,7 @@ static int ocelot_switch_init(struct ocelot_private *priv)
setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_CORE_ENA);
+ serdes_setup(priv);
return 0;
}
@@ -331,7 +493,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
* Put fron ports in "port isolation modes" - i.e. they cant send
* to other ports - via the PGID sorce masks.
*/
- for (i = 0; i <= MAX_PORT; i++)
+ for (i = 0; i < MAX_PORT; i++)
writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
/* Flush queues */
@@ -341,7 +503,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
writel(SYS_FRM_AGING_ENA | (20000000 / 65),
priv->regs[SYS] + SYS_FRM_AGING);
- for (i = PORT0; i <= PORT3; i++)
+ for (i = 0; i < MAX_PORT; i++)
ocelot_port_init(priv, i);
ocelot_cpu_capture_setup(priv);
@@ -433,43 +595,119 @@ static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
return byte_cnt;
}
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < OCELOT_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct ocelot_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int external_bus(struct ocelot_private *priv, size_t port_index)
+{
+ return priv->ports[port_index].serdes_index != 0xff;
+}
+
static int ocelot_probe(struct udevice *dev)
{
struct ocelot_private *priv = dev_get_priv(dev);
- int ret, i;
+ int i, ret;
+ struct resource res;
+ fdt32_t faddr;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+
+ if (!priv)
+ return -EINVAL;
- struct {
- enum ocelot_target id;
- char *name;
- } reg[] = {
- { SYS, "sys" },
- { REW, "rew" },
- { QSYS, "qsys" },
- { ANA, "ana" },
- { QS, "qs" },
- { HSIO, "hsio" },
- { PORT0, "port0" },
- { PORT1, "port1" },
- { PORT2, "port2" },
- { PORT3, "port3" },
- };
-
- for (i = 0; i < ARRAY_SIZE(reg); i++) {
- priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
- if (!priv->regs[reg[i].id]) {
- pr_err
- ("Error %d: can't get regs base addresses for %s\n",
- ret, reg[i].name);
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
return -ENOMEM;
}
}
- priv->bus[INTERNAL] = ocelot_mdiobus_init(dev);
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(struct mscc_miim_dev) *
+ OCELOT_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node); ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
+ &phandle);
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+ faddr = cpu_to_fdt32(res.start);
+
+ addr_base = ofnode_translate_address(mdio_node, &faddr);
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ ocelot_mdiobus_init(addr_base, addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
+ else
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
mscc_phy_reset();
- for (i = 0; i < 4; i++) {
- phy_connect(priv->bus[INTERNAL], i, dev,
- PHY_INTERFACE_MODE_NONE);
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy && external_bus(priv, i))
+ board_phy_config(phy);
}
return 0;
@@ -480,7 +718,7 @@ static int ocelot_remove(struct udevice *dev)
struct ocelot_private *priv = dev_get_priv(dev);
int i;
- for (i = 0; i < NUM_PHY; i++) {
+ for (i = 0; i < OCELOT_MIIM_BUS_COUNT; i++) {
mdio_unregister(priv->bus[i]);
mdio_free(priv->bus[i]);
}
diff --git a/drivers/net/mscc_eswitch/serval_switch.c b/drivers/net/mscc_eswitch/serval_switch.c
new file mode 100644
index 0000000000..2559f5d0cd
--- /dev/null
+++ b/drivers/net/mscc_eswitch/serval_switch.c
@@ -0,0 +1,703 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+#include "mscc_mac_table.h"
+
+#define GCB_MIIM_MII_STATUS 0x0
+#define GCB_MIIM_STAT_BUSY BIT(3)
+#define GCB_MIIM_MII_CMD 0x8
+#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
+#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
+#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
+#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
+#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
+#define GCB_MIIM_MII_CMD_VLD BIT(31)
+#define GCB_MIIM_DATA 0xC
+#define GCB_MIIM_DATA_ERROR (0x2 << 16)
+
+#define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x))
+#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
+#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
+#define ANA_PORT_PORT_CFG(x) (0xc070 + 0x100 * (x))
+#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
+#define ANA_PGID(x) (0x9c00 + 4 * (x))
+
+#define HSIO_ANA_SERDES1G_DES_CFG 0x3c
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
+#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG 0x40
+#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
+#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19)
+#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG 0x44
+#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
+#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG 0x48
+#define HSIO_ANA_SERDES1G_COMMON_CFG 0x4c
+#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG 0x50
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0 0x58
+#define HSIO_DIG_SERDES1G_MISC_CFG 0x6c
+#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES1G_CFG 0x74
+#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
+
+#define SYS_FRM_AGING 0x584
+#define SYS_FRM_AGING_ENA BIT(20)
+#define SYS_SYSTEM_RST_CFG 0x518
+#define SYS_SYSTEM_RST_MEM_INIT BIT(5)
+#define SYS_SYSTEM_RST_MEM_ENA BIT(6)
+#define SYS_SYSTEM_RST_CORE_ENA BIT(7)
+#define SYS_PORT_MODE(x) (0x524 + 0x4 * (x))
+#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 4)
+#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 2)
+#define SYS_PAUSE_CFG(x) (0x65c + 0x4 * (x))
+#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
+
+#define QSYS_SWITCH_PORT_MODE(x) (0x15a34 + 0x4 * (x))
+#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(13)
+#define QSYS_EGR_NO_SHARING 0x15a9c
+#define QSYS_QMAP 0x15adc
+
+/* Port registers */
+#define DEV_CLOCK_CFG 0x0
+#define DEV_CLOCK_CFG_LINK_SPEED_1000 1
+#define DEV_MAC_ENA_CFG 0x10
+#define DEV_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV_MAC_ENA_CFG_TX_ENA BIT(0)
+#define DEV_MAC_IFG_CFG 0x24
+#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x)
+#define PCS1G_CFG 0x3c
+#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
+#define PCS1G_MODE_CFG 0x40
+#define PCS1G_SD_CFG 0x44
+#define PCS1G_ANEG_CFG 0x48
+#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16)
+
+#define QS_XTR_GRP_CFG(x) (4 * (x))
+#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2)
+#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2)
+#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
+
+#define IFH_INJ_BYPASS BIT(31)
+#define IFH_TAG_TYPE_C 0
+#define MAC_VID 1
+#define CPU_PORT 11
+#define INTERNAL_PORT_MSK 0xFF
+#define IFH_LEN 4
+#define ETH_ALEN 6
+#define PGID_BROADCAST 13
+#define PGID_UNICAST 14
+
+static const char *const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6",
+ "port7", "port8", "port9", "port10",
+ "ana", "qs", "qsys", "rew", "sys", "hsio",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 11
+
+enum serval_ctrl_regs {
+ ANA = MAX_PORT,
+ QS,
+ QSYS,
+ REW,
+ SYS,
+ HSIO,
+};
+
+#define SERVAL_MIIM_BUS_COUNT 2
+
+struct serval_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
+};
+
+struct serval_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT];
+ struct serval_phy_port_t ports[MAX_PORT];
+};
+
+struct mscc_miim_dev {
+ void __iomem *regs;
+ phys_addr_t miim_base;
+ unsigned long miim_size;
+ struct mii_dev *bus;
+};
+
+static const unsigned long serval_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static const unsigned long serval_regs_ana_table[] = {
+ [MSCC_ANA_TABLES_MACHDATA] = 0x9b34,
+ [MSCC_ANA_TABLES_MACLDATA] = 0x9b38,
+ [MSCC_ANA_TABLES_MACACCESS] = 0x9b3c,
+};
+
+static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+ return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+ GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ u32 val;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+ miim->regs + GCB_MIIM_MII_CMD);
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ val = readl(miim->regs + GCB_MIIM_DATA);
+ if (val & GCB_MIIM_DATA_ERROR) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = val & 0xFFFF;
+ out:
+ return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret < 0)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+ GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+ out:
+ return ret;
+}
+
+static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
+ unsigned long miim_size)
+{
+ struct mii_dev *bus;
+
+ bus = mdio_alloc();
+ if (!bus)
+ return NULL;
+
+ ++miim_count;
+ sprintf(bus->name, "miim-bus%d", miim_count);
+
+ miim[miim_count].regs = ioremap(miim_base, miim_size);
+ miim[miim_count].miim_base = miim_base;
+ miim[miim_count].miim_size = miim_size;
+ bus->priv = &miim[miim_count];
+ bus->read = mscc_miim_read;
+ bus->write = mscc_miim_write;
+
+ if (mdio_register(bus))
+ return NULL;
+
+ miim[miim_count].bus = bus;
+ return bus;
+}
+
+static void serval_cpu_capture_setup(struct serval_private *priv)
+{
+ int i;
+
+ /* map the 8 CPU extraction queues to CPU port 11 */
+ writel(0, priv->regs[QSYS] + QSYS_QMAP);
+
+ for (i = 0; i <= 1; i++) {
+ /*
+ * Do byte-swap and expect status after last data word
+ * Extraction: Mode: manual extraction) | Byte_swap
+ */
+ writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
+ priv->regs[QS] + QS_XTR_GRP_CFG(i));
+ /*
+ * Injection: Mode: manual extraction | Byte_swap
+ */
+ writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
+ priv->regs[QS] + QS_INJ_GRP_CFG(i));
+ }
+
+ for (i = 0; i <= 1; i++)
+ /* Enable IFH insertion/parsing on CPU ports */
+ writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
+ SYS_PORT_MODE_INCL_XTR_HDR(1),
+ priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
+ /*
+ * Setup the CPU port as VLAN aware to support switching frames
+ * based on tags
+ */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
+
+ /* Disable learning (only RECV_ENA must be set) */
+ writel(ANA_PORT_PORT_CFG_RECV_ENA,
+ priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
+
+ /* Enable switching to/from cpu port */
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
+ QSYS_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* No pause on CPU port - not needed (off by default) */
+ clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
+ SYS_PAUSE_CFG_PAUSE_ENA);
+
+ setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
+}
+
+static void serval_port_init(struct serval_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + PCS1G_SD_CFG);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
+ regs + DEV_MAC_ENA_CFG);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + PCS1G_MODE_CFG);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
+ DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+ /* Enable the port in the core */
+ setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
+ QSYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES1G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES1G_CFG);
+ } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+
+ mdelay(100);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+ writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
+ HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+ HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+ base + HSIO_ANA_SERDES1G_IB_CFG);
+ writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+ HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+ HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES1G_DES_CFG);
+ writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+ HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+ HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+ HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+ base + HSIO_ANA_SERDES1G_OB_CFG);
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
+ HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+ base + HSIO_ANA_SERDES1G_PLL_CFG);
+ writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES1G_MISC_CFG);
+ serdes_write(base, addr);
+
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+ serdes_write(base, addr);
+
+ writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
+ serdes_write(base, addr);
+}
+
+static void serdes_setup(struct serval_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ serdes1g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ }
+}
+
+static int serval_switch_init(struct serval_private *priv)
+{
+ /* Reset switch & memories */
+ writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
+ priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
+
+ if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
+ pr_err("Timeout in memory reset\n");
+ return -EIO;
+ }
+
+ /* Enable switch core */
+ setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+ SYS_SYSTEM_RST_CORE_ENA);
+
+ serdes_setup(priv);
+
+ return 0;
+}
+
+static int serval_initialize(struct serval_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = serval_switch_init(priv);
+ if (ret)
+ return ret;
+
+ /* Flush queues */
+ mscc_flush(priv->regs[QS], serval_regs_qs);
+
+ /* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */
+ writel(SYS_FRM_AGING_ENA | (20000000 / 65),
+ priv->regs[SYS] + SYS_FRM_AGING);
+
+ for (i = 0; i < MAX_PORT; i++)
+ serval_port_init(priv, i);
+
+ serval_cpu_capture_setup(priv);
+
+ debug("Ports enabled\n");
+
+ return 0;
+}
+
+static int serval_write_hwaddr(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+ return 0;
+}
+
+static int serval_start(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = serval_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac,
+ PGID_BROADCAST);
+
+ writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
+ priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
+
+ /* It should be setup latter in serval_write_hwaddr */
+ mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
+ pdata->enetaddr, PGID_UNICAST);
+
+ writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+ return 0;
+}
+
+static void serval_stop(struct udevice *dev)
+{
+ writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET);
+ writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
+}
+
+static int serval_send(struct udevice *dev, void *packet, int length)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ u32 *buf = packet;
+
+ /*
+ * Generate the IFH for frame injection
+ *
+ * The IFH is a 128bit-value
+ * bit 127: bypass the analyzer processing
+ * bit 57-67: destination mask
+ * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
+ * bit 20-27: cpu extraction queue mask
+ * bit 16: tag type 0: C-tag, 1: S-tag
+ * bit 0-11: VID
+ */
+ ifh[0] = IFH_INJ_BYPASS;
+ ifh[1] = (0x07);
+ ifh[2] = (0x7f) << 25;
+ ifh[3] = (IFH_TAG_TYPE_C << 16);
+
+ return mscc_send(priv->regs[QS], serval_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int serval_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct serval_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int serval_probe(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ int i, ret;
+ struct resource res;
+ fdt32_t faddr;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+ 0, 0, &phandle);
+ if (ret)
+ continue;
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+ faddr = cpu_to_fdt32(res.start);
+
+ addr_base = ofnode_translate_address(mdio_node, &faddr);
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ serval_mdiobus_init(addr_base, addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ return -ENOMEM;
+
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy)
+ board_phy_config(phy);
+ }
+
+ return 0;
+}
+
+static int serval_remove(struct udevice *dev)
+{
+ struct serval_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops serval_ops = {
+ .start = serval_start,
+ .stop = serval_stop,
+ .send = serval_send,
+ .recv = serval_recv,
+ .write_hwaddr = serval_write_hwaddr,
+};
+
+static const struct udevice_id mscc_serval_ids[] = {
+ {.compatible = "mscc,vsc7418-switch"},
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(serval) = {
+ .name = "serval-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_serval_ids,
+ .probe = serval_probe,
+ .remove = serval_remove,
+ .ops = &serval_ops,
+ .priv_auto_alloc_size = sizeof(struct serval_private),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c
index cc09404830..0ef814c78b 100644
--- a/drivers/net/mtk_eth.c
+++ b/drivers/net/mtk_eth.c
@@ -1130,13 +1130,14 @@ static int mtk_eth_ofdata_to_platdata(struct udevice *dev)
&priv->rst_gpio, GPIOD_IS_OUT);
}
} else {
- subnode = ofnode_find_subnode(dev_ofnode(dev), "phy-handle");
- if (!ofnode_valid(subnode)) {
+ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
+ 0, &args);
+ if (ret) {
printf("error: phy-handle is not specified\n");
return ret;
}
- priv->phy_addr = ofnode_read_s32_default(subnode, "reg", -1);
+ priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
if (priv->phy_addr < 0) {
printf("error: phy address is not specified\n");
return ret;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3dc0822d9c..2a3da068c9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -119,21 +119,19 @@ config PHY_MICREL
bool "Micrel Ethernet PHYs support"
help
Enable support for the GbE PHYs manufactured by Micrel (now
- a part of Microchip). This includes drivers for the KSZ804,
- KSZ8031, KSZ8051, KSZ8081, KSZ8895, KSZ886x, KSZ8721
- either/or KSZ9021 (see the "Micrel KSZ9021 family support"
- config option for details), and KSZ9031 (if configured).
+ a part of Microchip). This includes drivers for the KSZ804, KSZ8031,
+ KSZ8051, KSZ8081, KSZ8895, KSZ886x and KSZ8721 (if "Micrel KSZ8xxx
+ family support" is selected) and the KSZ9021 and KSZ9031 (if "Micrel
+ KSZ90x1 family support" is selected).
if PHY_MICREL
config PHY_MICREL_KSZ9021
bool
- select PHY_GIGE
select PHY_MICREL_KSZ90X1
config PHY_MICREL_KSZ9031
bool
- select PHY_GIGE
select PHY_MICREL_KSZ90X1
config PHY_MICREL_KSZ90X1
@@ -146,20 +144,13 @@ config PHY_MICREL_KSZ90X1
delays configured in the device tree will be applied to the
PHY during initialization.
- This should not be enabled at the same time with PHY_MICREL_KSZ8XXX
- as the KSZ9021 and KS8721 share the same ID.
-
config PHY_MICREL_KSZ8XXX
bool "Micrel KSZ8xxx family support"
- default y if !PHY_MICREL_KSZ90X1
help
- Enable support for the 8000 series GbE PHYs manufactured by Micrel
+ Enable support for the 8000 series 10/100 PHYs manufactured by Micrel
(now a part of Microchip). This includes drivers for the KSZ804,
KSZ8031, KSZ8051, KSZ8081, KSZ8895, KSZ886x, and KSZ8721.
- This should not be enabled at the same time with PHY_MICREL_KSZ90X1
- as the KSZ9021 and KS8721 share the same ID.
-
endif # PHY_MICREL
config PHY_MSCC
@@ -202,6 +193,26 @@ config RTL8211X_PHY_FORCE_MASTER
If unsure, say N.
+config RTL8211F_PHY_FORCE_EEE_RXC_ON
+ bool "Ethernet PHY RTL8211F: do not stop receiving the xMII clock during LPI"
+ depends on PHY_REALTEK
+ default n
+ help
+ The IEEE 802.3az-2010 (EEE) standard provides a protocol to coordinate
+ transitions to/from a lower power consumption level (Low Power Idle
+ mode) based on link utilization. When no packets are being
+ transmitted, the system goes to Low Power Idle mode to save power.
+
+ Under particular circumstances this setting can cause issues where
+ the PHY is unable to transmit or receive any packet when in LPI mode.
+ The problem is caused when the PHY is configured to stop receiving
+ the xMII clock while it is signaling LPI. For some PHYs the bit
+ configuring this behavior is set by the Linux kernel, causing the
+ issue in U-Boot on reboot if the PHY retains the register value.
+
+ Default n, which means that the PHY state is not changed. To work
+ around the issues, change this setting to y.
+
config PHY_SMSC
bool "Microchip(SMSC) Ethernet PHYs support"
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index 12df09877d..5c3298d612 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -303,9 +303,14 @@ int aquantia_config(struct phy_device *phydev)
AQUANTIA_SYSTEM_INTERFACE_SR);
/* If SI is USXGMII then start USXGMII autoneg */
if ((val & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) {
+ reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS,
+ AQUANTIA_VENDOR_PROVISIONING_REG);
+
+ reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA;
+
phy_write(phydev, MDIO_MMD_PHYXS,
AQUANTIA_VENDOR_PROVISIONING_REG,
- AQUANTIA_USX_AUTONEG_CONTROL_ENA);
+ reg_val1);
printf("%s: system interface USXGMII\n",
phydev->dev->name);
} else {
diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c
index 3411150ab9..daa57ce33c 100644
--- a/drivers/net/phy/micrel_ksz8xxx.c
+++ b/drivers/net/phy/micrel_ksz8xxx.c
@@ -147,11 +147,13 @@ static struct phy_driver ksz8895_driver = {
.shutdown = &genphy_shutdown,
};
-/* Micrel used the exact same part number for the KSZ9021. */
+/* Micrel used the exact same model number for the KSZ9021,
+ * so the revision number is used to distinguish them.
+ */
static struct phy_driver KS8721_driver = {
.name = "Micrel KS8721BL",
- .uid = 0x221610,
- .mask = 0xfffff0,
+ .uid = 0x221618,
+ .mask = 0xfffffc,
.features = PHY_BASIC_FEATURES,
.config = &genphy_config,
.startup = &genphy_startup,
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c
index 63e7b0242b..f18e40a2fe 100644
--- a/drivers/net/phy/micrel_ksz90x1.c
+++ b/drivers/net/phy/micrel_ksz90x1.c
@@ -33,10 +33,14 @@
#define CTRL1000_CONFIG_MASTER (1 << 11)
#define CTRL1000_MANUAL_CONFIG (1 << 12)
+#define KSZ9021_PS_TO_REG 120
+
/* KSZ9031 PHY Registers */
#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d
#define MII_KSZ9031_MMD_REG_DATA 0x0e
+#define KSZ9031_PS_TO_REG 60
+
static int ksz90xx_startup(struct phy_device *phydev)
{
unsigned phy_ctl;
@@ -102,20 +106,28 @@ static const struct ksz90x1_reg_field ksz9031_clk_grp[] = {
};
static int ksz90x1_of_config_group(struct phy_device *phydev,
- struct ksz90x1_ofcfg *ofcfg)
+ struct ksz90x1_ofcfg *ofcfg,
+ int ps_to_regval)
{
struct udevice *dev = phydev->dev;
struct phy_driver *drv = phydev->drv;
- const int ps_to_regval = 60;
int val[4];
int i, changed = 0, offset, max;
u16 regval = 0;
+ ofnode node;
if (!drv || !drv->writeext)
return -EOPNOTSUPP;
+ /* Look for a PHY node under the Ethernet node */
+ node = dev_read_subnode(dev, "ethernet-phy");
+ if (!ofnode_valid(node)) {
+ /* No node found, look in the Ethernet node */
+ node = dev_ofnode(dev);
+ }
+
for (i = 0; i < ofcfg->grpsz; i++) {
- val[i] = dev_read_u32_default(dev, ofcfg->grp[i].name, ~0);
+ val[i] = ofnode_read_u32_default(node, ofcfg->grp[i].name, ~0);
offset = ofcfg->grp[i].off;
if (val[i] == -1) {
/* Default register value for KSZ9021 */
@@ -148,7 +160,8 @@ static int ksz9021_of_config(struct phy_device *phydev)
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
- ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
+ ret = ksz90x1_of_config_group(phydev, &ofcfg[i],
+ KSZ9021_PS_TO_REG);
if (ret)
return ret;
}
@@ -167,7 +180,8 @@ static int ksz9031_of_config(struct phy_device *phydev)
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
- ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
+ ret = ksz90x1_of_config_group(phydev, &ofcfg[i],
+ KSZ9031_PS_TO_REG);
if (ret)
return ret;
}
@@ -271,7 +285,7 @@ static int ksz9021_config(struct phy_device *phydev)
static struct phy_driver ksz9021_driver = {
.name = "Micrel ksz9021",
.uid = 0x221610,
- .mask = 0xfffff0,
+ .mask = 0xfffffe,
.features = PHY_GBIT_FEATURES,
.config = &ksz9021_config,
.startup = &ksz90xx_startup,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 4e8d2943ee..c1c1af9abd 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -462,6 +462,18 @@ static LIST_HEAD(phy_drivers);
int phy_init(void)
{
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+ /*
+ * The pointers inside phy_drivers also needs to be updated incase of
+ * manual reloc, without which these points to some invalid
+ * pre reloc address and leads to invalid accesses, hangs.
+ */
+ struct list_head *head = &phy_drivers;
+
+ head->next = (void *)head->next + gd->reloc_off;
+ head->prev = (void *)head->prev + gd->reloc_off;
+#endif
+
#ifdef CONFIG_B53_SWITCH
phy_b53_init();
#endif
@@ -549,6 +561,10 @@ int phy_register(struct phy_driver *drv)
drv->readext += gd->reloc_off;
if (drv->writeext)
drv->writeext += gd->reloc_off;
+ if (drv->read_mmd)
+ drv->read_mmd += gd->reloc_off;
+ if (drv->write_mmd)
+ drv->write_mmd += gd->reloc_off;
#endif
return 0;
}
@@ -655,7 +671,10 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
dev->drv = get_phy_driver(dev, interface);
- phy_probe(dev);
+ if (phy_probe(dev)) {
+ printf("%s, PHY probe failed\n", __func__);
+ return NULL;
+ }
if (addr >= 0 && addr < PHY_MAX_ADDR)
bus->phymap[addr] = dev;
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index dd45e11b3a..8f1d759632 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -12,6 +12,7 @@
#define PHY_RTL8211x_FORCE_MASTER BIT(1)
#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
+#define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3)
#define PHY_AUTONEGOTIATE_TIMEOUT 5000
@@ -102,6 +103,15 @@ static int rtl8211e_probe(struct phy_device *phydev)
return 0;
}
+static int rtl8211f_probe(struct phy_device *phydev)
+{
+#ifdef CONFIG_RTL8211F_PHY_FORCE_EEE_RXC_ON
+ phydev->flags |= PHY_RTL8211F_FORCE_EEE_RXC_ON;
+#endif
+
+ return 0;
+}
+
/* RealTek RTL8211x */
static int rtl8211x_config(struct phy_device *phydev)
{
@@ -151,6 +161,14 @@ static int rtl8211f_config(struct phy_device *phydev)
{
u16 reg;
+ if (phydev->flags & PHY_RTL8211F_FORCE_EEE_RXC_ON) {
+ unsigned int reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
+ reg &= ~MDIO_PCS_CTRL1_CLKSTOP_EN;
+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+ }
+
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
phy_write(phydev, MDIO_DEVAD_NONE,
@@ -360,6 +378,7 @@ static struct phy_driver RTL8211F_driver = {
.uid = 0x1cc916,
.mask = 0xffffff,
.features = PHY_GBIT_FEATURES,
+ .probe = &rtl8211f_probe,
.config = &rtl8211f_config,
.startup = &rtl8211f_startup,
.shutdown = &genphy_shutdown,
diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c
index 6db6edd0d0..25f1332ca9 100644
--- a/drivers/net/phy/ti.c
+++ b/drivers/net/phy/ti.c
@@ -73,16 +73,6 @@
#define MII_DP83867_CFG2_SPEEDOPT_INTLOW 0x2000
#define MII_DP83867_CFG2_MASK 0x003F
-#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
-#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
-
-/* MMD Access Control register fields */
-#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
-#define MII_MMD_CTRL_ADDR 0x0000 /* Address */
-#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
-#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
-#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
-
/* User setting - can be taken from DTS */
#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS
#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS
@@ -116,88 +106,20 @@ struct dp83867_private {
int clk_output_sel;
};
-/**
- * phy_read_mmd_indirect - reads data from the MMD registers
- * @phydev: The PHY device bus
- * @prtad: MMD Address
- * @devad: MMD DEVAD
- * @addr: PHY address on the MII bus
- *
- * Description: it reads data from the MMD registers (clause 22 to access to
- * clause 45) of the specified phy address.
- * To read these registers we have:
- * 1) Write reg 13 // DEVAD
- * 2) Write reg 14 // MMD Address
- * 3) Write reg 13 // MMD Data Command for MMD DEVAD
- * 3) Read reg 14 // Read MMD data
- */
-int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
- int devad, int addr)
-{
- int value = -1;
-
- /* Write the desired MMD Devad */
- phy_write(phydev, addr, MII_MMD_CTRL, devad);
-
- /* Write the desired MMD register address */
- phy_write(phydev, addr, MII_MMD_DATA, prtad);
-
- /* Select the Function : DATA with no post increment */
- phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
-
- /* Read the content of the MMD's selected register */
- value = phy_read(phydev, addr, MII_MMD_DATA);
- return value;
-}
-
-/**
- * phy_write_mmd_indirect - writes data to the MMD registers
- * @phydev: The PHY device
- * @prtad: MMD Address
- * @devad: MMD DEVAD
- * @addr: PHY address on the MII bus
- * @data: data to write in the MMD register
- *
- * Description: Write data from the MMD registers of the specified
- * phy address.
- * To write these registers we have:
- * 1) Write reg 13 // DEVAD
- * 2) Write reg 14 // MMD Address
- * 3) Write reg 13 // MMD Data Command for MMD DEVAD
- * 3) Write reg 14 // Write MMD data
- */
-void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
- int devad, int addr, u32 data)
-{
- /* Write the desired MMD Devad */
- phy_write(phydev, addr, MII_MMD_CTRL, devad);
-
- /* Write the desired MMD register address */
- phy_write(phydev, addr, MII_MMD_DATA, prtad);
-
- /* Select the Function : DATA with no post increment */
- phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
-
- /* Write the data into MMD's selected register */
- phy_write(phydev, addr, MII_MMD_DATA, data);
-}
-
static int dp83867_config_port_mirroring(struct phy_device *phydev)
{
struct dp83867_private *dp83867 =
(struct dp83867_private *)phydev->priv;
u16 val;
- val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
- phydev->addr);
+ val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4);
if (dp83867->port_mirroring == DP83867_PORT_MIRRORING_EN)
val |= DP83867_CFG4_PORT_MIRROR_EN;
else
val &= ~DP83867_CFG4_PORT_MIRROR_EN;
- phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
- phydev->addr, val);
+ phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, val);
return 0;
}
@@ -216,6 +138,10 @@ static int dp83867_of_init(struct phy_device *phydev)
/* Optional configuration */
+ node = phy_get_ofnode(phydev);
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
/*
* Keep the default value if ti,clk-output-sel is not set
* or to high
@@ -225,10 +151,6 @@ static int dp83867_of_init(struct phy_device *phydev)
ofnode_read_u32_default(node, "ti,clk-output-sel",
DP83867_CLK_O_SEL_REF_CLK);
- node = phy_get_ofnode(phydev);
- if (!ofnode_valid(node))
- return -EINVAL;
-
if (ofnode_read_bool(node, "ti,max-output-impedance"))
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
else if (ofnode_read_bool(node, "ti,min-output-impedance"))
@@ -257,13 +179,13 @@ static int dp83867_of_init(struct phy_device *phydev)
/* Clock output selection if muxing property is set */
if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) {
- val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
- DP83867_DEVADDR, phydev->addr);
+ val = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG);
val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
val |= (dp83867->clk_output_sel <<
DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT);
- phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
- DP83867_DEVADDR, phydev->addr, val);
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG, val);
}
return 0;
@@ -308,11 +230,11 @@ static int dp83867_config(struct phy_device *phydev)
/* Mode 1 or 2 workaround */
if (dp83867->rxctrl_strap_quirk) {
- val = phy_read_mmd_indirect(phydev, DP83867_CFG4,
- DP83867_DEVADDR, phydev->addr);
+ val = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_CFG4);
val &= ~BIT(7);
- phy_write_mmd_indirect(phydev, DP83867_CFG4,
- DP83867_DEVADDR, phydev->addr, val);
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_CFG4, val);
}
if (phy_interface_is_rgmii(phydev)) {
@@ -332,8 +254,8 @@ static int dp83867_config(struct phy_device *phydev)
* register's bit 11 (marked as RESERVED).
*/
- bs = phy_read_mmd_indirect(phydev, DP83867_STRAP_STS1,
- DP83867_DEVADDR, phydev->addr);
+ bs = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_STRAP_STS1);
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL);
if (bs & DP83867_STRAP_STS1_RESERVED) {
val &= ~DP83867_PHYCR_RESERVED_MASK;
@@ -354,8 +276,8 @@ static int dp83867_config(struct phy_device *phydev)
MII_DP83867_CFG2_SPEEDOPT_INTLOW);
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG2, cfg2);
- phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
- DP83867_DEVADDR, phydev->addr, 0x0);
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_RGMIICTL, 0x0);
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
DP83867_PHYCTRL_SGMIIEN |
@@ -367,8 +289,8 @@ static int dp83867_config(struct phy_device *phydev)
}
if (phy_interface_is_rgmii(phydev)) {
- val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
- DP83867_DEVADDR, phydev->addr);
+ val = phy_read_mmd(phydev, DP83867_DEVADDR,
+ DP83867_RGMIICTL);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
@@ -380,26 +302,24 @@ static int dp83867_config(struct phy_device *phydev)
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
val |= DP83867_RGMII_RX_CLK_DELAY_EN;
- phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
- DP83867_DEVADDR, phydev->addr, val);
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_RGMIICTL, val);
delay = (dp83867->rx_id_delay |
(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
- phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
- DP83867_DEVADDR, phydev->addr, delay);
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_RGMIIDCTL, delay);
if (dp83867->io_impedance >= 0) {
- val = phy_read_mmd_indirect(phydev,
- DP83867_IO_MUX_CFG,
- DP83867_DEVADDR,
- phydev->addr);
+ val = phy_read_mmd(phydev,
+ DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG);
val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
val |= dp83867->io_impedance &
DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
- phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
- DP83867_DEVADDR, phydev->addr,
- val);
+ phy_write_mmd(phydev, DP83867_DEVADDR,
+ DP83867_IO_MUX_CFG, val);
}
}
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c
index 749562db96..11abe5e0c9 100644
--- a/drivers/net/ravb.c
+++ b/drivers/net/ravb.c
@@ -46,6 +46,8 @@
#define CSR_OPS 0x0000000F
#define CSR_OPS_CONFIG BIT(1)
+#define APSR_TDM BIT(14)
+
#define TCCR_TSRQ0 BIT(0)
#define RFLR_RFL_MIN 0x05EE
@@ -389,9 +391,14 @@ static int ravb_dmac_init(struct udevice *dev)
/* FIFO size set */
writel(0x00222210, eth->iobase + RAVB_REG_TGC);
- /* Delay CLK: 2ns */
- if (pdata->max_speed == 1000)
- writel(BIT(14), eth->iobase + RAVB_REG_APSR);
+ /* Delay CLK: 2ns (not applicable on R-Car E3/D3) */
+ if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77990) ||
+ (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77995))
+ return 0;
+
+ if ((pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID))
+ writel(APSR_TDM, eth->iobase + RAVB_REG_APSR);
return 0;
}
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index a78f3d233f..521e5909a2 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -257,6 +257,7 @@ static struct {
{"RTL-8168/8111g", 0x4c, 0xff7e1880,},
{"RTL-8101e", 0x34, 0xff7e1880,},
{"RTL-8100e", 0x32, 0xff7e1880,},
+ {"RTL-8168h/8111h", 0x54, 0xff7e1880,},
};
enum _DescStatusBit {
@@ -301,7 +302,7 @@ static unsigned char rxdata[RX_BUF_LEN];
*/
#if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN
#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \
- !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86)
+ !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86)
#warning cache-line size is larger than descriptor size
#endif
#endif
@@ -941,6 +942,23 @@ static void rtl_halt(struct eth_device *dev)
}
#endif
+#ifdef CONFIG_DM_ETH
+static int rtl8169_write_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *plat = dev_get_platdata(dev);
+ unsigned int i;
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ RTL_W8(MAC0 + i, plat->enetaddr[i]);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ return 0;
+}
+#endif
+
/**************************************************************************
INIT - Look for an adapter, this routine's visible to the outside
***************************************************************************/
@@ -1195,6 +1213,7 @@ static const struct eth_ops rtl8169_eth_ops = {
.send = rtl8169_eth_send,
.recv = rtl8169_eth_recv,
.stop = rtl8169_eth_stop,
+ .write_hwaddr = rtl8169_write_hwaddr,
};
static const struct udevice_id rtl8169_eth_ids[] = {
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 4646f2ba4e..da79b766a6 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -34,7 +34,8 @@
# error "Please define CONFIG_SH_ETHER_PHY_ADDR"
#endif
-#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF)
+#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && \
+ !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
#define flush_cache_wback(addr, len) \
flush_dcache_range((u32)addr, \
(u32)(addr + ALIGN(len, CONFIG_SH_ETHER_ALIGNE_SIZE)))
@@ -425,7 +426,7 @@ static int sh_eth_phy_regs_config(struct sh_eth_dev *eth)
sh_eth_write(port_info, GECMR_100B, GECMR);
#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
sh_eth_write(port_info, 1, RTRATE);
-#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_RCAR_GEN2)
+#elif defined(CONFIG_RCAR_GEN2)
val = ECMR_RTM;
#endif
} else if (phy->speed == 10) {
@@ -806,9 +807,11 @@ static int sh_ether_probe(struct udevice *udev)
priv->iobase = pdata->iobase;
+#if CONFIG_IS_ENABLED(CLK)
ret = clk_get_by_index(udev, 0, &priv->clk);
if (ret < 0)
return ret;
+#endif
ret = dev_read_phandle_with_args(udev, "phy-handle", NULL, 0, 0, &phandle_args);
if (!ret) {
@@ -843,9 +846,11 @@ static int sh_ether_probe(struct udevice *udev)
eth->port_info[eth->port].iobase =
(void __iomem *)(BASE_IO_ADDR + 0x800 * eth->port);
+#if CONFIG_IS_ENABLED(CLK)
ret = clk_enable(&priv->clk);
if (ret)
goto err_mdio_register;
+#endif
ret = sh_eth_phy_config(udev);
if (ret) {
@@ -856,7 +861,9 @@ static int sh_ether_probe(struct udevice *udev)
return 0;
err_phy_config:
+#if CONFIG_IS_ENABLED(CLK)
clk_disable(&priv->clk);
+#endif
err_mdio_register:
mdio_free(mdiodev);
return ret;
@@ -868,7 +875,9 @@ static int sh_ether_remove(struct udevice *udev)
struct sh_eth_dev *eth = &priv->shdev;
struct sh_eth_info *port_info = &eth->port_info[eth->port];
+#if CONFIG_IS_ENABLED(CLK)
clk_disable(&priv->clk);
+#endif
free(port_info->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
@@ -917,6 +926,7 @@ int sh_ether_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id sh_ether_ids[] = {
+ { .compatible = "renesas,ether-r7s72100" },
{ .compatible = "renesas,ether-r8a7790" },
{ .compatible = "renesas,ether-r8a7791" },
{ .compatible = "renesas,ether-r8a7793" },
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index cd8190062a..e1bbd4913f 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -228,6 +228,60 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
[RMII_MII] = 0x0790,
};
+static const u16 sh_eth_offset_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [EDSR] = 0x0000,
+ [EDMR] = 0x0400,
+ [EDTRR] = 0x0408,
+ [EDRRR] = 0x0410,
+ [EESR] = 0x0428,
+ [EESIPR] = 0x0430,
+ [TDLAR] = 0x0010,
+ [TDFAR] = 0x0014,
+ [TDFXR] = 0x0018,
+ [TDFFR] = 0x001c,
+ [RDLAR] = 0x0030,
+ [RDFAR] = 0x0034,
+ [RDFXR] = 0x0038,
+ [RDFFR] = 0x003c,
+ [TRSCER] = 0x0438,
+ [RMFCR] = 0x0440,
+ [TFTR] = 0x0448,
+ [FDR] = 0x0450,
+ [RMCR] = 0x0458,
+ [RPADIR] = 0x0460,
+ [FCFTR] = 0x0468,
+ [CSMR] = 0x04E4,
+
+ [ECMR] = 0x0500,
+ [ECSR] = 0x0510,
+ [ECSIPR] = 0x0518,
+ [PIR] = 0x0520,
+ [PSR] = 0x0528,
+ [PIPR] = 0x052c,
+ [RFLR] = 0x0508,
+ [APR] = 0x0554,
+ [MPR] = 0x0558,
+ [PFTCR] = 0x055c,
+ [PFRCR] = 0x0560,
+ [TPAUSER] = 0x0564,
+ [GECMR] = 0x05b0,
+ [BCULR] = 0x05b4,
+ [MAHR] = 0x05c0,
+ [MALR] = 0x05c8,
+ [TROCR] = 0x0700,
+ [CDCR] = 0x0708,
+ [LCCR] = 0x0710,
+ [CEFCR] = 0x0740,
+ [FRECR] = 0x0748,
+ [TSFRCR] = 0x0750,
+ [TLFRCR] = 0x0758,
+ [RFCR] = 0x0760,
+ [CERCR] = 0x0768,
+ [CEECR] = 0x0770,
+ [MAFCR] = 0x0778,
+ [RMII_MII] = 0x0790,
+};
+
static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
[ECMR] = 0x0100,
[RFLR] = 0x0108,
@@ -295,9 +349,6 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
#define SH_ETH_TYPE_ETHER
#define BASE_IO_ADDR 0xfef00000
#endif
-#elif defined(CONFIG_CPU_SH7724)
-#define SH_ETH_TYPE_ETHER
-#define BASE_IO_ADDR 0xA4600000
#elif defined(CONFIG_R8A7740)
#define SH_ETH_TYPE_GETHER
#define BASE_IO_ADDR 0xE9A00000
@@ -606,6 +657,8 @@ static inline unsigned long sh_eth_reg_addr(struct sh_eth_info *port,
const u16 *reg_offset = sh_eth_offset_gigabit;
#elif defined(SH_ETH_TYPE_ETHER)
const u16 *reg_offset = sh_eth_offset_fast_sh4;
+#elif defined(SH_ETH_TYPE_RZ)
+ const u16 *reg_offset = sh_eth_offset_rz;
#else
#error
#endif
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 98bd7a5823..c0a440886e 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -138,7 +138,9 @@ struct emac_eth_dev {
struct phy_device *phydev;
struct mii_dev *bus;
struct clk tx_clk;
+ struct clk ephy_clk;
struct reset_ctl tx_rst;
+ struct reset_ctl ephy_rst;
#ifdef CONFIG_DM_GPIO
struct gpio_desc reset_gpio;
#endif
@@ -653,7 +655,6 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev)
static int sun8i_emac_board_setup(struct emac_eth_dev *priv)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
int ret;
ret = clk_enable(&priv->tx_clk);
@@ -670,16 +671,20 @@ static int sun8i_emac_board_setup(struct emac_eth_dev *priv)
}
}
- if (priv->variant == H3_EMAC) {
- /* Only H3/H5 have clock controls for internal EPHY */
- if (priv->use_internal_phy) {
- /* Set clock gating for ephy */
- setbits_le32(&ccm->bus_gate4,
- BIT(AHB_GATE_OFFSET_EPHY));
-
- /* Deassert EPHY */
- setbits_le32(&ccm->ahb_reset2_cfg,
- BIT(AHB_RESET_OFFSET_EPHY));
+ /* Only H3/H5 have clock controls for internal EPHY */
+ if (clk_valid(&priv->ephy_clk)) {
+ ret = clk_enable(&priv->ephy_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable EPHY TX clock\n");
+ return ret;
+ }
+ }
+
+ if (reset_valid(&priv->ephy_rst)) {
+ ret = reset_deassert(&priv->ephy_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert EPHY TX clock\n");
+ return ret;
}
}
@@ -839,6 +844,44 @@ static const struct eth_ops sun8i_emac_eth_ops = {
.stop = sun8i_emac_eth_stop,
};
+static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv)
+{
+ int node, ret;
+
+ /* look for mdio-mux node for internal PHY node */
+ node = fdt_path_offset(gd->fdt_blob,
+ "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1");
+ if (node < 0) {
+ debug("failed to get mdio-mux with internal PHY\n");
+ return node;
+ }
+
+ ret = fdt_node_check_compatible(gd->fdt_blob, node,
+ "allwinner,sun8i-h3-mdio-internal");
+ if (ret < 0) {
+ debug("failed to find mdio-internal node\n");
+ return ret;
+ }
+
+ ret = clk_get_by_index_nodev(offset_to_ofnode(node), 0,
+ &priv->ephy_clk);
+ if (ret) {
+ dev_err(dev, "failed to get EPHY TX clock\n");
+ return ret;
+ }
+
+ ret = reset_get_by_index_nodev(offset_to_ofnode(node), 0,
+ &priv->ephy_rst);
+ if (ret) {
+ dev_err(dev, "failed to get EPHY TX reset\n");
+ return ret;
+ }
+
+ priv->use_internal_phy = true;
+
+ return 0;
+}
+
static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
{
struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev);
@@ -920,12 +963,9 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
}
if (priv->variant == H3_EMAC) {
- 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;
+ ret = sun8i_get_ephy_nodes(priv);
+ if (ret)
+ return ret;
}
priv->interface = pdata->phy_interface;
diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c
index bb879d8d4f..9d53984973 100644
--- a/drivers/net/ti/davinci_emac.c
+++ b/drivers/net/ti/davinci_emac.c
@@ -816,55 +816,12 @@ int davinci_emac_initialize(void)
phy_id |= tmp & 0x0000ffff;
- switch (phy_id) {
-#ifdef PHY_KSZ8873
- case PHY_KSZ8873:
- sprintf(phy[i].name, "KSZ8873 @ 0x%02x",
- active_phy_addr[i]);
- phy[i].init = ksz8873_init_phy;
- phy[i].is_phy_connected = ksz8873_is_phy_connected;
- phy[i].get_link_speed = ksz8873_get_link_speed;
- phy[i].auto_negotiate = ksz8873_auto_negotiate;
- break;
-#endif
-#ifdef PHY_LXT972
- case PHY_LXT972:
- sprintf(phy[i].name, "LXT972 @ 0x%02x",
- active_phy_addr[i]);
- phy[i].init = lxt972_init_phy;
- phy[i].is_phy_connected = lxt972_is_phy_connected;
- phy[i].get_link_speed = lxt972_get_link_speed;
- phy[i].auto_negotiate = lxt972_auto_negotiate;
- break;
-#endif
-#ifdef PHY_DP83848
- case PHY_DP83848:
- sprintf(phy[i].name, "DP83848 @ 0x%02x",
- active_phy_addr[i]);
- phy[i].init = dp83848_init_phy;
- phy[i].is_phy_connected = dp83848_is_phy_connected;
- phy[i].get_link_speed = dp83848_get_link_speed;
- phy[i].auto_negotiate = dp83848_auto_negotiate;
- break;
-#endif
-#ifdef PHY_ET1011C
- case PHY_ET1011C:
- sprintf(phy[i].name, "ET1011C @ 0x%02x",
- active_phy_addr[i]);
- phy[i].init = gen_init_phy;
- phy[i].is_phy_connected = gen_is_phy_connected;
- phy[i].get_link_speed = et1011c_get_link_speed;
- phy[i].auto_negotiate = gen_auto_negotiate;
- break;
-#endif
- default:
- sprintf(phy[i].name, "GENERIC @ 0x%02x",
- active_phy_addr[i]);
- phy[i].init = gen_init_phy;
- phy[i].is_phy_connected = gen_is_phy_connected;
- phy[i].get_link_speed = gen_get_link_speed;
- phy[i].auto_negotiate = gen_auto_negotiate;
- }
+ sprintf(phy[i].name, "GENERIC @ 0x%02x",
+ active_phy_addr[i]);
+ phy[i].init = gen_init_phy;
+ phy[i].is_phy_connected = gen_is_phy_connected;
+ phy[i].get_link_speed = gen_get_link_speed;
+ phy[i].auto_negotiate = gen_auto_negotiate;
debug("Ethernet PHY: %s\n", phy[i].name);
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 1ee0a0aefb..d4965e2ef6 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -577,7 +577,7 @@ static int nvme_get_info_from_identify(struct nvme_dev *dev)
int ret;
int shift = NVME_CAP_MPSMIN(dev->cap) + 12;
- ret = nvme_identify(dev, 0, 1, (dma_addr_t)ctrl);
+ ret = nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl);
if (ret)
return -EIO;
@@ -646,7 +646,7 @@ static int nvme_blk_probe(struct udevice *udev)
ns->dev = ndev;
/* extract the namespace id from the block device name */
ns->ns_id = trailing_strtol(udev->name) + 1;
- if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)id))
+ if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id))
return -EIO;
flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK;
diff --git a/drivers/nvme/nvme_show.c b/drivers/nvme/nvme_show.c
index 395b0618e6..15e459da1a 100644
--- a/drivers/nvme/nvme_show.c
+++ b/drivers/nvme/nvme_show.c
@@ -111,14 +111,14 @@ int nvme_print_info(struct udevice *udev)
ALLOC_CACHE_ALIGN_BUFFER(char, buf_ctrl, sizeof(struct nvme_id_ctrl));
struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf_ctrl;
- if (nvme_identify(dev, 0, 1, (dma_addr_t)ctrl))
+ if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl))
return -EIO;
print_optional_admin_cmd(le16_to_cpu(ctrl->oacs), ns->devnum);
print_optional_nvm_cmd(le16_to_cpu(ctrl->oncs), ns->devnum);
print_format_nvme_attributes(ctrl->fna, ns->devnum);
- if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)id))
+ if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id))
return -EIO;
print_formats(id, ns);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 1521885bde..429bb836a8 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -69,6 +69,14 @@ config PCI_RCAR_GEN2
Renesas RCar Gen2 SoCs. The PCIe controller on RCar Gen2 is
also used to access EHCI USB controller on the SoC.
+config PCI_RCAR_GEN3
+ bool "Renesas RCar Gen3 PCIe driver"
+ depends on DM_PCI
+ depends on RCAR_GEN3
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Renesas RCar Gen3 SoCs.
+
config PCI_SANDBOX
bool "Sandbox PCI support"
depends on SANDBOX && DM_PCI
@@ -105,6 +113,14 @@ config PCIE_LAYERSCAPE
PCIe controllers. The PCIe may works in RC or EP mode according to
RCW[HOST_AGT_PEX] setting.
+config PCIE_LAYERSCAPE_GEN4
+ bool "Layerscape Gen4 PCIe support"
+ depends on DM_PCI
+ help
+ Support PCIe Gen4 on NXP Layerscape SoCs, which may have one or
+ several PCIe controllers. The PCIe controller can work in RC or
+ EP mode according to RCW[HOST_AGT_PEX] setting.
+
config PCIE_INTEL_FPGA
bool "Intel FPGA PCIe support"
depends on DM_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 4923641895..bd392edba1 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_RCAR_GEN3) += pci-rcar-gen3.o
obj-$(CONFIG_SH4_PCI) += pci_sh4.o
obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
@@ -32,5 +33,7 @@ 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
+obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
+ pcie_layerscape_gen4_fixup.o
obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
diff --git a/drivers/pci/pci-rcar-gen3.c b/drivers/pci/pci-rcar-gen3.c
new file mode 100644
index 0000000000..52ca13b70c
--- /dev/null
+++ b/drivers/pci/pci-rcar-gen3.c
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RCar Gen3 PCIEC driver
+ *
+ * Copyright (C) 2018-2019 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on Linux PCIe driver for Renesas R-Car SoCs
+ * Copyright (C) 2014 Renesas Electronics Europe Ltd
+ *
+ * Based on:
+ * arch/sh/drivers/pci/pcie-sh7786.c
+ * arch/sh/drivers/pci/ops-sh7786.c
+ * Copyright (C) 2009 - 2011 Paul Mundt
+ *
+ * Author: Phil Edworthy <phil.edworthy@renesas.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <wait_bit.h>
+
+#define PCIECAR 0x000010
+#define PCIECCTLR 0x000018
+#define CONFIG_SEND_ENABLE BIT(31)
+#define TYPE0 (0 << 8)
+#define TYPE1 BIT(8)
+#define PCIECDR 0x000020
+#define PCIEMSR 0x000028
+#define PCIEINTXR 0x000400
+#define PCIEPHYSR 0x0007f0
+#define PHYRDY BIT(0)
+#define PCIEMSITXR 0x000840
+
+/* Transfer control */
+#define PCIETCTLR 0x02000
+#define CFINIT 1
+#define PCIETSTR 0x02004
+#define DATA_LINK_ACTIVE 1
+#define PCIEERRFR 0x02020
+#define UNSUPPORTED_REQUEST BIT(4)
+#define PCIEMSIFR 0x02044
+#define PCIEMSIALR 0x02048
+#define MSIFE 1
+#define PCIEMSIAUR 0x0204c
+#define PCIEMSIIER 0x02050
+
+/* root port address */
+#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x) (0x02200 + ((x) * 0x20))
+#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
+#define LAM_PREFETCH BIT(3)
+#define LAM_64BIT BIT(2)
+#define LAR_ENABLE BIT(1)
+
+/* PCIe address reg & mask */
+#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
+#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
+#define PAR_ENABLE BIT(31)
+#define IO_SPACE BIT(8)
+
+/* Configuration */
+#define PCICONF(x) (0x010000 + ((x) * 0x4))
+#define PMCAP(x) (0x010040 + ((x) * 0x4))
+#define EXPCAP(x) (0x010070 + ((x) * 0x4))
+#define VCCAP(x) (0x010100 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR1 0x011004
+#define TLCTLR 0x011048
+#define MACSR 0x011054
+#define SPCHGFIN BIT(4)
+#define SPCHGFAIL BIT(6)
+#define SPCHGSUC BIT(7)
+#define LINK_SPEED (0xf << 16)
+#define LINK_SPEED_2_5GTS (1 << 16)
+#define LINK_SPEED_5_0GTS (2 << 16)
+#define MACCTLR 0x011058
+#define SPEED_CHANGE BIT(24)
+#define SCRAMBLE_DISABLE BIT(27)
+#define MACS2R 0x011078
+#define MACCGSPSETR 0x011084
+#define SPCNGRSN BIT(31)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYADRR 0x04000c
+#define WRITE_CMD BIT(16)
+#define PHY_ACK BIT(24)
+#define RATE_POS 12
+#define LANE_POS 8
+#define ADR_POS 0
+#define H1_PCIEPHYDOUTR 0x040014
+
+/* R-Car Gen2 PHY */
+#define GEN2_PCIEPHYADDR 0x780
+#define GEN2_PCIEPHYDATA 0x784
+#define GEN2_PCIEPHYCTRL 0x78c
+
+#define INT_PCI_MSI_NR 32
+
+#define RCONF(x) (PCICONF(0) + (x))
+#define RPMCAP(x) (PMCAP(0) + (x))
+#define REXPCAP(x) (EXPCAP(0) + (x))
+#define RVCCAP(x) (VCCAP(0) + (x))
+
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
+
+#define RCAR_PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+#define PCI_EXP_FLAGS 2 /* Capabilities register */
+#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
+#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
+#define PCI_EXP_LNKCAP 12 /* Link Capabilities */
+#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */
+#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */
+#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */
+
+enum {
+ RCAR_PCI_ACCESS_READ,
+ RCAR_PCI_ACCESS_WRITE,
+};
+
+struct rcar_gen3_pcie_priv {
+ fdt_addr_t regs;
+};
+
+static void rcar_rmw32(struct udevice *dev, int where, u32 mask, u32 data)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+ int shift = 8 * (where & 3);
+
+ clrsetbits_le32(priv->regs + (where & ~3),
+ mask << shift, data << shift);
+}
+
+static u32 rcar_read_conf(struct udevice *dev, int where)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+ int shift = 8 * (where & 3);
+
+ return readl(priv->regs + (where & ~3)) >> shift;
+}
+
+static int rcar_pcie_config_access(struct udevice *udev,
+ unsigned char access_type,
+ pci_dev_t bdf, int where, ulong *data)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(udev);
+ u32 reg = where & ~3;
+
+ /* Clear errors */
+ clrbits_le32(priv->regs + PCIEERRFR, 0);
+
+ /* Set the PIO address */
+ writel((bdf << 8) | reg, priv->regs + PCIECAR);
+
+ /* Enable the configuration access */
+ if (!PCI_BUS(bdf))
+ writel(CONFIG_SEND_ENABLE | TYPE0, priv->regs + PCIECCTLR);
+ else
+ writel(CONFIG_SEND_ENABLE | TYPE1, priv->regs + PCIECCTLR);
+
+ /* Check for errors */
+ if (readl(priv->regs + PCIEERRFR) & UNSUPPORTED_REQUEST)
+ return -ENODEV;
+
+ /* Check for master and target aborts */
+ if (rcar_read_conf(udev, RCONF(PCI_STATUS)) &
+ (PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT))
+ return -ENODEV;
+
+ if (access_type == RCAR_PCI_ACCESS_READ)
+ *data = readl(priv->regs + PCIECDR);
+ else
+ writel(*data, priv->regs + PCIECDR);
+
+ /* Disable the configuration access */
+ writel(0, priv->regs + PCIECCTLR);
+
+ return 0;
+}
+
+static int rcar_gen3_pcie_addr_valid(pci_dev_t d, uint where)
+{
+ u32 slot;
+
+ if (PCI_FUNC(d))
+ return -EINVAL;
+
+ slot = PCI_DEV(d);
+ if (slot != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rcar_gen3_pcie_read_config(struct udevice *dev, pci_dev_t bdf,
+ uint where, ulong *val,
+ enum pci_size_t size)
+{
+ ulong reg;
+ int ret;
+
+ ret = rcar_gen3_pcie_addr_valid(bdf, where);
+ if (ret) {
+ *val = pci_get_ff(size);
+ return 0;
+ }
+
+ ret = rcar_pcie_config_access(dev, RCAR_PCI_ACCESS_READ,
+ bdf, where, &reg);
+ if (ret != 0)
+ reg = 0xffffffffUL;
+
+ *val = pci_conv_32_to_size(reg, where, size);
+
+ return ret;
+}
+
+static int rcar_gen3_pcie_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint where, ulong val,
+ enum pci_size_t size)
+{
+ ulong data;
+ int ret;
+
+ ret = rcar_gen3_pcie_addr_valid(bdf, where);
+ if (ret)
+ return ret;
+
+ data = pci_conv_32_to_size(val, where, size);
+
+ ret = rcar_pcie_config_access(dev, RCAR_PCI_ACCESS_WRITE,
+ bdf, where, &data);
+
+ return ret;
+}
+
+static int rcar_gen3_pcie_wait_for_phyrdy(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+
+ return wait_for_bit_le32((void *)priv->regs + PCIEPHYSR, PHYRDY,
+ true, 50, false);
+}
+
+static int rcar_gen3_pcie_wait_for_dl(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+
+ return wait_for_bit_le32((void *)priv->regs + PCIETSTR,
+ DATA_LINK_ACTIVE, true, 50, false);
+}
+
+static int rcar_gen3_pcie_hw_init(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+ int ret;
+
+ /* Begin initialization */
+ writel(0, priv->regs + PCIETCTLR);
+
+ /* Set mode */
+ writel(1, priv->regs + PCIEMSR);
+
+ ret = rcar_gen3_pcie_wait_for_phyrdy(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Initial header for port config space is type 1, set the device
+ * class to match. Hardware takes care of propagating the IDSETR
+ * settings, so there is no need to bother with a quirk.
+ */
+ writel(PCI_CLASS_BRIDGE_PCI << 16, priv->regs + IDSETR1);
+
+ /*
+ * Setup Secondary Bus Number & Subordinate Bus Number, even though
+ * they aren't used, to avoid bridge being detected as broken.
+ */
+ rcar_rmw32(dev, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
+ rcar_rmw32(dev, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
+
+ /* Initialize default capabilities. */
+ rcar_rmw32(dev, REXPCAP(0), 0xff, PCI_CAP_ID_EXP);
+ rcar_rmw32(dev, REXPCAP(PCI_EXP_FLAGS),
+ PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
+ rcar_rmw32(dev, RCONF(PCI_HEADER_TYPE), 0x7f,
+ PCI_HEADER_TYPE_BRIDGE);
+
+ /* Enable data link layer active state reporting */
+ rcar_rmw32(dev, REXPCAP(PCI_EXP_LNKCAP),
+ PCI_EXP_LNKCAP_DLLLARC, PCI_EXP_LNKCAP_DLLLARC);
+
+ /* Write out the physical slot number = 0 */
+ rcar_rmw32(dev, REXPCAP(PCI_EXP_SLTCAP),
+ PCI_EXP_SLTCAP_PSN, 0);
+
+ /* Set the completion timer timeout to the maximum 50ms. */
+ rcar_rmw32(dev, TLCTLR + 1, 0x3f, 50);
+
+ /* Terminate list of capabilities (Next Capability Offset=0) */
+ rcar_rmw32(dev, RVCCAP(0), 0xfff00000, 0);
+
+ /* Finish initialization - establish a PCI Express link */
+ writel(CFINIT, priv->regs + PCIETCTLR);
+
+ return rcar_gen3_pcie_wait_for_dl(dev);
+}
+
+static int rcar_gen3_pcie_probe(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(dev);
+ struct clk pci_clk;
+ u32 mask;
+ int i, cnt, ret;
+
+ ret = clk_get_by_index(dev, 0, &pci_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&pci_clk);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags != PCI_REGION_SYS_MEMORY)
+ continue;
+
+ if (hose->regions[i].phys_start == 0)
+ continue;
+
+ mask = (hose->regions[i].size - 1) & ~0xf;
+ mask |= LAR_ENABLE;
+ writel(hose->regions[i].phys_start, priv->regs + PCIEPRAR(0));
+ writel(hose->regions[i].phys_start, priv->regs + PCIELAR(0));
+ writel(mask, priv->regs + PCIELAMR(0));
+ break;
+ }
+
+ writel(0, priv->regs + PCIEPRAR(4));
+ writel(0, priv->regs + PCIELAR(4));
+ writel(0, priv->regs + PCIELAMR(4));
+
+ ret = rcar_gen3_pcie_hw_init(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0, cnt = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags == PCI_REGION_SYS_MEMORY)
+ continue;
+
+ writel(0, priv->regs + PCIEPTCTLR(cnt));
+ writel((hose->regions[i].size - 1) & ~0x7f,
+ priv->regs + PCIEPAMR(cnt));
+ writel(upper_32_bits(hose->regions[i].phys_start),
+ priv->regs + PCIEPAUR(cnt));
+ writel(lower_32_bits(hose->regions[i].phys_start),
+ priv->regs + PCIEPALR(cnt));
+ mask = PAR_ENABLE;
+ if (hose->regions[i].flags == PCI_REGION_IO)
+ mask |= IO_SPACE;
+ writel(mask, priv->regs + PCIEPTCTLR(cnt));
+
+ cnt++;
+ }
+
+ return 0;
+}
+
+static int rcar_gen3_pcie_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_platdata(dev);
+
+ priv->regs = devfdt_get_addr_index(dev, 0);
+ if (!priv->regs)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops rcar_gen3_pcie_ops = {
+ .read_config = rcar_gen3_pcie_read_config,
+ .write_config = rcar_gen3_pcie_write_config,
+};
+
+static const struct udevice_id rcar_gen3_pcie_ids[] = {
+ { .compatible = "renesas,pcie-rcar-gen3" },
+ { }
+};
+
+U_BOOT_DRIVER(rcar_gen3_pcie) = {
+ .name = "rcar_gen3_pcie",
+ .id = UCLASS_PCI,
+ .of_match = rcar_gen3_pcie_ids,
+ .ops = &rcar_gen3_pcie_ops,
+ .probe = rcar_gen3_pcie_probe,
+ .ofdata_to_platdata = rcar_gen3_pcie_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct rcar_gen3_pcie_priv),
+};
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index d7237f6eee..1a3bf70834 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -359,7 +359,8 @@ int dm_pciauto_config_device(struct udevice *dev)
PCI_DEV(dm_pci_get_bdf(dev)));
break;
#endif
-#if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349)
+#if defined(CONFIG_ARCH_MPC834X) && !defined(CONFIG_TARGET_VME8349) && \
+ !defined(CONFIG_TARGET_CADDY2)
case PCI_CLASS_BRIDGE_OTHER:
/*
* The host/PCI bridge 1 seems broken in 8349 - it presents
diff --git a/drivers/pci/pci_auto_old.c b/drivers/pci/pci_auto_old.c
index e705a3072e..b566705c9d 100644
--- a/drivers/pci/pci_auto_old.c
+++ b/drivers/pci/pci_auto_old.c
@@ -376,7 +376,8 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
PCI_DEV(dev));
break;
#endif
-#if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349)
+#if defined(CONFIG_ARCH_MPC834X) && !defined(CONFIG_TARGET_VME8349) && \
+ !defined(CONFIG_TARGET_CADDY2)
case PCI_CLASS_BRIDGE_OTHER:
/*
* The host/PCI bridge 1 seems broken in 8349 - it presents
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index 7d9b75c2c4..2cede1211b 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -306,7 +306,7 @@ int dm_pci_run_vga_bios(struct udevice *dev, int (*int15_handler)(void),
goto err;
#endif
} else {
-#if defined(CONFIG_X86) && CONFIG_IS_ENABLED(X86_32BIT_INIT)
+#if defined(CONFIG_X86) && (CONFIG_IS_ENABLED(X86_32BIT_INIT) || CONFIG_TPL)
bios_set_interrupt_handler(0x15, int15_handler);
bios_run_on_x86(dev, (unsigned long)ram, vesa_mode,
diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c
new file mode 100644
index 0000000000..1fd8761bbc
--- /dev/null
+++ b/drivers/pci/pcie_layerscape_gen4.c
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * PCIe Gen4 driver for NXP Layerscape SoCs
+ * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/arch/fsl_serdes.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm.h>
+#include <linux/sizes.h>
+
+#include "pcie_layerscape_gen4.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+LIST_HEAD(ls_pcie_g4_list);
+
+static u64 bar_size[4] = {
+ PCIE_BAR0_SIZE,
+ PCIE_BAR1_SIZE,
+ PCIE_BAR2_SIZE,
+ PCIE_BAR4_SIZE
+};
+
+static int ls_pcie_g4_ltssm(struct ls_pcie_g4 *pcie)
+{
+ u32 state;
+
+ state = pf_ctrl_readl(pcie, PCIE_LTSSM_STA) & LTSSM_STATE_MASK;
+
+ return state;
+}
+
+static int ls_pcie_g4_link_up(struct ls_pcie_g4 *pcie)
+{
+ int ltssm;
+
+ ltssm = ls_pcie_g4_ltssm(pcie);
+ if (ltssm != LTSSM_PCIE_L0)
+ return 0;
+
+ return 1;
+}
+
+static void ls_pcie_g4_ep_enable_cfg(struct ls_pcie_g4 *pcie)
+{
+ ccsr_writel(pcie, GPEX_CFG_READY, PCIE_CONFIG_READY);
+}
+
+static void ls_pcie_g4_cfg_set_target(struct ls_pcie_g4 *pcie, u32 target)
+{
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(0), target);
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(0), 0);
+}
+
+static int ls_pcie_g4_outbound_win_set(struct ls_pcie_g4 *pcie, int idx,
+ int type, u64 phys, u64 bus_addr,
+ pci_size_t size)
+{
+ u32 val;
+ u32 size_h, size_l;
+
+ if (idx >= PAB_WINS_NUM)
+ return -EINVAL;
+
+ size_h = upper_32_bits(~(size - 1));
+ size_l = lower_32_bits(~(size - 1));
+
+ val = ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(idx));
+ val &= ~((AXI_AMAP_CTRL_TYPE_MASK << AXI_AMAP_CTRL_TYPE_SHIFT) |
+ (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT) |
+ AXI_AMAP_CTRL_EN);
+ val |= ((type & AXI_AMAP_CTRL_TYPE_MASK) << AXI_AMAP_CTRL_TYPE_SHIFT) |
+ ((size_l >> AXI_AMAP_CTRL_SIZE_SHIFT) <<
+ AXI_AMAP_CTRL_SIZE_SHIFT) | AXI_AMAP_CTRL_EN;
+
+ ccsr_writel(pcie, PAB_AXI_AMAP_CTRL(idx), val);
+
+ ccsr_writel(pcie, PAB_AXI_AMAP_AXI_WIN(idx), lower_32_bits(phys));
+ ccsr_writel(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(idx), upper_32_bits(phys));
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr));
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr));
+ ccsr_writel(pcie, PAB_EXT_AXI_AMAP_SIZE(idx), size_h);
+
+ return 0;
+}
+
+static int ls_pcie_g4_rc_inbound_win_set(struct ls_pcie_g4 *pcie, int idx,
+ int type, u64 phys, u64 bus_addr,
+ pci_size_t size)
+{
+ u32 val;
+ pci_size_t win_size = ~(size - 1);
+
+ val = ccsr_readl(pcie, PAB_PEX_AMAP_CTRL(idx));
+
+ val &= ~(PEX_AMAP_CTRL_TYPE_MASK << PEX_AMAP_CTRL_TYPE_SHIFT);
+ val &= ~(PEX_AMAP_CTRL_EN_MASK << PEX_AMAP_CTRL_EN_SHIFT);
+ val = (val | (type << PEX_AMAP_CTRL_TYPE_SHIFT));
+ val = (val | (1 << PEX_AMAP_CTRL_EN_SHIFT));
+
+ ccsr_writel(pcie, PAB_PEX_AMAP_CTRL(idx),
+ val | lower_32_bits(win_size));
+
+ ccsr_writel(pcie, PAB_EXT_PEX_AMAP_SIZE(idx), upper_32_bits(win_size));
+ ccsr_writel(pcie, PAB_PEX_AMAP_AXI_WIN(idx), lower_32_bits(phys));
+ ccsr_writel(pcie, PAB_EXT_PEX_AMAP_AXI_WIN(idx), upper_32_bits(phys));
+ ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr));
+ ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr));
+
+ return 0;
+}
+
+static void ls_pcie_g4_dump_wins(struct ls_pcie_g4 *pcie, int wins)
+{
+ int i;
+
+ for (i = 0; i < wins; i++) {
+ debug("APIO Win%d:\n", i);
+ debug("\tLOWER PHYS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(i)));
+ debug("\tUPPER PHYS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(i)));
+ debug("\tLOWER BUS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_L(i)));
+ debug("\tUPPER BUS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(i)));
+ debug("\tSIZE: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)) &
+ (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT));
+ debug("\tEXT_SIZE: 0x%08x\n",
+ ccsr_readl(pcie, PAB_EXT_AXI_AMAP_SIZE(i)));
+ debug("\tPARAM: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(i)));
+ debug("\tCTRL: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)));
+ }
+}
+
+static void ls_pcie_g4_setup_wins(struct ls_pcie_g4 *pcie)
+{
+ struct pci_region *io, *mem, *pref;
+ int idx = 1;
+
+ /* INBOUND WIN */
+ ls_pcie_g4_rc_inbound_win_set(pcie, 0, IB_TYPE_MEM_F, 0, 0, SIZE_1T);
+
+ /* OUTBOUND WIN 0: CFG */
+ ls_pcie_g4_outbound_win_set(pcie, 0, PAB_AXI_TYPE_CFG,
+ pcie->cfg_res.start, 0,
+ fdt_resource_size(&pcie->cfg_res));
+
+ pci_get_regions(pcie->bus, &io, &mem, &pref);
+
+ if (io)
+ /* OUTBOUND WIN: IO */
+ ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_IO,
+ io->phys_start, io->bus_start,
+ io->size);
+
+ if (mem)
+ /* OUTBOUND WIN: MEM */
+ ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM,
+ mem->phys_start, mem->bus_start,
+ mem->size);
+
+ if (pref)
+ /* OUTBOUND WIN: perf MEM */
+ ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM,
+ pref->phys_start, pref->bus_start,
+ pref->size);
+
+ ls_pcie_g4_dump_wins(pcie, idx);
+}
+
+/* Return 0 if the address is valid, -errno if not valid */
+static int ls_pcie_g4_addr_valid(struct ls_pcie_g4 *pcie, pci_dev_t bdf)
+{
+ struct udevice *bus = pcie->bus;
+
+ if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ return -ENODEV;
+
+ if (!pcie->enabled)
+ return -ENXIO;
+
+ if (PCI_BUS(bdf) < bus->seq)
+ return -EINVAL;
+
+ if ((PCI_BUS(bdf) > bus->seq) && (!ls_pcie_g4_link_up(pcie)))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+void *ls_pcie_g4_conf_address(struct ls_pcie_g4 *pcie, pci_dev_t bdf,
+ int offset)
+{
+ struct udevice *bus = pcie->bus;
+ u32 target;
+
+ if (PCI_BUS(bdf) == bus->seq) {
+ if (offset < INDIRECT_ADDR_BNDRY) {
+ ccsr_set_page(pcie, 0);
+ return pcie->ccsr + offset;
+ }
+
+ ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
+ return pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset);
+ }
+
+ target = PAB_TARGET_BUS(PCI_BUS(bdf) - bus->seq) |
+ PAB_TARGET_DEV(PCI_DEV(bdf)) |
+ PAB_TARGET_FUNC(PCI_FUNC(bdf));
+
+ ls_pcie_g4_cfg_set_target(pcie, target);
+
+ return pcie->cfg + offset;
+}
+
+static int ls_pcie_g4_read_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct ls_pcie_g4 *pcie = dev_get_priv(bus);
+ void *address;
+ int ret = 0;
+
+ if (ls_pcie_g4_addr_valid(pcie, bdf)) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ address = ls_pcie_g4_conf_address(pcie, bdf, offset);
+
+ switch (size) {
+ case PCI_SIZE_8:
+ *valuep = readb(address);
+ break;
+ case PCI_SIZE_16:
+ *valuep = readw(address);
+ break;
+ case PCI_SIZE_32:
+ *valuep = readl(address);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ls_pcie_g4_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct ls_pcie_g4 *pcie = dev_get_priv(bus);
+ void *address;
+
+ if (ls_pcie_g4_addr_valid(pcie, bdf))
+ return 0;
+
+ address = ls_pcie_g4_conf_address(pcie, bdf, offset);
+
+ switch (size) {
+ case PCI_SIZE_8:
+ writeb(value, address);
+ return 0;
+ case PCI_SIZE_16:
+ writew(value, address);
+ return 0;
+ case PCI_SIZE_32:
+ writel(value, address);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void ls_pcie_g4_setup_ctrl(struct ls_pcie_g4 *pcie)
+{
+ u32 val;
+
+ /* Fix class code */
+ val = ccsr_readl(pcie, GPEX_CLASSCODE);
+ val &= ~(GPEX_CLASSCODE_MASK << GPEX_CLASSCODE_SHIFT);
+ val |= PCI_CLASS_BRIDGE_PCI << GPEX_CLASSCODE_SHIFT;
+ ccsr_writel(pcie, GPEX_CLASSCODE, val);
+
+ /* Enable APIO and Memory/IO/CFG Wins */
+ val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0));
+ val |= APIO_EN | MEM_WIN_EN | IO_WIN_EN | CFG_WIN_EN;
+ ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val);
+
+ ls_pcie_g4_setup_wins(pcie);
+
+ pcie->stream_id_cur = 0;
+}
+
+static void ls_pcie_g4_ep_inbound_win_set(struct ls_pcie_g4 *pcie, int pf,
+ int bar, u64 phys)
+{
+ u32 val;
+
+ /* PF BAR1 is for MSI-X and only need to enable */
+ if (bar == 1) {
+ ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), BAR_AMAP_EN);
+ return;
+ }
+
+ val = upper_32_bits(phys);
+ ccsr_writel(pcie, PAB_EXT_PEX_BAR_AMAP(pf, bar), val);
+ val = lower_32_bits(phys) | BAR_AMAP_EN;
+ ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), val);
+}
+
+static void ls_pcie_g4_ep_setup_wins(struct ls_pcie_g4 *pcie, int pf)
+{
+ u64 phys;
+ int bar;
+ u32 val;
+
+ if ((!pcie->sriov_support && pf > LS_G4_PF0) || pf > LS_G4_PF1)
+ return;
+
+ phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR_SIZE * 4 * pf;
+ for (bar = 0; bar < PF_BAR_NUM; bar++) {
+ ls_pcie_g4_ep_inbound_win_set(pcie, pf, bar, phys);
+ phys += PCIE_BAR_SIZE;
+ }
+
+ /* OUTBOUND: map MEM */
+ ls_pcie_g4_outbound_win_set(pcie, pf, PAB_AXI_TYPE_MEM,
+ pcie->cfg_res.start +
+ CONFIG_SYS_PCI_MEMORY_SIZE * pf, 0x0,
+ CONFIG_SYS_PCI_MEMORY_SIZE);
+
+ val = ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf));
+ val &= ~FUNC_NUM_PCIE_MASK;
+ val |= pf;
+ ccsr_writel(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf), val);
+}
+
+static void ls_pcie_g4_ep_enable_bar(struct ls_pcie_g4 *pcie, int pf,
+ int bar, bool vf_bar, bool enable)
+{
+ u32 val;
+ u32 bar_pos = BAR_POS(bar, pf, vf_bar);
+
+ val = ccsr_readl(pcie, GPEX_BAR_ENABLE);
+ if (enable)
+ val |= 1 << bar_pos;
+ else
+ val &= ~(1 << bar_pos);
+ ccsr_writel(pcie, GPEX_BAR_ENABLE, val);
+}
+
+static void ls_pcie_g4_ep_set_bar_size(struct ls_pcie_g4 *pcie, int pf,
+ int bar, bool vf_bar, u64 size)
+{
+ u32 bar_pos = BAR_POS(bar, pf, vf_bar);
+ u32 mask_l = lower_32_bits(~(size - 1));
+ u32 mask_h = upper_32_bits(~(size - 1));
+
+ ccsr_writel(pcie, GPEX_BAR_SELECT, bar_pos);
+ ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l);
+ ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h);
+}
+
+static void ls_pcie_g4_ep_setup_bar(struct ls_pcie_g4 *pcie, int pf,
+ int bar, bool vf_bar, u64 size)
+{
+ bool en = size ? true : false;
+
+ ls_pcie_g4_ep_enable_bar(pcie, pf, bar, vf_bar, en);
+ ls_pcie_g4_ep_set_bar_size(pcie, pf, bar, vf_bar, size);
+}
+
+static void ls_pcie_g4_ep_setup_bars(struct ls_pcie_g4 *pcie, int pf)
+{
+ int bar;
+
+ /* Setup PF BARs */
+ for (bar = 0; bar < PF_BAR_NUM; bar++)
+ ls_pcie_g4_ep_setup_bar(pcie, pf, bar, false, bar_size[bar]);
+
+ if (!pcie->sriov_support)
+ return;
+
+ /* Setup VF BARs */
+ for (bar = 0; bar < VF_BAR_NUM; bar++)
+ ls_pcie_g4_ep_setup_bar(pcie, pf, bar, true, bar_size[bar]);
+}
+
+static void ls_pcie_g4_set_sriov(struct ls_pcie_g4 *pcie, int pf)
+{
+ unsigned int val;
+
+ val = ccsr_readl(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf));
+ val &= ~(TTL_VF_MASK << TTL_VF_SHIFT);
+ val |= PCIE_VF_NUM << TTL_VF_SHIFT;
+ val &= ~(INI_VF_MASK << INI_VF_SHIFT);
+ val |= PCIE_VF_NUM << INI_VF_SHIFT;
+ ccsr_writel(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf), val);
+
+ val = ccsr_readl(pcie, PCIE_SRIOV_VF_OFFSET_STRIDE);
+ val += PCIE_VF_NUM * pf - pf;
+ ccsr_writel(pcie, GPEX_SRIOV_VF_OFFSET_STRIDE(pf), val);
+}
+
+static void ls_pcie_g4_setup_ep(struct ls_pcie_g4 *pcie)
+{
+ u32 pf, sriov;
+ u32 val;
+ int i;
+
+ /* Enable APIO and Memory Win */
+ val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0));
+ val |= APIO_EN | MEM_WIN_EN;
+ ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val);
+
+ sriov = ccsr_readl(pcie, PCIE_SRIOV_CAPABILITY);
+ if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV)
+ pcie->sriov_support = 1;
+
+ pf = pcie->sriov_support ? PCIE_PF_NUM : 1;
+
+ for (i = 0; i < pf; i++) {
+ ls_pcie_g4_ep_setup_bars(pcie, i);
+ ls_pcie_g4_ep_setup_wins(pcie, i);
+ if (pcie->sriov_support)
+ ls_pcie_g4_set_sriov(pcie, i);
+ }
+
+ ls_pcie_g4_ep_enable_cfg(pcie);
+ ls_pcie_g4_dump_wins(pcie, pf);
+}
+
+static int ls_pcie_g4_probe(struct udevice *dev)
+{
+ struct ls_pcie_g4 *pcie = dev_get_priv(dev);
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ u32 link_ctrl_sta;
+ u32 val;
+ int ret;
+
+ pcie->bus = dev;
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "ccsr", &pcie->ccsr_res);
+ if (ret) {
+ printf("ls-pcie-g4: resource \"ccsr\" not found\n");
+ return ret;
+ }
+
+ pcie->idx = (pcie->ccsr_res.start - PCIE_SYS_BASE_ADDR) /
+ PCIE_CCSR_SIZE;
+
+ list_add(&pcie->list, &ls_pcie_g4_list);
+
+ pcie->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx));
+ if (!pcie->enabled) {
+ printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
+ return 0;
+ }
+
+ pcie->ccsr = map_physmem(pcie->ccsr_res.start,
+ fdt_resource_size(&pcie->ccsr_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "config", &pcie->cfg_res);
+ if (ret) {
+ printf("%s: resource \"config\" not found\n", dev->name);
+ return ret;
+ }
+
+ pcie->cfg = map_physmem(pcie->cfg_res.start,
+ fdt_resource_size(&pcie->cfg_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "lut", &pcie->lut_res);
+ if (ret) {
+ printf("ls-pcie-g4: resource \"lut\" not found\n");
+ return ret;
+ }
+
+ pcie->lut = map_physmem(pcie->lut_res.start,
+ fdt_resource_size(&pcie->lut_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "pf_ctrl", &pcie->pf_ctrl_res);
+ if (ret) {
+ printf("ls-pcie-g4: resource \"pf_ctrl\" not found\n");
+ return ret;
+ }
+
+ pcie->pf_ctrl = map_physmem(pcie->pf_ctrl_res.start,
+ fdt_resource_size(&pcie->pf_ctrl_res),
+ MAP_NOCACHE);
+
+ pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian");
+
+ debug("%s ccsr:%lx, cfg:0x%lx, big-endian:%d\n",
+ dev->name, (unsigned long)pcie->ccsr, (unsigned long)pcie->cfg,
+ pcie->big_endian);
+
+ pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
+
+ if (pcie->mode == PCI_HEADER_TYPE_NORMAL) {
+ printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint");
+ ls_pcie_g4_setup_ep(pcie);
+ } else {
+ printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex");
+ ls_pcie_g4_setup_ctrl(pcie);
+ }
+
+ /* Enable Amba & PEX PIO */
+ val = ccsr_readl(pcie, PAB_CTRL);
+ val |= PAB_CTRL_APIO_EN | PAB_CTRL_PPIO_EN;
+ ccsr_writel(pcie, PAB_CTRL, val);
+
+ val = ccsr_readl(pcie, PAB_PEX_PIO_CTRL(0));
+ val |= PPIO_EN;
+ ccsr_writel(pcie, PAB_PEX_PIO_CTRL(0), val);
+
+ if (!ls_pcie_g4_link_up(pcie)) {
+ /* Let the user know there's no PCIe link */
+ printf(": no link\n");
+ return 0;
+ }
+
+ /* Print the negotiated PCIe link width */
+ link_ctrl_sta = ccsr_readl(pcie, PCIE_LINK_CTRL_STA);
+ printf(": x%d gen%d\n",
+ (link_ctrl_sta >> PCIE_LINK_WIDTH_SHIFT & PCIE_LINK_WIDTH_MASK),
+ (link_ctrl_sta >> PCIE_LINK_SPEED_SHIFT) & PCIE_LINK_SPEED_MASK);
+
+ return 0;
+}
+
+static const struct dm_pci_ops ls_pcie_g4_ops = {
+ .read_config = ls_pcie_g4_read_config,
+ .write_config = ls_pcie_g4_write_config,
+};
+
+static const struct udevice_id ls_pcie_g4_ids[] = {
+ { .compatible = "fsl,lx2160a-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_layerscape_gen4) = {
+ .name = "pcie_layerscape_gen4",
+ .id = UCLASS_PCI,
+ .of_match = ls_pcie_g4_ids,
+ .ops = &ls_pcie_g4_ops,
+ .probe = ls_pcie_g4_probe,
+ .priv_auto_alloc_size = sizeof(struct ls_pcie_g4),
+};
diff --git a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h
new file mode 100644
index 0000000000..27c2d09332
--- /dev/null
+++ b/drivers/pci/pcie_layerscape_gen4.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * PCIe Gen4 driver for NXP Layerscape SoCs
+ * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
+ */
+
+#ifndef _PCIE_LAYERSCAPE_GEN4_H_
+#define _PCIE_LAYERSCAPE_GEN4_H_
+#include <pci.h>
+#include <dm.h>
+
+#ifndef CONFIG_SYS_PCI_MEMORY_SIZE
+#define CONFIG_SYS_PCI_MEMORY_SIZE (4 * 1024 * 1024 * 1024ULL)
+#endif
+
+#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE
+#define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR
+#endif
+
+#define PCIE_PF_NUM 2
+#define PCIE_VF_NUM 32
+
+#define LS_G4_PF0 0
+#define LS_G4_PF1 1
+#define PF_BAR_NUM 4
+#define VF_BAR_NUM 4
+#define PCIE_BAR_SIZE (8 * 1024) /* 8K */
+#define PCIE_BAR0_SIZE PCIE_BAR_SIZE
+#define PCIE_BAR1_SIZE PCIE_BAR_SIZE
+#define PCIE_BAR2_SIZE PCIE_BAR_SIZE
+#define PCIE_BAR4_SIZE PCIE_BAR_SIZE
+#define SIZE_1T (1024 * 1024 * 1024 * 1024ULL)
+
+/* GPEX CSR */
+#define GPEX_CLASSCODE 0x474
+#define GPEX_CLASSCODE_SHIFT 16
+#define GPEX_CLASSCODE_MASK 0xffff
+
+#define GPEX_CFG_READY 0x4b0
+#define PCIE_CONFIG_READY BIT(0)
+
+#define GPEX_BAR_ENABLE 0x4d4
+#define GPEX_BAR_SIZE_LDW 0x4d8
+#define GPEX_BAR_SIZE_UDW 0x4dC
+#define GPEX_BAR_SELECT 0x4e0
+
+#define BAR_POS(bar, pf, vf_bar) \
+ ((bar) + (pf) * PF_BAR_NUM + (vf_bar) * PCIE_PF_NUM * PF_BAR_NUM)
+
+#define GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf) (0x644 + (pf) * 4)
+#define TTL_VF_MASK 0xffff
+#define TTL_VF_SHIFT 16
+#define INI_VF_MASK 0xffff
+#define INI_VF_SHIFT 0
+#define GPEX_SRIOV_VF_OFFSET_STRIDE(pf) (0x704 + (pf) * 4)
+
+/* PAB CSR */
+#define PAB_CTRL 0x808
+#define PAB_CTRL_APIO_EN BIT(0)
+#define PAB_CTRL_PPIO_EN BIT(1)
+#define PAB_CTRL_MAX_BRST_LEN_SHIFT 4
+#define PAB_CTRL_MAX_BRST_LEN_MASK 0x3
+#define PAB_CTRL_PAGE_SEL_SHIFT 13
+#define PAB_CTRL_PAGE_SEL_MASK 0x3f
+#define PAB_CTRL_FUNC_SEL_SHIFT 19
+#define PAB_CTRL_FUNC_SEL_MASK 0x1ff
+
+#define PAB_RST_CTRL 0x820
+#define PAB_BR_STAT 0x80c
+
+/* AXI PIO Engines */
+#define PAB_AXI_PIO_CTRL(idx) (0x840 + 0x10 * (idx))
+#define APIO_EN BIT(0)
+#define MEM_WIN_EN BIT(1)
+#define IO_WIN_EN BIT(2)
+#define CFG_WIN_EN BIT(3)
+#define PAB_AXI_PIO_STAT(idx) (0x844 + 0x10 * (idx))
+#define PAB_AXI_PIO_SL_CMD_STAT(idx) (0x848 + 0x10 * (idx))
+#define PAB_AXI_PIO_SL_ADDR_STAT(idx) (0x84c + 0x10 * (idx))
+#define PAB_AXI_PIO_SL_EXT_ADDR_STAT(idx) (0xb8a0 + 0x4 * (idx))
+
+/* PEX PIO Engines */
+#define PAB_PEX_PIO_CTRL(idx) (0x8c0 + 0x10 * (idx))
+#define PPIO_EN BIT(0)
+#define PAB_PEX_PIO_STAT(idx) (0x8c4 + 0x10 * (idx))
+#define PAB_PEX_PIO_MT_STAT(idx) (0x8c8 + 0x10 * (idx))
+
+#define INDIRECT_ADDR_BNDRY 0xc00
+#define PAGE_IDX_SHIFT 10
+#define PAGE_ADDR_MASK 0x3ff
+
+#define OFFSET_TO_PAGE_IDX(off) \
+ (((off) >> PAGE_IDX_SHIFT) & PAB_CTRL_PAGE_SEL_MASK)
+
+#define OFFSET_TO_PAGE_ADDR(off) \
+ (((off) & PAGE_ADDR_MASK) | INDIRECT_ADDR_BNDRY)
+
+/* APIO WINs */
+#define PAB_AXI_AMAP_CTRL(idx) (0xba0 + 0x10 * (idx))
+#define PAB_EXT_AXI_AMAP_SIZE(idx) (0xbaf0 + 0x4 * (idx))
+#define PAB_AXI_AMAP_AXI_WIN(idx) (0xba4 + 0x10 * (idx))
+#define PAB_EXT_AXI_AMAP_AXI_WIN(idx) (0x80a0 + 0x4 * (idx))
+#define PAB_AXI_AMAP_PEX_WIN_L(idx) (0xba8 + 0x10 * (idx))
+#define PAB_AXI_AMAP_PEX_WIN_H(idx) (0xbac + 0x10 * (idx))
+#define PAB_AXI_AMAP_PCI_HDR_PARAM(idx) (0x5ba0 + 0x4 * (idx))
+#define FUNC_NUM_PCIE_MASK GENMASK(7, 0)
+
+#define AXI_AMAP_CTRL_EN BIT(0)
+#define AXI_AMAP_CTRL_TYPE_SHIFT 1
+#define AXI_AMAP_CTRL_TYPE_MASK 0x3
+#define AXI_AMAP_CTRL_SIZE_SHIFT 10
+#define AXI_AMAP_CTRL_SIZE_MASK 0x3fffff
+
+#define PAB_TARGET_BUS(x) (((x) & 0xff) << 24)
+#define PAB_TARGET_DEV(x) (((x) & 0x1f) << 19)
+#define PAB_TARGET_FUNC(x) (((x) & 0x7) << 16)
+
+#define PAB_AXI_TYPE_CFG 0x00
+#define PAB_AXI_TYPE_IO 0x01
+#define PAB_AXI_TYPE_MEM 0x02
+#define PAB_AXI_TYPE_ATOM 0x03
+
+#define PAB_WINS_NUM 256
+
+/* PPIO WINs RC mode */
+#define PAB_PEX_AMAP_CTRL(idx) (0x4ba0 + 0x10 * (idx))
+#define PAB_EXT_PEX_AMAP_SIZE(idx) (0xbef0 + 0x04 * (idx))
+#define PAB_PEX_AMAP_AXI_WIN(idx) (0x4ba4 + 0x10 * (idx))
+#define PAB_EXT_PEX_AMAP_AXI_WIN(idx) (0xb4a0 + 0x04 * (idx))
+#define PAB_PEX_AMAP_PEX_WIN_L(idx) (0x4ba8 + 0x10 * (idx))
+#define PAB_PEX_AMAP_PEX_WIN_H(idx) (0x4bac + 0x10 * (idx))
+
+#define IB_TYPE_MEM_F 0x2
+#define IB_TYPE_MEM_NF 0x3
+
+#define PEX_AMAP_CTRL_TYPE_SHIFT 0x1
+#define PEX_AMAP_CTRL_EN_SHIFT 0x0
+#define PEX_AMAP_CTRL_TYPE_MASK 0x3
+#define PEX_AMAP_CTRL_EN_MASK 0x1
+
+/* PPIO WINs EP mode */
+#define PAB_PEX_BAR_AMAP(pf, bar) \
+ (0x1ba0 + 0x20 * (pf) + 4 * (bar))
+#define BAR_AMAP_EN BIT(0)
+#define PAB_EXT_PEX_BAR_AMAP(pf, bar) \
+ (0x84a0 + 0x20 * (pf) + 4 * (bar))
+
+/* CCSR registers */
+#define PCIE_LINK_CTRL_STA 0x5c
+#define PCIE_LINK_SPEED_SHIFT 16
+#define PCIE_LINK_SPEED_MASK 0x0f
+#define PCIE_LINK_WIDTH_SHIFT 20
+#define PCIE_LINK_WIDTH_MASK 0x3f
+#define PCIE_SRIOV_CAPABILITY 0x2a0
+#define PCIE_SRIOV_VF_OFFSET_STRIDE 0x2b4
+
+/* LUT registers */
+#define PCIE_LUT_UDR(n) (0x800 + (n) * 8)
+#define PCIE_LUT_LDR(n) (0x804 + (n) * 8)
+#define PCIE_LUT_ENABLE BIT(31)
+#define PCIE_LUT_ENTRY_COUNT 32
+
+/* PF control registers */
+#define PCIE_LTSSM_STA 0x7fc
+#define LTSSM_STATE_MASK 0x7f
+#define LTSSM_PCIE_L0 0x2d /* L0 state */
+
+#define PCIE_SRDS_PRTCL(idx) (PCIE1 + (idx))
+#define PCIE_SYS_BASE_ADDR 0x3400000
+#define PCIE_CCSR_SIZE 0x0100000
+
+struct ls_pcie_g4 {
+ int idx;
+ struct list_head list;
+ struct udevice *bus;
+ struct fdt_resource ccsr_res;
+ struct fdt_resource cfg_res;
+ struct fdt_resource lut_res;
+ struct fdt_resource pf_ctrl_res;
+ void __iomem *ccsr;
+ void __iomem *cfg;
+ void __iomem *lut;
+ void __iomem *pf_ctrl;
+ bool big_endian;
+ bool enabled;
+ int next_lut_index;
+ struct pci_controller hose;
+ int stream_id_cur;
+ int mode;
+ int sriov_support;
+};
+
+extern struct list_head ls_pcie_g4_list;
+
+static inline void lut_writel(struct ls_pcie_g4 *pcie, unsigned int value,
+ unsigned int offset)
+{
+ if (pcie->big_endian)
+ out_be32(pcie->lut + offset, value);
+ else
+ out_le32(pcie->lut + offset, value);
+}
+
+static inline u32 lut_readl(struct ls_pcie_g4 *pcie, unsigned int offset)
+{
+ if (pcie->big_endian)
+ return in_be32(pcie->lut + offset);
+ else
+ return in_le32(pcie->lut + offset);
+}
+
+static inline void ccsr_set_page(struct ls_pcie_g4 *pcie, u8 pg_idx)
+{
+ u32 val;
+
+ val = in_le32(pcie->ccsr + PAB_CTRL);
+ val &= ~(PAB_CTRL_PAGE_SEL_MASK << PAB_CTRL_PAGE_SEL_SHIFT);
+ val |= (pg_idx & PAB_CTRL_PAGE_SEL_MASK) << PAB_CTRL_PAGE_SEL_SHIFT;
+
+ out_le32(pcie->ccsr + PAB_CTRL, val);
+}
+
+static inline unsigned int ccsr_readl(struct ls_pcie_g4 *pcie, u32 offset)
+{
+ if (offset < INDIRECT_ADDR_BNDRY) {
+ ccsr_set_page(pcie, 0);
+ return in_le32(pcie->ccsr + offset);
+ }
+
+ ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
+ return in_le32(pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset));
+}
+
+static inline void ccsr_writel(struct ls_pcie_g4 *pcie, u32 offset, u32 value)
+{
+ if (offset < INDIRECT_ADDR_BNDRY) {
+ ccsr_set_page(pcie, 0);
+ out_le32(pcie->ccsr + offset, value);
+ } else {
+ ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
+ out_le32(pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset), value);
+ }
+}
+
+static inline unsigned int pf_ctrl_readl(struct ls_pcie_g4 *pcie, u32 offset)
+{
+ if (pcie->big_endian)
+ return in_be32(pcie->pf_ctrl + offset);
+ else
+ return in_le32(pcie->pf_ctrl + offset);
+}
+
+static inline void pf_ctrl_writel(struct ls_pcie_g4 *pcie, u32 offset,
+ u32 value)
+{
+ if (pcie->big_endian)
+ out_be32(pcie->pf_ctrl + offset, value);
+ else
+ out_le32(pcie->pf_ctrl + offset, value);
+}
+
+#endif /* _PCIE_LAYERSCAPE_GEN4_H_ */
diff --git a/drivers/pci/pcie_layerscape_gen4_fixup.c b/drivers/pci/pcie_layerscape_gen4_fixup.c
new file mode 100644
index 0000000000..1c9e5750bd
--- /dev/null
+++ b/drivers/pci/pcie_layerscape_gen4_fixup.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * PCIe Gen4 driver for NXP Layerscape SoCs
+ * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
+ *
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/arch/fsl_serdes.h>
+#include <asm/io.h>
+#include <errno.h>
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#ifdef CONFIG_ARM
+#include <asm/arch/clock.h>
+#endif
+#include "pcie_layerscape_gen4.h"
+
+#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
+/*
+ * Return next available LUT index.
+ */
+static int ls_pcie_g4_next_lut_index(struct ls_pcie_g4 *pcie)
+{
+ if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
+ return pcie->next_lut_index++;
+
+ return -ENOSPC; /* LUT is full */
+}
+
+/* returns the next available streamid for pcie, -errno if failed */
+static int ls_pcie_g4_next_streamid(struct ls_pcie_g4 *pcie)
+{
+ int stream_id = pcie->stream_id_cur;
+
+ if (stream_id > FSL_PEX_STREAM_ID_NUM)
+ return -EINVAL;
+
+ pcie->stream_id_cur++;
+
+ return stream_id | ((pcie->idx + 1) << 11);
+}
+
+/*
+ * Program a single LUT entry
+ */
+static void ls_pcie_g4_lut_set_mapping(struct ls_pcie_g4 *pcie, int index,
+ u32 devid, u32 streamid)
+{
+ /* leave mask as all zeroes, want to match all bits */
+ lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
+ lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
+}
+
+/*
+ * An msi-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie_g4 *pcie,
+ u32 devid, u32 streamid)
+{
+ u32 *prop;
+ u32 phandle;
+ int nodeoff;
+
+#ifdef CONFIG_FSL_PCIE_COMPAT
+ nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
+ pcie->ccsr_res.start);
+#else
+#error "No CONFIG_FSL_PCIE_COMPAT defined"
+#endif
+ if (nodeoff < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
+ return;
+ }
+
+ /* get phandle to MSI controller */
+ prop = (u32 *)fdt_getprop(blob, nodeoff, "msi-parent", 0);
+ if (!prop) {
+ debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
+ __func__, pcie->idx);
+ return;
+ }
+ phandle = fdt32_to_cpu(*prop);
+
+ /* set one msi-map row */
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", devid);
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", phandle);
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", streamid);
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", 1);
+}
+
+/*
+ * An iommu-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_iommu_map_entry(void *blob, struct ls_pcie_g4 *pcie,
+ u32 devid, u32 streamid)
+{
+ u32 *prop;
+ u32 iommu_map[4];
+ int nodeoff;
+ int lenp;
+
+#ifdef CONFIG_FSL_PCIE_COMPAT
+ nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
+ pcie->ccsr_res.start);
+#else
+#error "No CONFIG_FSL_PCIE_COMPAT defined"
+#endif
+ if (nodeoff < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
+ return;
+ }
+
+ /* get phandle to iommu controller */
+ prop = fdt_getprop_w(blob, nodeoff, "iommu-map", &lenp);
+ if (!prop) {
+ debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
+ __func__, pcie->idx);
+ return;
+ }
+
+ /* set iommu-map row */
+ iommu_map[0] = cpu_to_fdt32(devid);
+ iommu_map[1] = *++prop;
+ iommu_map[2] = cpu_to_fdt32(streamid);
+ iommu_map[3] = cpu_to_fdt32(1);
+
+ if (devid == 0)
+ fdt_setprop_inplace(blob, nodeoff, "iommu-map", iommu_map, 16);
+ else
+ fdt_appendprop(blob, nodeoff, "iommu-map", iommu_map, 16);
+}
+
+static void fdt_fixup_pcie(void *blob)
+{
+ struct udevice *dev, *bus;
+ struct ls_pcie_g4 *pcie;
+ int streamid;
+ int index;
+ pci_dev_t bdf;
+
+ /* Scan all known buses */
+ for (pci_find_first_device(&dev); dev; pci_find_next_device(&dev)) {
+ for (bus = dev; device_is_on_pci_bus(bus);)
+ bus = bus->parent;
+ pcie = dev_get_priv(bus);
+
+ streamid = ls_pcie_g4_next_streamid(pcie);
+ if (streamid < 0) {
+ debug("ERROR: no stream ids free\n");
+ continue;
+ }
+
+ index = ls_pcie_g4_next_lut_index(pcie);
+ if (index < 0) {
+ debug("ERROR: no LUT indexes free\n");
+ continue;
+ }
+
+ /* the DT fixup must be relative to the hose first_busno */
+ bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0);
+ /* map PCI b.d.f to streamID in LUT */
+ ls_pcie_g4_lut_set_mapping(pcie, index, bdf >> 8, streamid);
+ /* update msi-map in device tree */
+ fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8, streamid);
+ /* update iommu-map in device tree */
+ fdt_pcie_set_iommu_map_entry(blob, pcie, bdf >> 8, streamid);
+ }
+}
+#endif
+
+static void ft_pcie_ep_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
+{
+ int off;
+
+ off = fdt_node_offset_by_compat_reg(blob, "fsl,lx2160a-pcie-ep",
+ pcie->ccsr_res.start);
+
+ if (off < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n",
+ __func__);
+ return;
+ }
+
+ if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ else
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+static void ft_pcie_rc_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
+{
+ int off;
+
+#ifdef CONFIG_FSL_PCIE_COMPAT
+ off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
+ pcie->ccsr_res.start);
+#else
+#error "No CONFIG_FSL_PCIE_COMPAT defined"
+#endif
+ if (off < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
+ return;
+ }
+
+ if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ else
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+static void ft_pcie_layerscape_gen4_setup(void *blob, struct ls_pcie_g4 *pcie)
+{
+ ft_pcie_rc_layerscape_gen4_fix(blob, pcie);
+ ft_pcie_ep_layerscape_gen4_fix(blob, pcie);
+}
+
+/* Fixup Kernel DT for PCIe */
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ struct ls_pcie_g4 *pcie;
+
+ list_for_each_entry(pcie, &ls_pcie_g4_list, list)
+ ft_pcie_layerscape_gen4_setup(blob, pcie);
+
+#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
+ fdt_fixup_pcie(blob);
+#endif
+}
+
+#else /* !CONFIG_OF_BOARD_SETUP */
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+}
+#endif
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 102fb91fff..957efb3984 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -147,6 +147,14 @@ config MESON_GXL_USB_PHY
This is the generic phy driver for the Amlogic Meson GXL
USB2 and USB3 PHYS.
+config MESON_G12A_USB_PHY
+ bool "Amlogic Meson G12A USB PHYs"
+ depends on PHY && ARCH_MESON && MESON_G12A
+ imply REGMAP
+ help
+ This is the generic phy driver for the Amlogic Meson G12A
+ USB2 and USB3 PHYS.
+
config MSM8916_USB_PHY
bool "Qualcomm MSM8916 USB PHY support"
depends on PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index b55917bce1..90646ca55b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_PHY_RCAR_GEN3) += phy-rcar-gen3.o
obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o
obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o
+obj-$(CONFIG_MESON_G12A_USB_PHY) += meson-g12a-usb2.o meson-g12a-usb3-pcie.o
obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o
obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c
new file mode 100644
index 0000000000..ad1a77fcfc
--- /dev/null
+++ b/drivers/phy/meson-g12a-usb2.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson G12A USB2 PHY driver
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ */
+
+#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 <reset.h>
+#include <clk.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+#define PHY_CTRL_R0 0x0
+#define PHY_CTRL_R1 0x4
+#define PHY_CTRL_R2 0x8
+#define PHY_CTRL_R3 0xc
+#define PHY_CTRL_R4 0x10
+#define PHY_CTRL_R5 0x14
+#define PHY_CTRL_R6 0x18
+#define PHY_CTRL_R7 0x1c
+#define PHY_CTRL_R8 0x20
+#define PHY_CTRL_R9 0x24
+#define PHY_CTRL_R10 0x28
+#define PHY_CTRL_R11 0x2c
+#define PHY_CTRL_R12 0x30
+#define PHY_CTRL_R13 0x34
+#define PHY_CTRL_R14 0x38
+#define PHY_CTRL_R15 0x3c
+#define PHY_CTRL_R16 0x40
+#define PHY_CTRL_R17 0x44
+#define PHY_CTRL_R18 0x48
+#define PHY_CTRL_R19 0x4c
+#define PHY_CTRL_R20 0x50
+#define PHY_CTRL_R21 0x54
+#define PHY_CTRL_R22 0x58
+#define PHY_CTRL_R23 0x5c
+
+#define RESET_COMPLETE_TIME 1000
+#define PLL_RESET_COMPLETE_TIME 100
+
+struct phy_meson_g12a_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
+ struct reset_ctl reset;
+};
+
+
+static int phy_meson_g12a_usb2_power_on(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+
+#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_g12a_usb2_power_off(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+
+#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;
+}
+
+static int phy_meson_g12a_usb2_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = reset_assert(&priv->reset);
+ udelay(1);
+ ret |= reset_deassert(&priv->reset);
+ if (ret)
+ return ret;
+
+ udelay(RESET_COMPLETE_TIME);
+
+ /* usb2_otg_aca_en == 0 */
+ regmap_update_bits(priv->regmap, PHY_CTRL_R21, BIT(2), 0);
+
+ /* PLL Setup : 24MHz * 20 / 1 = 480MHz */
+ regmap_write(priv->regmap, PHY_CTRL_R16, 0x39400414);
+ regmap_write(priv->regmap, PHY_CTRL_R17, 0x927e0000);
+ regmap_write(priv->regmap, PHY_CTRL_R18, 0xac5f49e5);
+
+ udelay(PLL_RESET_COMPLETE_TIME);
+
+ /* UnReset PLL */
+ regmap_write(priv->regmap, PHY_CTRL_R16, 0x19400414);
+
+ /* PHY Tuning */
+ regmap_write(priv->regmap, PHY_CTRL_R20, 0xfe18);
+ regmap_write(priv->regmap, PHY_CTRL_R4, 0x8000fff);
+
+ /* Tuning Disconnect Threshold */
+ regmap_write(priv->regmap, PHY_CTRL_R3, 0x34);
+
+ /* Analog Settings */
+ regmap_write(priv->regmap, PHY_CTRL_R14, 0);
+ regmap_write(priv->regmap, PHY_CTRL_R13, 0x78000);
+
+ return 0;
+}
+
+static int phy_meson_g12a_usb2_exit(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = reset_assert(&priv->reset);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct phy_ops meson_g12a_usb2_phy_ops = {
+ .init = phy_meson_g12a_usb2_init,
+ .exit = phy_meson_g12a_usb2_exit,
+ .power_on = phy_meson_g12a_usb2_power_on,
+ .power_off = phy_meson_g12a_usb2_power_off,
+};
+
+int meson_g12a_usb2_phy_probe(struct udevice *dev)
+{
+ struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_index(dev, 0, &priv->reset);
+ if (ret == -ENOTSUPP)
+ return 0;
+ else if (ret)
+ return ret;
+
+ ret = reset_deassert(&priv->reset);
+ if (ret) {
+ reset_release_all(&priv->reset, 1);
+ 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_g12a_usb2_phy_ids[] = {
+ { .compatible = "amlogic,g12a-usb2-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_g12a_usb2_phy) = {
+ .name = "meson_g12a_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_g12a_usb2_phy_ids,
+ .probe = meson_g12a_usb2_phy_probe,
+ .ops = &meson_g12a_usb2_phy_ops,
+ .priv_auto_alloc_size = sizeof(struct phy_meson_g12a_usb2_priv),
+};
diff --git a/drivers/phy/meson-g12a-usb3-pcie.c b/drivers/phy/meson-g12a-usb3-pcie.c
new file mode 100644
index 0000000000..920675dc99
--- /dev/null
+++ b/drivers/phy/meson-g12a-usb3-pcie.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Meson G12A USB3+PCIE Combo PHY driver
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <regmap.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <reset.h>
+#include <bitfield.h>
+#include <generic-phy.h>
+
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/bitfield.h>
+
+#define PHY_R0 0x00
+ #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0)
+ #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5)
+
+#define PHY_R1 0x04
+ #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0)
+ #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5)
+ #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10)
+ #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13)
+ #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16)
+ #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21)
+ #define PHY_R1_PHY_REF_CLKDIV2 BIT(24)
+ #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25)
+
+#define PHY_R2 0x08
+ #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0)
+ #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6)
+ #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12)
+ #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18)
+
+#define PHY_R4 0x10
+ #define PHY_R4_PHY_CR_WRITE BIT(0)
+ #define PHY_R4_PHY_CR_READ BIT(1)
+ #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2)
+ #define PHY_R4_PHY_CR_CAP_DATA BIT(18)
+ #define PHY_R4_PHY_CR_CAP_ADDR BIT(19)
+
+#define PHY_R5 0x14
+ #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0)
+ #define PHY_R5_PHY_CR_ACK BIT(16)
+ #define PHY_R5_PHY_BS_OUT BIT(17)
+
+struct phy_g12a_usb3_pcie_priv {
+ struct regmap *regmap;
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+ struct reset_ctl_bulk resets;
+};
+
+static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv,
+ unsigned int addr)
+{
+ unsigned int val, reg;
+ int ret;
+
+ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr);
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ !(val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+phy_g12a_usb3_pcie_cr_bus_read(struct phy_g12a_usb3_pcie_priv *priv,
+ unsigned int addr, unsigned int *data)
+{
+ unsigned int val;
+ int ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, 0);
+ regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val);
+
+ regmap_write(priv->regmap, PHY_R4, 0);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ !(val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+phy_g12a_usb3_pcie_cr_bus_write(struct phy_g12a_usb3_pcie_priv *priv,
+ unsigned int addr, unsigned int data)
+{
+ unsigned int val, reg;
+ int ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr);
+ if (ret)
+ return ret;
+
+ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data);
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK) == 0,
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK),
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ regmap_write(priv->regmap, PHY_R4, reg);
+
+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val,
+ (val & PHY_R5_PHY_CR_ACK) == 0,
+ 5, 1000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+phy_g12a_usb3_pcie_cr_bus_update_bits(struct phy_g12a_usb3_pcie_priv *priv,
+ uint offset, uint mask, uint val)
+{
+ uint reg;
+ int ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_read(priv, offset, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~mask;
+
+ return phy_g12a_usb3_pcie_cr_bus_write(priv, offset, reg | val);
+}
+
+static int phy_meson_g12a_usb3_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
+ unsigned int data;
+ int ret;
+
+ /* TOFIX Handle PCIE mode */
+
+ ret = reset_assert_bulk(&priv->resets);
+ udelay(1);
+ ret |= reset_deassert_bulk(&priv->resets);
+ if (ret)
+ return ret;
+
+ /* Switch PHY to USB3 */
+ regmap_update_bits(priv->regmap, PHY_R0,
+ PHY_R0_PCIE_USB3_SWITCH,
+ PHY_R0_PCIE_USB3_SWITCH);
+
+ /*
+ * WORKAROUND: There is SSPHY suspend bug due to
+ * which USB enumerates
+ * in HS mode instead of SS mode. Workaround it by asserting
+ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus
+ * mode
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x102d,
+ BIT(7), BIT(7));
+ if (ret)
+ return ret;
+
+ ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x1010, 0xff0, 20);
+ if (ret)
+ return ret;
+
+ /*
+ * Fix RX Equalization setting as follows
+ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
+ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
+ * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
+ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1006, &data);
+ if (ret)
+ return ret;
+
+ data &= ~BIT(6);
+ data |= BIT(7);
+ data &= ~(0x7 << 8);
+ data |= (0x3 << 8);
+ data |= (1 << 11);
+ ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1006, data);
+ if (ret)
+ return ret;
+
+ /*
+ * Set EQ and TX launch amplitudes as follows
+ * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
+ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
+ * LANE0.TX_OVRD_DRV_LO.EN set to 1.
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_read(priv, 0x1002, &data);
+ if (ret)
+ return ret;
+
+ data &= ~0x3f80;
+ data |= (0x16 << 7);
+ data &= ~0x7f;
+ data |= (0x7f | BIT(14));
+ ret = phy_g12a_usb3_pcie_cr_bus_write(priv, 0x1002, data);
+ if (ret)
+ return ret;
+
+ /*
+ * MPLL_LOOP_CTL.PROP_CNTRL = 8
+ */
+ ret = phy_g12a_usb3_pcie_cr_bus_update_bits(priv, 0x30,
+ 0xf << 4, 8 << 4);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regmap, PHY_R2,
+ PHY_R2_PHY_TX_VBOOST_LVL,
+ FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4));
+
+ regmap_update_bits(priv->regmap, PHY_R1,
+ PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL,
+ FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) |
+ FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9));
+
+ return ret;
+}
+
+static int phy_meson_g12a_usb3_exit(struct phy *phy)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+ return reset_assert_bulk(&priv->resets);
+}
+
+struct phy_ops meson_g12a_usb3_pcie_phy_ops = {
+ .init = phy_meson_g12a_usb3_init,
+ .exit = phy_meson_g12a_usb3_exit,
+};
+
+int meson_g12a_usb3_pcie_phy_probe(struct udevice *dev)
+{
+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret == -ENOTSUPP)
+ return 0;
+ else 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 != -ENOENT && 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_g12a_usb3_pcie_phy_ids[] = {
+ { .compatible = "amlogic,g12a-usb3-pcie-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_g12a_usb3_pcie_phy) = {
+ .name = "meson_g12a_usb3_pcie_phy",
+ .id = UCLASS_PHY,
+ .of_match = meson_g12a_usb3_pcie_phy_ids,
+ .probe = meson_g12a_usb3_pcie_phy_probe,
+ .ops = &meson_g12a_usb3_pcie_phy_ops,
+ .priv_auto_alloc_size = sizeof(struct phy_g12a_usb3_pcie_priv),
+};
diff --git a/drivers/pinctrl/nxp/pinctrl-imx8.c b/drivers/pinctrl/nxp/pinctrl-imx8.c
index 0738da0ebe..c1b0ca438a 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx8.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx8.c
@@ -25,6 +25,7 @@ static int imx8_pinctrl_probe(struct udevice *dev)
static const struct udevice_id imx8_pinctrl_match[] = {
{ .compatible = "fsl,imx8qxp-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
+ { .compatible = "fsl,imx8qm-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
{ /* sentinel */ }
};
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index 0e6c559d5e..5b1cd29d86 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -116,6 +116,9 @@ static int pinconfig_post_bind(struct udevice *dev)
ofnode node;
int ret;
+ if (!dev_of_valid(dev))
+ return 0;
+
dev_for_each_subnode(node, dev) {
if (pre_reloc_only &&
!ofnode_pre_reloc(node))
@@ -169,6 +172,102 @@ static int pinconfig_post_bind(struct udevice *dev)
}
#endif
+static int
+pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset,
+ struct udevice **pctldev,
+ unsigned int *pin_selector)
+{
+ struct ofnode_phandle_args args;
+ unsigned gpio_offset, pfc_base, pfc_pins;
+ int ret;
+
+ ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
+ 0, &args);
+ if (ret) {
+ dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL,
+ args.node, pctldev);
+ if (ret) {
+ dev_dbg(dev,
+ "%s: uclass_get_device_by_of_offset failed: err=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ gpio_offset = args.args[0];
+ pfc_base = args.args[1];
+ pfc_pins = args.args[2];
+
+ if (offset < gpio_offset || offset > gpio_offset + pfc_pins) {
+ dev_dbg(dev,
+ "%s: GPIO can not be mapped to pincontrol pin\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ offset -= gpio_offset;
+ offset += pfc_base;
+ *pin_selector = offset;
+
+ return 0;
+}
+
+/**
+ * pinctrl_gpio_request() - request a single pin to be used as GPIO
+ *
+ * @dev: GPIO peripheral device
+ * @offset: the GPIO pin offset from the GPIO controller
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
+{
+ const struct pinctrl_ops *ops;
+ struct udevice *pctldev;
+ unsigned int pin_selector;
+ int ret;
+
+ ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset,
+ &pctldev, &pin_selector);
+ if (ret)
+ return ret;
+
+ ops = pinctrl_get_ops(pctldev);
+ if (!ops || !ops->gpio_request_enable)
+ return -ENOTSUPP;
+
+ return ops->gpio_request_enable(pctldev, pin_selector);
+}
+
+/**
+ * pinctrl_gpio_free() - free a single pin used as GPIO
+ *
+ * @dev: GPIO peripheral device
+ * @offset: the GPIO pin offset from the GPIO controller
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_gpio_free(struct udevice *dev, unsigned offset)
+{
+ const struct pinctrl_ops *ops;
+ struct udevice *pctldev;
+ unsigned int pin_selector;
+ int ret;
+
+ ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset,
+ &pctldev, &pin_selector);
+ if (ret)
+ return ret;
+
+ ops = pinctrl_get_ops(pctldev);
+ if (!ops || !ops->gpio_disable_free)
+ return -ENOTSUPP;
+
+ return ops->gpio_disable_free(pctldev, pin_selector);
+}
+
/**
* pinctrl_select_state_simple() - simple implementation of pinctrl_select_state
*
diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig
index 152414ce31..0ffd7fcfd4 100644
--- a/drivers/pinctrl/renesas/Kconfig
+++ b/drivers/pinctrl/renesas/Kconfig
@@ -3,6 +3,7 @@ if ARCH_RMOBILE
config PINCTRL_PFC
bool "Renesas pin control drivers"
depends on DM && ARCH_RMOBILE
+ default n if CPU_RZA1
help
Enable support for clock present on Renesas RCar SoCs.
@@ -116,4 +117,15 @@ config PINCTRL_PFC_R8A77995
the GPIO definitions and pin control functions for each available
multiplex function.
+config PINCTRL_PFC_R7S72100
+ bool "Renesas RZ/A1 R7S72100 pin control driver"
+ depends on CPU_RZA1
+ default y if CPU_RZA1
+ help
+ Support pin multiplexing control on Renesas RZ/A1 R7S72100 SoCs.
+
+ The driver is controlled by a device tree node which contains both
+ the GPIO definitions and pin control functions for each available
+ multiplex function.
+
endif
diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile
index 596b0023a3..e8703f681e 100644
--- a/drivers/pinctrl/renesas/Makefile
+++ b/drivers/pinctrl/renesas/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_PINCTRL_PFC_R8A77965) += pfc-r8a77965.o
obj-$(CONFIG_PINCTRL_PFC_R8A77970) += pfc-r8a77970.o
obj-$(CONFIG_PINCTRL_PFC_R8A77990) += pfc-r8a77990.o
obj-$(CONFIG_PINCTRL_PFC_R8A77995) += pfc-r8a77995.o
+obj-$(CONFIG_PINCTRL_PFC_R7S72100) += pfc-r7s72100.o
diff --git a/drivers/pinctrl/renesas/pfc-r7s72100.c b/drivers/pinctrl/renesas/pfc-r7s72100.c
new file mode 100644
index 0000000000..7e4530d684
--- /dev/null
+++ b/drivers/pinctrl/renesas/pfc-r7s72100.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * R7S72100 processor support
+ *
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#define P(bank) (0x0000 + (bank) * 4)
+#define PSR(bank) (0x0100 + (bank) * 4)
+#define PPR(bank) (0x0200 + (bank) * 4)
+#define PM(bank) (0x0300 + (bank) * 4)
+#define PMC(bank) (0x0400 + (bank) * 4)
+#define PFC(bank) (0x0500 + (bank) * 4)
+#define PFCE(bank) (0x0600 + (bank) * 4)
+#define PNOT(bank) (0x0700 + (bank) * 4)
+#define PMSR(bank) (0x0800 + (bank) * 4)
+#define PMCSR(bank) (0x0900 + (bank) * 4)
+#define PFCAE(bank) (0x0A00 + (bank) * 4)
+#define PIBC(bank) (0x4000 + (bank) * 4)
+#define PBDC(bank) (0x4100 + (bank) * 4)
+#define PIPC(bank) (0x4200 + (bank) * 4)
+
+#define RZA1_PINS_PER_PORT 16
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct r7s72100_pfc_platdata {
+ void __iomem *base;
+};
+
+static void r7s72100_pfc_set_function(struct udevice *dev, u16 bank, u16 line,
+ u16 func, u16 inbuf, u16 bidir)
+{
+ struct r7s72100_pfc_platdata *plat = dev_get_platdata(dev);
+
+ clrsetbits_le16(plat->base + PFCAE(bank), BIT(line),
+ (func & BIT(2)) ? BIT(line) : 0);
+ clrsetbits_le16(plat->base + PFCE(bank), BIT(line),
+ (func & BIT(1)) ? BIT(line) : 0);
+ clrsetbits_le16(plat->base + PFC(bank), BIT(line),
+ (func & BIT(0)) ? BIT(line) : 0);
+
+ clrsetbits_le16(plat->base + PIBC(bank), BIT(line),
+ inbuf ? BIT(line) : 0);
+ clrsetbits_le16(plat->base + PBDC(bank), BIT(line),
+ bidir ? BIT(line) : 0);
+
+ setbits_le32(plat->base + PMCSR(bank), BIT(line + 16) | BIT(line));
+
+ setbits_le16(plat->base + PIPC(bank), BIT(line));
+}
+
+static int r7s72100_pfc_set_state(struct udevice *dev, struct udevice *config)
+{
+ const void *blob = gd->fdt_blob;
+ int node = dev_of_offset(config);
+ u32 cells[32];
+ u16 bank, line, func;
+ int i, count, bidir;
+
+ count = fdtdec_get_int_array_count(blob, node, "pinmux",
+ cells, ARRAY_SIZE(cells));
+ if (count < 0) {
+ printf("%s: bad pinmux array %d\n", __func__, count);
+ return -EINVAL;
+ }
+
+ if (count > ARRAY_SIZE(cells)) {
+ printf("%s: unsupported pinmux array count %d\n",
+ __func__, count);
+ return -EINVAL;
+ }
+
+ for (i = 0 ; i < count; i++) {
+ func = (cells[i] >> 16) & 0xf;
+ if (func == 0 || func > 8) {
+ printf("Invalid cell %i in node %s!\n",
+ count, ofnode_get_name(dev_ofnode(config)));
+ continue;
+ }
+
+ func = (func - 1) & 0x7;
+
+ bank = (cells[i] / RZA1_PINS_PER_PORT) & 0xff;
+ line = cells[i] % RZA1_PINS_PER_PORT;
+
+ bidir = 0;
+ if (bank == 3 && line == 3 && func == 1)
+ bidir = 1;
+
+ r7s72100_pfc_set_function(dev, bank, line, func, 0, bidir);
+ }
+
+ return 0;
+}
+
+const struct pinctrl_ops r7s72100_pfc_ops = {
+ .set_state = r7s72100_pfc_set_state,
+};
+
+static int r7s72100_pfc_probe(struct udevice *dev)
+{
+ struct r7s72100_pfc_platdata *plat = dev_get_platdata(dev);
+ fdt_addr_t addr_base;
+ ofnode node;
+
+ addr_base = devfdt_get_addr(dev);
+ if (addr_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = (void __iomem *)addr_base;
+
+ dev_for_each_subnode(node, dev) {
+ struct udevice *cdev;
+
+ if (!ofnode_read_bool(node, "gpio-controller"))
+ continue;
+
+ device_bind_driver_to_node(dev, "r7s72100-gpio",
+ ofnode_get_name(node),
+ node, &cdev);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id r7s72100_pfc_match[] = {
+ { .compatible = "renesas,r7s72100-ports" },
+ {}
+};
+
+U_BOOT_DRIVER(r7s72100_pfc) = {
+ .name = "r7s72100_pfc",
+ .id = UCLASS_PINCTRL,
+ .of_match = r7s72100_pfc_match,
+ .probe = r7s72100_pfc_probe,
+ .platdata_auto_alloc_size = sizeof(struct r7s72100_pfc_platdata),
+ .ops = &r7s72100_pfc_ops,
+};
diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c
index 06359501b7..d1271dad44 100644
--- a/drivers/pinctrl/renesas/pfc.c
+++ b/drivers/pinctrl/renesas/pfc.c
@@ -459,14 +459,15 @@ static const char *sh_pfc_pinctrl_get_function_name(struct udevice *dev,
return priv->pfc.info->functions[selector].name;
}
-int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector)
+static int sh_pfc_gpio_request_enable(struct udevice *dev,
+ unsigned pin_selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
struct sh_pfc_pin_config *cfg;
const struct sh_pfc_pin *pin = NULL;
- int i, idx;
+ int i, ret, idx;
for (i = 1; i < pfc->info->nr_pins; i++) {
if (priv->pfc.info->pins[i].pin != pin_selector)
@@ -485,7 +486,42 @@ int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector)
if (cfg->type != PINMUX_TYPE_NONE)
return -EBUSY;
- return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO);
+ ret = sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO);
+ if (ret)
+ return ret;
+
+ cfg->type = PINMUX_TYPE_GPIO;
+
+ return 0;
+}
+
+static int sh_pfc_gpio_disable_free(struct udevice *dev,
+ unsigned pin_selector)
+{
+ struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sh_pfc_pinctrl *pmx = &priv->pmx;
+ struct sh_pfc *pfc = &priv->pfc;
+ struct sh_pfc_pin_config *cfg;
+ const struct sh_pfc_pin *pin = NULL;
+ int i, idx;
+
+ for (i = 1; i < pfc->info->nr_pins; i++) {
+ if (priv->pfc.info->pins[i].pin != pin_selector)
+ continue;
+
+ pin = &priv->pfc.info->pins[i];
+ break;
+ }
+
+ if (!pin)
+ return -EINVAL;
+
+ idx = sh_pfc_get_pin_index(pfc, pin->pin);
+ cfg = &pmx->configs[idx];
+
+ cfg->type = PINMUX_TYPE_NONE;
+
+ return 0;
}
static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector,
@@ -746,6 +782,9 @@ static struct pinctrl_ops sh_pfc_pinctrl_ops = {
.pinmux_set = sh_pfc_pinctrl_pin_set,
.pinmux_group_set = sh_pfc_pinctrl_group_set,
.set_state = pinctrl_generic_set_state,
+
+ .gpio_request_enable = sh_pfc_gpio_request_enable,
+ .gpio_disable_free = sh_pfc_gpio_disable_free,
};
static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h
index 09e11d31b3..6629e1f772 100644
--- a/drivers/pinctrl/renesas/sh_pfc.h
+++ b/drivers/pinctrl/renesas/sh_pfc.h
@@ -275,7 +275,6 @@ void sh_pfc_write(struct sh_pfc *pfc, u32 reg, u32 data);
const struct pinmux_bias_reg *
sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin,
unsigned int *bit);
-int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector);
extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3036.c b/drivers/pinctrl/rockchip/pinctrl-rk3036.c
index 2729b03443..28c905129b 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3036.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3036.c
@@ -11,6 +11,30 @@
#include "pinctrl-rockchip.h"
+static int rk3036_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3036_PULL_OFFSET 0x118
#define RK3036_PULL_PINS_PER_REG 16
#define RK3036_PULL_BANK_STRIDE 8
@@ -29,6 +53,27 @@ static void rk3036_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
*bit = pin_num % RK3036_PULL_PINS_PER_REG;
};
+static int rk3036_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit;
+ u32 data;
+
+ if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
+ pull != PIN_CONFIG_BIAS_DISABLE)
+ return -ENOTSUPP;
+
+ rk3036_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ data = BIT(bit + 16);
+ if (pull == PIN_CONFIG_BIAS_DISABLE)
+ data |= BIT(bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
static struct rockchip_pin_bank rk3036_pin_banks[] = {
PIN_BANK(0, 32, "gpio0"),
PIN_BANK(1, 32, "gpio1"),
@@ -36,12 +81,11 @@ static struct rockchip_pin_bank rk3036_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3036_pin_ctrl = {
- .pin_banks = rk3036_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3036_pin_banks),
- .label = "RK3036-GPIO",
- .type = RK3036,
- .grf_mux_offset = 0xa8,
- .pull_calc_reg = rk3036_calc_pull_reg_and_bit,
+ .pin_banks = rk3036_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3036_pin_banks),
+ .grf_mux_offset = 0xa8,
+ .set_mux = rk3036_set_mux,
+ .set_pull = rk3036_set_pull,
};
static const struct udevice_id rk3036_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3128.c b/drivers/pinctrl/rockchip/pinctrl-rk3128.c
index 43a6c173a0..3eb4d952bb 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3128.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3128.c
@@ -98,6 +98,42 @@ static struct rockchip_mux_route_data rk3128_mux_route_data[] = {
},
};
+static int rk3128_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->recalced_mask & BIT(pin))
+ rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3128_PULL_OFFSET 0x118
#define RK3128_PULL_PINS_PER_REG 16
#define RK3128_PULL_BANK_STRIDE 8
@@ -116,6 +152,27 @@ static void rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
*bit = pin_num % RK3128_PULL_PINS_PER_REG;
}
+static int rk3128_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit;
+ u32 data;
+
+ if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
+ pull != PIN_CONFIG_BIAS_DISABLE)
+ return -ENOTSUPP;
+
+ rk3128_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ data = BIT(bit + 16);
+ if (pull == PIN_CONFIG_BIAS_DISABLE)
+ data |= BIT(bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
static struct rockchip_pin_bank rk3128_pin_banks[] = {
PIN_BANK(0, 32, "gpio0"),
PIN_BANK(1, 32, "gpio1"),
@@ -126,14 +183,13 @@ static struct rockchip_pin_bank rk3128_pin_banks[] = {
static struct rockchip_pin_ctrl rk3128_pin_ctrl = {
.pin_banks = rk3128_pin_banks,
.nr_banks = ARRAY_SIZE(rk3128_pin_banks),
- .label = "RK3128-GPIO",
- .type = RK3128,
.grf_mux_offset = 0xa8,
.iomux_recalced = rk3128_mux_recalced_data,
.niomux_recalced = ARRAY_SIZE(rk3128_mux_recalced_data),
.iomux_routes = rk3128_mux_route_data,
.niomux_routes = ARRAY_SIZE(rk3128_mux_route_data),
- .pull_calc_reg = rk3128_calc_pull_reg_and_bit,
+ .set_mux = rk3128_set_mux,
+ .set_pull = rk3128_set_pull,
};
static const struct udevice_id rk3128_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3188.c b/drivers/pinctrl/rockchip/pinctrl-rk3188.c
index 5ed9aec938..043764fc92 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3188.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3188.c
@@ -11,6 +11,30 @@
#include "pinctrl-rockchip.h"
+static int rk3188_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3188_PULL_OFFSET 0x164
#define RK3188_PULL_PMU_OFFSET 0x64
@@ -47,6 +71,33 @@ static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
}
}
+static int rk3188_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3188_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
static struct rockchip_pin_bank rk3188_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_GPIO_ONLY, 0, 0, 0),
PIN_BANK(1, 32, "gpio1"),
@@ -55,12 +106,11 @@ static struct rockchip_pin_bank rk3188_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3188_pin_ctrl = {
- .pin_banks = rk3188_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3188_pin_banks),
- .label = "RK3188-GPIO",
- .type = RK3188,
- .grf_mux_offset = 0x60,
- .pull_calc_reg = rk3188_calc_pull_reg_and_bit,
+ .pin_banks = rk3188_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3188_pin_banks),
+ .grf_mux_offset = 0x60,
+ .set_mux = rk3188_set_mux,
+ .set_pull = rk3188_set_pull,
};
static const struct udevice_id rk3188_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk322x.c b/drivers/pinctrl/rockchip/pinctrl-rk322x.c
index d2a6cd7055..c5e4fe30a7 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk322x.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk322x.c
@@ -141,6 +141,39 @@ static struct rockchip_mux_route_data rk3228_mux_route_data[] = {
},
};
+static int rk3228_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3228_PULL_OFFSET 0x100
static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
@@ -158,6 +191,33 @@ static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
*bit *= ROCKCHIP_PULL_BITS_PER_PIN;
}
+static int rk3228_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3228_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3228_DRV_GRF_OFFSET 0x200
static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
@@ -175,6 +235,29 @@ static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
*bit *= ROCKCHIP_DRV_BITS_PER_PIN;
}
+static int rk3228_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data;
+ u8 bit;
+ int type = bank->drv[pin_num / 8].drv_type;
+
+ rk3228_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+ return ret;
+}
+
static struct rockchip_pin_bank rk3228_pin_banks[] = {
PIN_BANK(0, 32, "gpio0"),
PIN_BANK(1, 32, "gpio1"),
@@ -183,15 +266,14 @@ static struct rockchip_pin_bank rk3228_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3228_pin_ctrl = {
- .pin_banks = rk3228_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3228_pin_banks),
- .label = "RK3228-GPIO",
- .type = RK3288,
- .grf_mux_offset = 0x0,
- .iomux_routes = rk3228_mux_route_data,
- .niomux_routes = ARRAY_SIZE(rk3228_mux_route_data),
- .pull_calc_reg = rk3228_calc_pull_reg_and_bit,
- .drv_calc_reg = rk3228_calc_drv_reg_and_bit,
+ .pin_banks = rk3228_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3228_pin_banks),
+ .grf_mux_offset = 0x0,
+ .iomux_routes = rk3228_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(rk3228_mux_route_data),
+ .set_mux = rk3228_set_mux,
+ .set_pull = rk3228_set_pull,
+ .set_drive = rk3228_set_drive,
};
static const struct udevice_id rk3228_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3288.c b/drivers/pinctrl/rockchip/pinctrl-rk3288.c
index 8b6ce11a63..7ae147f304 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3288.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3288.c
@@ -7,7 +7,6 @@
#include <dm.h>
#include <dm/pinctrl.h>
#include <regmap.h>
-#include <syscon.h>
#include "pinctrl-rockchip.h"
@@ -29,6 +28,47 @@ static struct rockchip_mux_route_data rk3288_mux_route_data[] = {
},
};
+static int rk3288_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ /* bank0 is special, there are no higher 16 bit writing bits. */
+ if (bank->bank_num == 0) {
+ regmap_read(regmap, reg, &data);
+ data &= ~(mask << bit);
+ } else {
+ /* enable the write to the equivalent lower bits */
+ data = (mask << (bit + 16));
+ }
+
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3288_PULL_OFFSET 0x140
#define RK3288_PULL_PMU_OFFSET 0x64
@@ -42,10 +82,6 @@ static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = RK3288_PULL_PMU_OFFSET;
-
- *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
- *bit = pin_num % ROCKCHIP_PULL_PINS_PER_REG;
- *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
} else {
*regmap = priv->regmap_base;
*reg = RK3288_PULL_OFFSET;
@@ -53,11 +89,46 @@ static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
/* correct the offset, as we're starting with the 2nd bank */
*reg -= 0x10;
*reg += bank->bank_num * ROCKCHIP_PULL_BANK_STRIDE;
- *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
+ }
+
+ *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
+ *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+}
+
+static int rk3288_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3288_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
- *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
- *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+ /* bank0 is special, there are no higher 16 bit writing bits */
+ if (bank->bank_num == 0) {
+ regmap_read(regmap, reg, &data);
+ data &= ~(((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << bit);
+ } else {
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
}
+
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
}
#define RK3288_DRV_PMU_OFFSET 0x70
@@ -73,10 +144,6 @@ static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = RK3288_DRV_PMU_OFFSET;
-
- *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
- *bit = pin_num % ROCKCHIP_DRV_PINS_PER_REG;
- *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
} else {
*regmap = priv->regmap_base;
*reg = RK3288_DRV_GRF_OFFSET;
@@ -84,27 +151,48 @@ static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
/* correct the offset, as we're starting with the 2nd bank */
*reg -= 0x10;
*reg += bank->bank_num * ROCKCHIP_DRV_BANK_STRIDE;
- *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
+ }
- *bit = (pin_num % ROCKCHIP_DRV_PINS_PER_REG);
- *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
+ *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
+ *bit = (pin_num % ROCKCHIP_DRV_PINS_PER_REG);
+ *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
+}
+
+static int rk3288_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data;
+ u8 bit;
+ int type = bank->drv[pin_num / 8].drv_type;
+
+ rk3288_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ /* bank0 is special, there are no higher 16 bit writing bits. */
+ if (bank->bank_num == 0) {
+ regmap_read(regmap, reg, &data);
+ data &= ~(((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << bit);
+ } else {
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
}
+
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+ return ret;
}
static struct rockchip_pin_bank rk3288_pin_banks[] = {
- PIN_BANK_IOMUX_DRV_PULL_FLAGS(0, 24, "gpio0",
- IOMUX_SOURCE_PMU | IOMUX_WRITABLE_32BIT,
- IOMUX_SOURCE_PMU | IOMUX_WRITABLE_32BIT,
- IOMUX_SOURCE_PMU | IOMUX_WRITABLE_32BIT,
- IOMUX_UNROUTED,
- DRV_TYPE_WRITABLE_32BIT,
- DRV_TYPE_WRITABLE_32BIT,
- DRV_TYPE_WRITABLE_32BIT,
- 0,
- PULL_TYPE_WRITABLE_32BIT,
- PULL_TYPE_WRITABLE_32BIT,
- PULL_TYPE_WRITABLE_32BIT,
- 0
+ PIN_BANK_IOMUX_FLAGS(0, 24, "gpio0", IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_UNROUTED
),
PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_UNROUTED,
IOMUX_UNROUTED,
@@ -133,16 +221,15 @@ static struct rockchip_pin_bank rk3288_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
- .pin_banks = rk3288_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3288_pin_banks),
- .label = "RK3288-GPIO",
- .type = RK3288,
- .grf_mux_offset = 0x0,
- .pmu_mux_offset = 0x84,
- .iomux_routes = rk3288_mux_route_data,
- .niomux_routes = ARRAY_SIZE(rk3288_mux_route_data),
- .pull_calc_reg = rk3288_calc_pull_reg_and_bit,
- .drv_calc_reg = rk3288_calc_drv_reg_and_bit,
+ .pin_banks = rk3288_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3288_pin_banks),
+ .grf_mux_offset = 0x0,
+ .pmu_mux_offset = 0x84,
+ .iomux_routes = rk3288_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(rk3288_mux_route_data),
+ .set_mux = rk3288_set_mux,
+ .set_pull = rk3288_set_pull,
+ .set_drive = rk3288_set_drive,
};
static const struct udevice_id rk3288_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3328.c b/drivers/pinctrl/rockchip/pinctrl-rk3328.c
index f1b3d10dbe..8d37a6f945 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3328.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3328.c
@@ -121,6 +121,42 @@ static struct rockchip_mux_route_data rk3328_mux_route_data[] = {
},
};
+static int rk3328_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->recalced_mask & BIT(pin))
+ rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3328_PULL_OFFSET 0x100
static void rk3328_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
@@ -138,6 +174,33 @@ static void rk3328_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
*bit *= ROCKCHIP_PULL_BITS_PER_PIN;
}
+static int rk3328_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3328_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3328_DRV_GRF_OFFSET 0x200
static void rk3328_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
@@ -155,6 +218,30 @@ static void rk3328_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
*bit *= ROCKCHIP_DRV_BITS_PER_PIN;
}
+static int rk3328_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data;
+ u8 bit;
+ int type = bank->drv[pin_num / 8].drv_type;
+
+ rk3328_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3328_SCHMITT_BITS_PER_PIN 1
#define RK3328_SCHMITT_PINS_PER_REG 16
#define RK3328_SCHMITT_BANK_STRIDE 8
@@ -177,6 +264,21 @@ static int rk3328_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
return 0;
}
+static int rk3328_set_schmitt(struct rockchip_pin_bank *bank,
+ int pin_num, int enable)
+{
+ struct regmap *regmap;
+ int reg;
+ u8 bit;
+ u32 data;
+
+ rk3328_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ /* enable the write to the equivalent lower bits */
+ data = BIT(bit + 16) | (enable << bit);
+
+ return regmap_write(regmap, reg, data);
+}
+
static struct rockchip_pin_bank rk3328_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", 0, 0, 0, 0),
PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0),
@@ -192,18 +294,17 @@ static struct rockchip_pin_bank rk3328_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3328_pin_ctrl = {
- .pin_banks = rk3328_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3328_pin_banks),
- .label = "RK3328-GPIO",
- .type = RK3288,
- .grf_mux_offset = 0x0,
- .iomux_recalced = rk3328_mux_recalced_data,
- .niomux_recalced = ARRAY_SIZE(rk3328_mux_recalced_data),
- .iomux_routes = rk3328_mux_route_data,
- .niomux_routes = ARRAY_SIZE(rk3328_mux_route_data),
- .pull_calc_reg = rk3328_calc_pull_reg_and_bit,
- .drv_calc_reg = rk3328_calc_drv_reg_and_bit,
- .schmitt_calc_reg = rk3328_calc_schmitt_reg_and_bit,
+ .pin_banks = rk3328_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3328_pin_banks),
+ .grf_mux_offset = 0x0,
+ .iomux_recalced = rk3328_mux_recalced_data,
+ .niomux_recalced = ARRAY_SIZE(rk3328_mux_recalced_data),
+ .iomux_routes = rk3328_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(rk3328_mux_route_data),
+ .set_mux = rk3328_set_mux,
+ .set_pull = rk3328_set_pull,
+ .set_drive = rk3328_set_drive,
+ .set_schmitt = rk3328_set_schmitt,
};
static const struct udevice_id rk3328_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3368.c b/drivers/pinctrl/rockchip/pinctrl-rk3368.c
index f5cd6ff24e..6cb7bb45d9 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3368.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3368.c
@@ -11,6 +11,30 @@
#include "pinctrl-rockchip.h"
+static int rk3368_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3368_PULL_GRF_OFFSET 0x100
#define RK3368_PULL_PMU_OFFSET 0x10
@@ -24,10 +48,6 @@ static void rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = RK3368_PULL_PMU_OFFSET;
-
- *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
- *bit = pin_num % ROCKCHIP_PULL_PINS_PER_REG;
- *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
} else {
*regmap = priv->regmap_base;
*reg = RK3368_PULL_GRF_OFFSET;
@@ -35,11 +55,39 @@ static void rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
/* correct the offset, as we're starting with the 2nd bank */
*reg -= 0x10;
*reg += bank->bank_num * ROCKCHIP_PULL_BANK_STRIDE;
- *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
+ }
+
+ *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
- *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
- *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+ *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
+ *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+}
+
+static int rk3368_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3368_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
}
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
}
#define RK3368_DRV_PMU_OFFSET 0x20
@@ -55,10 +103,6 @@ static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = RK3368_DRV_PMU_OFFSET;
-
- *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
- *bit = pin_num % ROCKCHIP_DRV_PINS_PER_REG;
- *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
} else {
*regmap = priv->regmap_base;
*reg = RK3368_DRV_GRF_OFFSET;
@@ -66,11 +110,35 @@ static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
/* correct the offset, as we're starting with the 2nd bank */
*reg -= 0x10;
*reg += bank->bank_num * ROCKCHIP_DRV_BANK_STRIDE;
- *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
+ }
- *bit = (pin_num % ROCKCHIP_DRV_PINS_PER_REG);
- *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
+ *reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
+ *bit = (pin_num % ROCKCHIP_DRV_PINS_PER_REG);
+ *bit *= ROCKCHIP_DRV_BITS_PER_PIN;
+}
+
+static int rk3368_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data;
+ u8 bit;
+ int type = bank->drv[pin_num / 8].drv_type;
+
+ rk3368_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
}
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
}
static struct rockchip_pin_bank rk3368_pin_banks[] = {
@@ -85,14 +153,13 @@ static struct rockchip_pin_bank rk3368_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
- .pin_banks = rk3368_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3368_pin_banks),
- .label = "RK3368-GPIO",
- .type = RK3368,
- .grf_mux_offset = 0x0,
- .pmu_mux_offset = 0x0,
- .pull_calc_reg = rk3368_calc_pull_reg_and_bit,
- .drv_calc_reg = rk3368_calc_drv_reg_and_bit,
+ .pin_banks = rk3368_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3368_pin_banks),
+ .grf_mux_offset = 0x0,
+ .pmu_mux_offset = 0x0,
+ .set_mux = rk3368_set_mux,
+ .set_pull = rk3368_set_pull,
+ .set_drive = rk3368_set_drive,
};
static const struct udevice_id rk3368_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3399.c b/drivers/pinctrl/rockchip/pinctrl-rk3399.c
index c5aab647a5..75634e9f4d 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rk3399.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3399.c
@@ -50,6 +50,39 @@ static struct rockchip_mux_route_data rk3399_mux_route_data[] = {
},
};
+static int rk3399_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data, route_reg, route_val;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->route_mask & BIT(pin)) {
+ if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
+ &route_val)) {
+ ret = regmap_write(regmap, route_reg, route_val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RK3399_PULL_GRF_OFFSET 0xe040
#define RK3399_PULL_PMU_OFFSET 0x40
@@ -65,10 +98,6 @@ static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
*reg = RK3399_PULL_PMU_OFFSET;
*reg += bank->bank_num * ROCKCHIP_PULL_BANK_STRIDE;
-
- *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
- *bit = pin_num % ROCKCHIP_PULL_PINS_PER_REG;
- *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
} else {
*regmap = priv->regmap_base;
*reg = RK3399_PULL_GRF_OFFSET;
@@ -76,11 +105,39 @@ static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
/* correct the offset, as we're starting with the 3rd bank */
*reg -= 0x20;
*reg += bank->bank_num * ROCKCHIP_PULL_BANK_STRIDE;
- *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
+ }
+
+ *reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
+ *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+}
+
+static int rk3399_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
- *bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
- *bit *= ROCKCHIP_PULL_BITS_PER_PIN;
+ rk3399_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
}
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
}
static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
@@ -104,6 +161,79 @@ static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
*bit = (pin_num % 8) * 2;
}
+static int rk3399_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data, rmask_bits, temp;
+ u8 bit;
+ int drv_type = bank->drv[pin_num / 8].drv_type;
+
+ rk3399_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(drv_type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ switch (drv_type) {
+ case DRV_TYPE_IO_1V8_3V0_AUTO:
+ case DRV_TYPE_IO_3V3_ONLY:
+ rmask_bits = ROCKCHIP_DRV_3BITS_PER_PIN;
+ switch (bit) {
+ case 0 ... 12:
+ /* regular case, nothing to do */
+ break;
+ case 15:
+ /*
+ * drive-strength offset is special, as it is spread
+ * over 2 registers, the bit data[15] contains bit 0
+ * of the value while temp[1:0] contains bits 2 and 1
+ */
+ data = (ret & 0x1) << 15;
+ temp = (ret >> 0x1) & 0x3;
+
+ data |= BIT(31);
+ ret = regmap_write(regmap, reg, data);
+ if (ret)
+ return ret;
+
+ temp |= (0x3 << 16);
+ reg += 0x4;
+ ret = regmap_write(regmap, reg, temp);
+
+ return ret;
+ case 18 ... 21:
+ /* setting fully enclosed in the second register */
+ reg += 4;
+ bit -= 16;
+ break;
+ default:
+ debug("unsupported bit: %d for pinctrl drive type: %d\n",
+ bit, drv_type);
+ return -EINVAL;
+ }
+ break;
+ case DRV_TYPE_IO_DEFAULT:
+ case DRV_TYPE_IO_1V8_OR_3V0:
+ case DRV_TYPE_IO_1V8_ONLY:
+ rmask_bits = ROCKCHIP_DRV_BITS_PER_PIN;
+ break;
+ default:
+ debug("unsupported pinctrl drive type: %d\n",
+ drv_type);
+ return -EINVAL;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << rmask_bits) - 1) << (bit + 16);
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
static struct rockchip_pin_bank rk3399_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(0, 32, "gpio0",
IOMUX_SOURCE_PMU,
@@ -158,18 +288,17 @@ static struct rockchip_pin_bank rk3399_pin_banks[] = {
};
static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
- .pin_banks = rk3399_pin_banks,
- .nr_banks = ARRAY_SIZE(rk3399_pin_banks),
- .label = "RK3399-GPIO",
- .type = RK3399,
- .grf_mux_offset = 0xe000,
- .pmu_mux_offset = 0x0,
- .grf_drv_offset = 0xe100,
- .pmu_drv_offset = 0x80,
- .iomux_routes = rk3399_mux_route_data,
- .niomux_routes = ARRAY_SIZE(rk3399_mux_route_data),
- .pull_calc_reg = rk3399_calc_pull_reg_and_bit,
- .drv_calc_reg = rk3399_calc_drv_reg_and_bit,
+ .pin_banks = rk3399_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3399_pin_banks),
+ .grf_mux_offset = 0xe000,
+ .pmu_mux_offset = 0x0,
+ .grf_drv_offset = 0xe100,
+ .pmu_drv_offset = 0x80,
+ .iomux_routes = rk3399_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(rk3399_mux_route_data),
+ .set_mux = rk3399_set_mux,
+ .set_pull = rk3399_set_pull,
+ .set_drive = rk3399_set_drive,
};
static const struct udevice_id rk3399_pinctrl_ids[] = {
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
index ce935656f0..80dc431d20 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
@@ -35,8 +35,8 @@ static int rockchip_verify_config(struct udevice *dev, u32 bank, u32 pin)
return 0;
}
-static void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
- int *reg, u8 *bit, int *mask)
+void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
+ int *reg, u8 *bit, int *mask)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
struct rockchip_pin_ctrl *ctrl = priv->ctrl;
@@ -58,8 +58,8 @@ static void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
*bit = data->bit;
}
-static bool rockchip_get_mux_route(struct rockchip_pin_bank *bank, int pin,
- int mux, u32 *reg, u32 *value)
+bool rockchip_get_mux_route(struct rockchip_pin_bank *bank, int pin,
+ int mux, u32 *reg, u32 *value)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
struct rockchip_pin_ctrl *ctrl = priv->ctrl;
@@ -82,7 +82,7 @@ static bool rockchip_get_mux_route(struct rockchip_pin_bank *bank, int pin,
return true;
}
-static int rockchip_get_mux_data(int mux_type, int pin, u8 *bit, int *mask)
+int rockchip_get_mux_data(int mux_type, int pin, u8 *bit, int *mask)
{
int offset = 0;
@@ -193,11 +193,9 @@ static int rockchip_verify_mux(struct rockchip_pin_bank *bank,
static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
+ struct rockchip_pin_ctrl *ctrl = priv->ctrl;
int iomux_num = (pin / 8);
- struct regmap *regmap;
- int reg, ret, mask, mux_type;
- u8 bit;
- u32 data, route_reg, route_val;
+ int ret;
ret = rockchip_verify_mux(bank, pin, mux);
if (ret < 0)
@@ -208,35 +206,10 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
debug("setting mux of GPIO%d-%d to %d\n", bank->bank_num, pin, mux);
- regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
- ? priv->regmap_pmu : priv->regmap_base;
+ if (!ctrl->set_mux)
+ return -ENOTSUPP;
- /* get basic quadrupel of mux registers and the correct reg inside */
- mux_type = bank->iomux[iomux_num].type;
- reg = bank->iomux[iomux_num].offset;
- reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
-
- if (bank->recalced_mask & BIT(pin))
- rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
-
- if (bank->route_mask & BIT(pin)) {
- if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
- &route_val)) {
- ret = regmap_write(regmap, route_reg, route_val);
- if (ret)
- return ret;
- }
- }
-
- if (mux_type & IOMUX_WRITABLE_32BIT) {
- regmap_read(regmap, reg, &data);
- data &= ~(mask << bit);
- } else {
- data = (mask << (bit + 16));
- }
-
- data |= (mux & mask) << bit;
- ret = regmap_write(regmap, reg, data);
+ ret = ctrl->set_mux(bank, pin, mux);
return ret;
}
@@ -249,99 +222,37 @@ static int rockchip_perpin_drv_list[DRV_TYPE_MAX][8] = {
{ 4, 7, 10, 13, 16, 19, 22, 26 }
};
-static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
- int pin_num, int strength)
+int rockchip_translate_drive_value(int type, int strength)
{
- struct rockchip_pinctrl_priv *priv = bank->priv;
- struct rockchip_pin_ctrl *ctrl = priv->ctrl;
- struct regmap *regmap;
- int reg, ret, i;
- u32 data, rmask_bits, temp;
- u8 bit;
- /* Where need to clean the special mask for rockchip_perpin_drv_list */
- int drv_type = bank->drv[pin_num / 8].drv_type & (~DRV_TYPE_IO_MASK);
-
- debug("setting drive of GPIO%d-%d to %d\n", bank->bank_num,
- pin_num, strength);
-
- ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
+ int i, ret;
ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list[drv_type]); i++) {
- if (rockchip_perpin_drv_list[drv_type][i] == strength) {
+ for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list[type]); i++) {
+ if (rockchip_perpin_drv_list[type][i] == strength) {
ret = i;
break;
- } else if (rockchip_perpin_drv_list[drv_type][i] < 0) {
- ret = rockchip_perpin_drv_list[drv_type][i];
+ } else if (rockchip_perpin_drv_list[type][i] < 0) {
+ ret = rockchip_perpin_drv_list[type][i];
break;
}
}
- if (ret < 0) {
- debug("unsupported driver strength %d\n", strength);
- return ret;
- }
-
- switch (drv_type) {
- case DRV_TYPE_IO_1V8_3V0_AUTO:
- case DRV_TYPE_IO_3V3_ONLY:
- rmask_bits = ROCKCHIP_DRV_3BITS_PER_PIN;
- switch (bit) {
- case 0 ... 12:
- /* regular case, nothing to do */
- break;
- case 15:
- /*
- * drive-strength offset is special, as it is spread
- * over 2 registers, the bit data[15] contains bit 0
- * of the value while temp[1:0] contains bits 2 and 1
- */
- data = (ret & 0x1) << 15;
- temp = (ret >> 0x1) & 0x3;
-
- data |= BIT(31);
- ret = regmap_write(regmap, reg, data);
- if (ret)
- return ret;
+ return ret;
+}
- temp |= (0x3 << 16);
- reg += 0x4;
- ret = regmap_write(regmap, reg, temp);
+static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ struct rockchip_pin_ctrl *ctrl = priv->ctrl;
- return ret;
- case 18 ... 21:
- /* setting fully enclosed in the second register */
- reg += 4;
- bit -= 16;
- break;
- default:
- debug("unsupported bit: %d for pinctrl drive type: %d\n",
- bit, drv_type);
- return -EINVAL;
- }
- break;
- case DRV_TYPE_IO_DEFAULT:
- case DRV_TYPE_IO_1V8_OR_3V0:
- case DRV_TYPE_IO_1V8_ONLY:
- rmask_bits = ROCKCHIP_DRV_BITS_PER_PIN;
- break;
- default:
- debug("unsupported pinctrl drive type: %d\n",
- drv_type);
- return -EINVAL;
- }
+ debug("setting drive of GPIO%d-%d to %d\n", bank->bank_num,
+ pin_num, strength);
- if (bank->drv[pin_num / 8].drv_type & DRV_TYPE_WRITABLE_32BIT) {
- regmap_read(regmap, reg, &data);
- data &= ~(((1 << rmask_bits) - 1) << bit);
- } else {
- /* enable the write to the equivalent lower bits */
- data = ((1 << rmask_bits) - 1) << (bit + 16);
- }
+ if (!ctrl->set_drive)
+ return -ENOTSUPP;
- data |= (ret << bit);
- ret = regmap_write(regmap, reg, data);
- return ret;
+ return ctrl->set_drive(bank, pin_num, strength);
}
static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
@@ -359,70 +270,35 @@ static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
},
};
+int rockchip_translate_pull_value(int type, int pull)
+{
+ int i, ret;
+
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[type]);
+ i++) {
+ if (rockchip_pull_list[type][i] == pull) {
+ ret = i;
+ break;
+ }
+ }
+
+ return ret;
+}
+
static int rockchip_set_pull(struct rockchip_pin_bank *bank,
int pin_num, int pull)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
struct rockchip_pin_ctrl *ctrl = priv->ctrl;
- struct regmap *regmap;
- int reg, ret, i, pull_type;
- u8 bit;
- u32 data;
debug("setting pull of GPIO%d-%d to %d\n", bank->bank_num,
pin_num, pull);
- ctrl->pull_calc_reg(bank, pin_num, &regmap, &reg, &bit);
+ if (!ctrl->set_pull)
+ return -ENOTSUPP;
- switch (ctrl->type) {
- case RK3036:
- case RK3128:
- data = BIT(bit + 16);
- if (pull == PIN_CONFIG_BIAS_DISABLE)
- data |= BIT(bit);
- ret = regmap_write(regmap, reg, data);
- break;
- case RV1108:
- case RK3188:
- case RK3288:
- case RK3368:
- case RK3399:
- /*
- * Where need to clean the special mask for
- * rockchip_pull_list.
- */
- pull_type = bank->pull_type[pin_num / 8] & (~PULL_TYPE_IO_MASK);
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[pull_type]);
- i++) {
- if (rockchip_pull_list[pull_type][i] == pull) {
- ret = i;
- break;
- }
- }
-
- if (ret < 0) {
- debug("unsupported pull setting %d\n", pull);
- return ret;
- }
-
- if (bank->pull_type[pin_num / 8] & PULL_TYPE_WRITABLE_32BIT) {
- regmap_read(regmap, reg, &data);
- data &= ~(((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << bit);
- } else {
- /* enable the write to the equivalent lower bits */
- data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
- }
-
- data |= (ret << bit);
- ret = regmap_write(regmap, reg, data);
- break;
- default:
- debug("unsupported pinctrl type\n");
- return -EINVAL;
- }
-
- return ret;
+ return ctrl->set_pull(bank, pin_num, pull);
}
static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
@@ -430,89 +306,40 @@ static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
{
struct rockchip_pinctrl_priv *priv = bank->priv;
struct rockchip_pin_ctrl *ctrl = priv->ctrl;
- struct regmap *regmap;
- int reg, ret;
- u8 bit;
- u32 data;
debug("setting input schmitt of GPIO%d-%d to %d\n", bank->bank_num,
pin_num, enable);
- ret = ctrl->schmitt_calc_reg(bank, pin_num, &regmap, &reg, &bit);
- if (ret)
- return ret;
-
- /* enable the write to the equivalent lower bits */
- data = BIT(bit + 16) | (enable << bit);
-
- return regmap_write(regmap, reg, data);
-}
-
-/*
- * Pinconf_ops handling
- */
-static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
- unsigned int pull)
-{
- switch (ctrl->type) {
- case RK3036:
- case RK3128:
- return (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT ||
- pull == PIN_CONFIG_BIAS_DISABLE);
- case RV1108:
- case RK3188:
- case RK3288:
- case RK3368:
- case RK3399:
- return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT);
- }
+ if (!ctrl->set_schmitt)
+ return -ENOTSUPP;
- return false;
+ return ctrl->set_schmitt(bank, pin_num, enable);
}
/* set the pin config settings for a specified pin */
static int rockchip_pinconf_set(struct rockchip_pin_bank *bank,
u32 pin, u32 param, u32 arg)
{
- struct rockchip_pinctrl_priv *priv = bank->priv;
- struct rockchip_pin_ctrl *ctrl = priv->ctrl;
int rc;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- rc = rockchip_set_pull(bank, pin, param);
- if (rc)
- return rc;
- break;
-
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
case PIN_CONFIG_BIAS_BUS_HOLD:
- if (!rockchip_pinconf_pull_valid(ctrl, param))
- return -ENOTSUPP;
-
- if (!arg)
- return -EINVAL;
-
rc = rockchip_set_pull(bank, pin, param);
if (rc)
return rc;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- if (!ctrl->drv_calc_reg)
- return -ENOTSUPP;
-
rc = rockchip_set_drive_perpin(bank, pin, arg);
if (rc < 0)
return rc;
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
- if (!ctrl->schmitt_calc_reg)
- return -ENOTSUPP;
-
rc = rockchip_set_schmitt(bank, pin, arg);
if (rc < 0)
return rc;
@@ -530,9 +357,8 @@ static const struct pinconf_param rockchip_conf_params[] = {
{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+ { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
- { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
- { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
};
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip.h b/drivers/pinctrl/rockchip/pinctrl-rockchip.h
index 5a6849c996..9651e9c7a6 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip.h
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip.h
@@ -8,16 +8,6 @@
#include <linux/types.h>
-enum rockchip_pinctrl_type {
- RV1108,
- RK3036,
- RK3128,
- RK3188,
- RK3288,
- RK3368,
- RK3399,
-};
-
/**
* Encode variants of iomux registers into a type variable
*/
@@ -26,7 +16,6 @@ enum rockchip_pinctrl_type {
#define IOMUX_SOURCE_PMU BIT(2)
#define IOMUX_UNROUTED BIT(3)
#define IOMUX_WIDTH_3BIT BIT(4)
-#define IOMUX_WRITABLE_32BIT BIT(5)
/**
* Defined some common pins constants
@@ -50,9 +39,6 @@ struct rockchip_iomux {
int offset;
};
-#define DRV_TYPE_IO_MASK GENMASK(31, 16)
-#define DRV_TYPE_WRITABLE_32BIT BIT(31)
-
/**
* enum type index corresponding to rockchip_perpin_drv_list arrays index.
*/
@@ -65,9 +51,6 @@ enum rockchip_pin_drv_type {
DRV_TYPE_MAX
};
-#define PULL_TYPE_IO_MASK GENMASK(31, 16)
-#define PULL_TYPE_WRITABLE_32BIT BIT(31)
-
/**
* enum type index corresponding to rockchip_pull_list arrays index.
*/
@@ -207,32 +190,6 @@ struct rockchip_pin_bank {
}, \
}
-#define PIN_BANK_IOMUX_DRV_PULL_FLAGS(id, pins, label, iom0, iom1, \
- iom2, iom3, drv0, drv1, drv2, \
- drv3, pull0, pull1, pull2, \
- pull3) \
- { \
- .bank_num = id, \
- .nr_pins = pins, \
- .name = label, \
- .iomux = { \
- { .type = iom0, .offset = -1 }, \
- { .type = iom1, .offset = -1 }, \
- { .type = iom2, .offset = -1 }, \
- { .type = iom3, .offset = -1 }, \
- }, \
- .drv = { \
- { .drv_type = drv0, .offset = -1 }, \
- { .drv_type = drv1, .offset = -1 }, \
- { .drv_type = drv2, .offset = -1 }, \
- { .drv_type = drv3, .offset = -1 }, \
- }, \
- .pull_type[0] = pull0, \
- .pull_type[1] = pull1, \
- .pull_type[2] = pull2, \
- .pull_type[3] = pull3, \
- }
-
#define PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(id, pins, \
label, iom0, iom1, iom2, \
iom3, drv0, drv1, drv2, \
@@ -299,8 +256,6 @@ struct rockchip_pin_ctrl {
struct rockchip_pin_bank *pin_banks;
u32 nr_banks;
u32 nr_pins;
- char *label;
- enum rockchip_pinctrl_type type;
int grf_mux_offset;
int pmu_mux_offset;
int grf_drv_offset;
@@ -310,15 +265,14 @@ struct rockchip_pin_ctrl {
struct rockchip_mux_route_data *iomux_routes;
u32 niomux_routes;
- void (*pull_calc_reg)(struct rockchip_pin_bank *bank,
- int pin_num, struct regmap **regmap,
- int *reg, u8 *bit);
- void (*drv_calc_reg)(struct rockchip_pin_bank *bank,
- int pin_num, struct regmap **regmap,
- int *reg, u8 *bit);
- int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank,
- int pin_num, struct regmap **regmap,
- int *reg, u8 *bit);
+ int (*set_mux)(struct rockchip_pin_bank *bank,
+ int pin, int mux);
+ int (*set_pull)(struct rockchip_pin_bank *bank,
+ int pin_num, int pull);
+ int (*set_drive)(struct rockchip_pin_bank *bank,
+ int pin_num, int strength);
+ int (*set_schmitt)(struct rockchip_pin_bank *bank,
+ int pin_num, int enable);
};
/**
@@ -331,5 +285,12 @@ struct rockchip_pinctrl_priv {
extern const struct pinctrl_ops rockchip_pinctrl_ops;
int rockchip_pinctrl_probe(struct udevice *dev);
+void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
+ int *reg, u8 *bit, int *mask);
+bool rockchip_get_mux_route(struct rockchip_pin_bank *bank, int pin,
+ int mux, u32 *reg, u32 *value);
+int rockchip_get_mux_data(int mux_type, int pin, u8 *bit, int *mask);
+int rockchip_translate_drive_value(int type, int strength);
+int rockchip_translate_pull_value(int type, int pull);
#endif /* __DRIVERS_PINCTRL_ROCKCHIP_H */
diff --git a/drivers/pinctrl/rockchip/pinctrl-rv1108.c b/drivers/pinctrl/rockchip/pinctrl-rv1108.c
index f4a09a6824..54610a3e90 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rv1108.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rv1108.c
@@ -75,6 +75,33 @@ static struct rockchip_mux_recalced_data rv1108_mux_recalced_data[] = {
},
};
+static int rv1108_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, ret, mask, mux_type;
+ u8 bit;
+ u32 data;
+
+ regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ ? priv->regmap_pmu : priv->regmap_base;
+
+ /* get basic quadrupel of mux registers and the correct reg inside */
+ mux_type = bank->iomux[iomux_num].type;
+ reg = bank->iomux[iomux_num].offset;
+ reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+ if (bank->recalced_mask & BIT(pin))
+ rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
+
+ data = (mask << (bit + 16));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RV1108_PULL_PMU_OFFSET 0x10
#define RV1108_PULL_OFFSET 0x110
@@ -101,6 +128,34 @@ static void rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
*bit *= ROCKCHIP_PULL_BITS_PER_PIN;
}
+static int rv1108_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rv1108_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ type = bank->pull_type[pin_num / 8];
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
#define RV1108_DRV_PMU_OFFSET 0x20
#define RV1108_DRV_GRF_OFFSET 0x210
@@ -128,6 +183,30 @@ static void rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
*bit *= ROCKCHIP_DRV_BITS_PER_PIN;
}
+static int rv1108_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data;
+ u8 bit;
+ int type = bank->drv[pin_num / 8].drv_type;
+
+ rv1108_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ret = rockchip_translate_drive_value(type, strength);
+ if (ret < 0) {
+ debug("unsupported driver strength %d\n", strength);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+ return ret;
+}
+
#define RV1108_SCHMITT_PMU_OFFSET 0x30
#define RV1108_SCHMITT_GRF_OFFSET 0x388
#define RV1108_SCHMITT_BANK_STRIDE 8
@@ -158,6 +237,21 @@ static int rv1108_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
return 0;
}
+static int rv1108_set_schmitt(struct rockchip_pin_bank *bank,
+ int pin_num, int enable)
+{
+ struct regmap *regmap;
+ int reg;
+ u8 bit;
+ u32 data;
+
+ rv1108_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ /* enable the write to the equivalent lower bits */
+ data = BIT(bit + 16) | (enable << bit);
+
+ return regmap_write(regmap, reg, data);
+}
+
static struct rockchip_pin_bank rv1108_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
IOMUX_SOURCE_PMU,
@@ -171,15 +265,14 @@ static struct rockchip_pin_bank rv1108_pin_banks[] = {
static struct rockchip_pin_ctrl rv1108_pin_ctrl = {
.pin_banks = rv1108_pin_banks,
.nr_banks = ARRAY_SIZE(rv1108_pin_banks),
- .label = "RV1108-GPIO",
- .type = RV1108,
.grf_mux_offset = 0x10,
.pmu_mux_offset = 0x0,
.iomux_recalced = rv1108_mux_recalced_data,
.niomux_recalced = ARRAY_SIZE(rv1108_mux_recalced_data),
- .pull_calc_reg = rv1108_calc_pull_reg_and_bit,
- .drv_calc_reg = rv1108_calc_drv_reg_and_bit,
- .schmitt_calc_reg = rv1108_calc_schmitt_reg_and_bit,
+ .set_mux = rv1108_set_mux,
+ .set_pull = rv1108_set_pull,
+ .set_drive = rv1108_set_drive,
+ .set_schmitt = rv1108_set_schmitt,
};
static const struct udevice_id rv1108_pinctrl_ids[] = {
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c
index 9994cbafbf..88db294cf1 100644
--- a/drivers/pwm/rk_pwm.c
+++ b/drivers/pwm/rk_pwm.c
@@ -12,7 +12,7 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/pwm.h>
+#include <asm/arch-rockchip/pwm.h>
#include <power/regulator.h>
struct rk_pwm_priv {
diff --git a/drivers/qe/Kconfig b/drivers/qe/Kconfig
index 49a6e32b16..864b36b822 100644
--- a/drivers/qe/Kconfig
+++ b/drivers/qe/Kconfig
@@ -1,6 +1,14 @@
#
# QUICC Engine Drivers
#
+config QE
+ bool "Enable support for QUICC Engine"
+ depends on PPC
+ default y if ARCH_T1040 || ARCH_T1042 || ARCH_T1024 || ARCH_P1021 \
+ || ARCH_P1025
+ help
+ Chose this option to add support for the QUICC Engine.
+
config U_QE
bool "Enable support for U QUICC Engine"
default y if (ARCH_LS1021A && !SD_BOOT && !NAND_BOOT && !QSPI_BOOT) \
@@ -10,3 +18,28 @@ config U_QE
|| (TARGET_LS1043ARDB && !SPL_NO_QE && !NAND_BOOT && !QSPI_BOOT)
help
Choose this option to add support for U QUICC Engine.
+
+choice
+ prompt "QUICC Engine FMan ethernet firmware location"
+ depends on FMAN_ENET || QE
+ default SYS_QE_FMAN_FW_IN_ROM
+
+config SYS_QE_FMAN_FW_IN_NOR
+ bool "NOR flash"
+
+config SYS_QE_FMAN_FW_IN_NAND
+ bool "NAND flash"
+
+config SYS_QE_FMAN_FW_IN_SPIFLASH
+ bool "SPI flash"
+
+config SYS_QE_FMAN_FW_IN_MMC
+ bool "MMC"
+
+config SYS_QE_FMAN_FW_IN_REMOTE
+ bool "Remote memory location (PCI)"
+
+config SYS_QE_FMAN_FW_IN_ROM
+ bool "Firmware is already in ROM"
+
+endchoice
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 70d02d3f93..505ae9b45f 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -119,7 +119,7 @@ static void qe_sdma_init(void)
*/
static u8 thread_snum[] = {
/* Evthreads 16-29 are not supported in MPC8309 */
-#if !defined(CONFIG_MPC8309)
+#if !defined(CONFIG_ARCH_MPC8309)
0x04, 0x05, 0x0c, 0x0d,
0x14, 0x15, 0x1c, 0x1d,
0x24, 0x25, 0x2c, 0x2d,
diff --git a/drivers/ram/mpc83xx_sdram.c b/drivers/ram/mpc83xx_sdram.c
index 441baeb6f1..f03d0428b2 100644
--- a/drivers/ram/mpc83xx_sdram.c
+++ b/drivers/ram/mpc83xx_sdram.c
@@ -169,8 +169,8 @@ static int mpc83xx_sdram_static_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
odt_rd_cfg = ofnode_read_u32_default(node, "odt_rd_cfg", 0);
switch (odt_rd_cfg) {
case ODT_RD_ONLY_OTHER_DIMM:
- if (!IS_ENABLED(CONFIG_MPC8360) &&
- !IS_ENABLED(CONFIG_MPC837x)) {
+ if (!IS_ENABLED(CONFIG_ARCH_MPC8360) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC837X)) {
debug("%s: odt_rd_cfg value %d invalid.\n",
ofnode_get_name(node), odt_rd_cfg);
return -EINVAL;
@@ -179,10 +179,10 @@ static int mpc83xx_sdram_static_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
case ODT_RD_NEVER:
case ODT_RD_ONLY_CURRENT:
case ODT_RD_ONLY_OTHER_CS:
- if (!IS_ENABLED(CONFIG_MPC830x) &&
- !IS_ENABLED(CONFIG_MPC831x) &&
- !IS_ENABLED(CONFIG_MPC8360) &&
- !IS_ENABLED(CONFIG_MPC837x)) {
+ if (!IS_ENABLED(CONFIG_ARCH_MPC830X) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC831X) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC8360) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC837X)) {
debug("%s: odt_rd_cfg value %d invalid.\n",
ofnode_get_name(node), odt_rd_cfg);
return -EINVAL;
@@ -200,8 +200,8 @@ static int mpc83xx_sdram_static_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
odt_wr_cfg = ofnode_read_u32_default(node, "odt_wr_cfg", 0);
switch (odt_wr_cfg) {
case ODT_WR_ONLY_OTHER_DIMM:
- if (!IS_ENABLED(CONFIG_MPC8360) &&
- !IS_ENABLED(CONFIG_MPC837x)) {
+ if (!IS_ENABLED(CONFIG_ARCH_MPC8360) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC837X)) {
debug("%s: odt_wr_cfg value %d invalid.\n",
ofnode_get_name(node), odt_wr_cfg);
return -EINVAL;
@@ -210,10 +210,10 @@ static int mpc83xx_sdram_static_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
case ODT_WR_NEVER:
case ODT_WR_ONLY_CURRENT:
case ODT_WR_ONLY_OTHER_CS:
- if (!IS_ENABLED(CONFIG_MPC830x) &&
- !IS_ENABLED(CONFIG_MPC831x) &&
- !IS_ENABLED(CONFIG_MPC8360) &&
- !IS_ENABLED(CONFIG_MPC837x)) {
+ if (!IS_ENABLED(CONFIG_ARCH_MPC830X) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC831X) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC8360) &&
+ !IS_ENABLED(CONFIG_ARCH_MPC837X)) {
debug("%s: odt_wr_cfg value %d invalid.\n",
ofnode_get_name(node), odt_wr_cfg);
return -EINVAL;
diff --git a/drivers/ram/rockchip/dmc-rk3368.c b/drivers/ram/rockchip/dmc-rk3368.c
index 8d1b9faacc..e52fc3baad 100644
--- a/drivers/ram/rockchip/dmc-rk3368.c
+++ b/drivers/ram/rockchip/dmc-rk3368.c
@@ -12,12 +12,12 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3368.h>
-#include <asm/arch/grf_rk3368.h>
-#include <asm/arch/ddr_rk3368.h>
-#include <asm/arch/sdram.h>
-#include <asm/arch/sdram_common.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3368.h>
+#include <asm/arch-rockchip/grf_rk3368.h>
+#include <asm/arch-rockchip/ddr_rk3368.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_common.h>
struct dram_info {
struct ram_info info;
@@ -842,7 +842,11 @@ static int setup_sdram(struct udevice *dev)
move_to_access_state(pctl);
/* TODO(prt): could detect rank in training... */
+#ifdef CONFIG_TARGET_EVB_PX5
+ params->chan.rank = 1;
+#else
params->chan.rank = 2;
+#endif
/* TODO(prt): bus width is not auto-detected (yet)... */
params->chan.bw = 2; /* 32bit wide bus */
params->chan.dbw = params->chan.dbw; /* 32bit wide bus */
diff --git a/drivers/ram/rockchip/sdram_rk3128.c b/drivers/ram/rockchip/sdram_rk3128.c
index df7b988703..bfabc22a7d 100644
--- a/drivers/ram/rockchip/sdram_rk3128.c
+++ b/drivers/ram/rockchip/sdram_rk3128.c
@@ -7,9 +7,9 @@
#include <dm.h>
#include <ram.h>
#include <syscon.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/grf_rk3128.h>
-#include <asm/arch/sdram_common.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/grf_rk3128.h>
+#include <asm/arch-rockchip/sdram_common.h>
struct dram_info {
struct ram_info info;
diff --git a/drivers/ram/rockchip/sdram_rk3188.c b/drivers/ram/rockchip/sdram_rk3188.c
index fdd500aa47..00e52ec949 100644
--- a/drivers/ram/rockchip/sdram_rk3188.c
+++ b/drivers/ram/rockchip/sdram_rk3188.c
@@ -15,13 +15,13 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3188.h>
-#include <asm/arch/ddr_rk3188.h>
-#include <asm/arch/grf_rk3188.h>
-#include <asm/arch/pmu_rk3188.h>
-#include <asm/arch/sdram.h>
-#include <asm/arch/sdram_common.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3188.h>
+#include <asm/arch-rockchip/ddr_rk3188.h>
+#include <asm/arch-rockchip/grf_rk3188.h>
+#include <asm/arch-rockchip/pmu_rk3188.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_common.h>
#include <linux/err.h>
struct chan_info {
diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c
index 53835a9cd0..e96ac54c39 100644
--- a/drivers/ram/rockchip/sdram_rk322x.c
+++ b/drivers/ram/rockchip/sdram_rk322x.c
@@ -11,14 +11,14 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk322x.h>
-#include <asm/arch/grf_rk322x.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/sdram_rk322x.h>
-#include <asm/arch/timer.h>
-#include <asm/arch/uart.h>
-#include <asm/arch/sdram_common.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk322x.h>
+#include <asm/arch-rockchip/grf_rk322x.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/sdram_rk322x.h>
+#include <asm/arch-rockchip/timer.h>
+#include <asm/arch-rockchip/uart.h>
+#include <asm/arch-rockchip/sdram_common.h>
#include <asm/types.h>
#include <linux/err.h>
@@ -49,7 +49,7 @@ struct rk322x_sdram_params {
struct regmap *map;
};
-#ifdef CONFIG_SPL_BUILD
+#ifdef CONFIG_TPL_BUILD
/*
* [7:6] bank(n:n bit bank)
* [5:4] row(13+n)
@@ -750,7 +750,7 @@ static int rk322x_dmc_ofdata_to_platdata(struct udevice *dev)
return 0;
}
-#endif /* CONFIG_SPL_BUILD */
+#endif /* CONFIG_TPL_BUILD */
#if CONFIG_IS_ENABLED(OF_PLATDATA)
static int conv_of_platdata(struct udevice *dev)
@@ -778,7 +778,7 @@ static int conv_of_platdata(struct udevice *dev)
static int rk322x_dmc_probe(struct udevice *dev)
{
-#ifdef CONFIG_SPL_BUILD
+#ifdef CONFIG_TPL_BUILD
struct rk322x_sdram_params *plat = dev_get_platdata(dev);
int ret;
struct udevice *dev_clk;
@@ -786,7 +786,7 @@ static int rk322x_dmc_probe(struct udevice *dev)
struct dram_info *priv = dev_get_priv(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
-#ifdef CONFIG_SPL_BUILD
+#ifdef CONFIG_TPL_BUILD
#if CONFIG_IS_ENABLED(OF_PLATDATA)
ret = conv_of_platdata(dev);
if (ret)
@@ -842,12 +842,12 @@ U_BOOT_DRIVER(dmc_rk322x) = {
.id = UCLASS_RAM,
.of_match = rk322x_dmc_ids,
.ops = &rk322x_dmc_ops,
-#ifdef CONFIG_SPL_BUILD
+#ifdef CONFIG_TPL_BUILD
.ofdata_to_platdata = rk322x_dmc_ofdata_to_platdata,
#endif
.probe = rk322x_dmc_probe,
.priv_auto_alloc_size = sizeof(struct dram_info),
-#ifdef CONFIG_SPL_BUILD
+#ifdef CONFIG_TPL_BUILD
.platdata_auto_alloc_size = sizeof(struct rk322x_sdram_params),
#endif
};
diff --git a/drivers/ram/rockchip/sdram_rk3288.c b/drivers/ram/rockchip/sdram_rk3288.c
index d1e52d84e7..6bb025a851 100644
--- a/drivers/ram/rockchip/sdram_rk3288.c
+++ b/drivers/ram/rockchip/sdram_rk3288.c
@@ -15,13 +15,13 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3288.h>
-#include <asm/arch/ddr_rk3288.h>
-#include <asm/arch/grf_rk3288.h>
-#include <asm/arch/pmu_rk3288.h>
-#include <asm/arch/sdram.h>
-#include <asm/arch/sdram_common.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3288.h>
+#include <asm/arch-rockchip/ddr_rk3288.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rockchip/pmu_rk3288.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <asm/arch-rockchip/sdram_common.h>
#include <linux/err.h>
#include <power/regulator.h>
#include <power/rk8xx_pmic.h>
diff --git a/drivers/ram/rockchip/sdram_rk3328.c b/drivers/ram/rockchip/sdram_rk3328.c
index e8b234d866..f4e0b18447 100644
--- a/drivers/ram/rockchip/sdram_rk3328.c
+++ b/drivers/ram/rockchip/sdram_rk3328.c
@@ -7,9 +7,9 @@
#include <dm.h>
#include <ram.h>
#include <syscon.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/grf_rk3328.h>
-#include <asm/arch/sdram_common.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/grf_rk3328.h>
+#include <asm/arch-rockchip/sdram_common.h>
struct dram_info {
struct ram_info info;
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
index 94dd01156a..52518656c4 100644
--- a/drivers/ram/rockchip/sdram_rk3399.c
+++ b/drivers/ram/rockchip/sdram_rk3399.c
@@ -13,12 +13,12 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/sdram_common.h>
-#include <asm/arch/sdram_rk3399.h>
-#include <asm/arch/cru_rk3399.h>
-#include <asm/arch/grf_rk3399.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_rk3399.h>
+#include <asm/arch-rockchip/cru_rk3399.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/hardware.h>
#include <linux/err.h>
#include <time.h>
@@ -30,7 +30,8 @@ struct chan_info {
};
struct dram_info {
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_TPL_BUILD) || \
+ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
struct chan_info chan[2];
struct clk ddr_clk;
struct rk3399_cru *cru;
@@ -55,7 +56,8 @@ struct dram_info {
#define PHY_DRV_ODT_40 0xe
#define PHY_DRV_ODT_34_3 0xf
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_TPL_BUILD) || \
+ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
struct rockchip_dmc_plat {
#if CONFIG_IS_ENABLED(OF_PLATDATA)
@@ -1187,7 +1189,8 @@ static int rk3399_dmc_init(struct udevice *dev)
static int rk3399_dmc_probe(struct udevice *dev)
{
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_TPL_BUILD) || \
+ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
if (rk3399_dmc_init(dev))
return 0;
#else
@@ -1226,12 +1229,14 @@ U_BOOT_DRIVER(dmc_rk3399) = {
.id = UCLASS_RAM,
.of_match = rk3399_dmc_ids,
.ops = &rk3399_dmc_ops,
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_TPL_BUILD) || \
+ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
.ofdata_to_platdata = rk3399_dmc_ofdata_to_platdata,
#endif
.probe = rk3399_dmc_probe,
.priv_auto_alloc_size = sizeof(struct dram_info),
-#ifdef CONFIG_SPL_BUILD
+#if defined(CONFIG_TPL_BUILD) || \
+ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
.platdata_auto_alloc_size = sizeof(struct rockchip_dmc_plat),
#endif
};
diff --git a/drivers/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig
index b9c816662c..2fd8c7b7e3 100644
--- a/drivers/ram/stm32mp1/Kconfig
+++ b/drivers/ram/stm32mp1/Kconfig
@@ -10,3 +10,40 @@ config STM32MP1_DDR
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)
+
+config STM32MP1_DDR_INTERACTIVE
+ bool "STM32MP1 DDR driver : interactive support"
+ depends on STM32MP1_DDR
+ help
+ activate interactive support in STM32MP1 DDR controller driver
+ used for DDR tuning tools
+ to enter in intercative mode type 'd' during SPL DDR driver
+ initialisation
+
+config STM32MP1_DDR_INTERACTIVE_FORCE
+ bool "STM32MP1 DDR driver : force interactive mode"
+ depends on STM32MP1_DDR_INTERACTIVE
+ default n
+ help
+ force interactive mode in STM32MP1 DDR controller driver
+ skip the polling of character 'd' in console
+ useful when SPL is loaded in sysram
+ directly by programmer
+
+config STM32MP1_DDR_TESTS
+ bool "STM32MP1 DDR driver : tests support"
+ depends on STM32MP1_DDR_INTERACTIVE
+ default y
+ help
+ activate test support for interactive support in
+ STM32MP1 DDR controller driver: command test
+
+config STM32MP1_DDR_TUNING
+ bool "STM32MP1 DDR driver : support of tuning"
+ depends on STM32MP1_DDR_INTERACTIVE
+ default y
+ help
+ activate tuning command in STM32MP1 DDR interactive mode
+ used for DDR tuning tools
+ - DQ Deskew algorithm
+ - DQS Trimming
diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile
index 79eb028fab..e1e9135603 100644
--- a/drivers/ram/stm32mp1/Makefile
+++ b/drivers/ram/stm32mp1/Makefile
@@ -5,3 +5,11 @@
obj-y += stm32mp1_ram.o
obj-y += stm32mp1_ddr.o
+
+obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o
+obj-$(CONFIG_STM32MP1_DDR_TESTS) += stm32mp1_tests.o
+obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o
+
+ifneq ($(DDR_INTERACTIVE),)
+CFLAGS_stm32mp1_interactive.o += -DCONFIG_STM32MP1_DDR_INTERACTIVE_FORCE=y
+endif
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
index c7c3ba70a4..d765a46f7c 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
@@ -41,8 +41,32 @@ struct reg_desc {
offsetof(struct stm32mp1_ddrphy, x),\
offsetof(struct y, x)}
+#define DDR_REG_DYN(x) \
+ {#x,\
+ offsetof(struct stm32mp1_ddrctl, x),\
+ INVALID_OFFSET}
+
+#define DDRPHY_REG_DYN(x) \
+ {#x,\
+ offsetof(struct stm32mp1_ddrphy, x),\
+ INVALID_OFFSET}
+
+/***********************************************************
+ * PARAMETERS: value get from device tree :
+ * size / order need to be aligned with binding
+ * modification NOT ALLOWED !!!
+ ***********************************************************/
+#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */
+#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */
+#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */
+#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */
+
+#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
+#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
+#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */
+
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
-static const struct reg_desc ddr_reg[] = {
+static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
DDRCTL_REG_REG(mstr),
DDRCTL_REG_REG(mrctrl0),
DDRCTL_REG_REG(mrctrl1),
@@ -71,7 +95,7 @@ static const struct reg_desc ddr_reg[] = {
};
#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
-static const struct reg_desc ddr_timing[] = {
+static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
DDRCTL_REG_TIMING(rfshtmg),
DDRCTL_REG_TIMING(dramtmg0),
DDRCTL_REG_TIMING(dramtmg1),
@@ -87,7 +111,7 @@ static const struct reg_desc ddr_timing[] = {
};
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
-static const struct reg_desc ddr_map[] = {
+static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
DDRCTL_REG_MAP(addrmap1),
DDRCTL_REG_MAP(addrmap2),
DDRCTL_REG_MAP(addrmap3),
@@ -100,7 +124,7 @@ static const struct reg_desc ddr_map[] = {
};
#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
-static const struct reg_desc ddr_perf[] = {
+static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
DDRCTL_REG_PERF(sched),
DDRCTL_REG_PERF(sched1),
DDRCTL_REG_PERF(perfhpr1),
@@ -121,7 +145,7 @@ static const struct reg_desc ddr_perf[] = {
};
#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
-static const struct reg_desc ddrphy_reg[] = {
+static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {
DDRPHY_REG_REG(pgcr),
DDRPHY_REG_REG(aciocr),
DDRPHY_REG_REG(dxccr),
@@ -136,7 +160,7 @@ static const struct reg_desc ddrphy_reg[] = {
};
#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
-static const struct reg_desc ddrphy_timing[] = {
+static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
DDRPHY_REG_TIMING(ptr0),
DDRPHY_REG_TIMING(ptr1),
DDRPHY_REG_TIMING(ptr2),
@@ -150,7 +174,7 @@ static const struct reg_desc ddrphy_timing[] = {
};
#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
-static const struct reg_desc ddrphy_cal[] = {
+static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = {
DDRPHY_REG_CAL(dx0dllcr),
DDRPHY_REG_CAL(dx0dqtr),
DDRPHY_REG_CAL(dx0dqstr),
@@ -165,6 +189,45 @@ static const struct reg_desc ddrphy_cal[] = {
DDRPHY_REG_CAL(dx3dqstr),
};
+/**************************************************************
+ * DYNAMIC REGISTERS: only used for debug purpose (read/modify)
+ **************************************************************/
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+static const struct reg_desc ddr_dyn[] = {
+ DDR_REG_DYN(stat),
+ DDR_REG_DYN(init0),
+ DDR_REG_DYN(dfimisc),
+ DDR_REG_DYN(dfistat),
+ DDR_REG_DYN(swctl),
+ DDR_REG_DYN(swstat),
+ DDR_REG_DYN(pctrl_0),
+ DDR_REG_DYN(pctrl_1),
+};
+
+#define DDR_REG_DYN_SIZE ARRAY_SIZE(ddr_dyn)
+
+static const struct reg_desc ddrphy_dyn[] = {
+ DDRPHY_REG_DYN(pir),
+ DDRPHY_REG_DYN(pgsr),
+ DDRPHY_REG_DYN(zq0sr0),
+ DDRPHY_REG_DYN(zq0sr1),
+ DDRPHY_REG_DYN(dx0gsr0),
+ DDRPHY_REG_DYN(dx0gsr1),
+ DDRPHY_REG_DYN(dx1gsr0),
+ DDRPHY_REG_DYN(dx1gsr1),
+ DDRPHY_REG_DYN(dx2gsr0),
+ DDRPHY_REG_DYN(dx2gsr1),
+ DDRPHY_REG_DYN(dx3gsr0),
+ DDRPHY_REG_DYN(dx3gsr1),
+};
+
+#define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn)
+
+#endif
+
+/*****************************************************************
+ * REGISTERS ARRAY: used to parse device tree and interactive mode
+ *****************************************************************/
enum reg_type {
REG_REG,
REG_TIMING,
@@ -173,6 +236,13 @@ enum reg_type {
REGPHY_REG,
REGPHY_TIMING,
REGPHY_CAL,
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+/* dynamic registers => managed in driver or not changed,
+ * can be dumped in interactive mode
+ */
+ REG_DYN,
+ REGPHY_DYN,
+#endif
REG_TYPE_NB
};
@@ -193,19 +263,26 @@ struct ddr_reg_info {
const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
- "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE},
+ "static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE},
[REG_TIMING] = {
- "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE},
+ "timing", ddr_timing, DDRCTL_REG_TIMING_SIZE, DDR_BASE},
[REG_PERF] = {
- "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE},
+ "perf", ddr_perf, DDRCTL_REG_PERF_SIZE, DDR_BASE},
[REG_MAP] = {
- "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE},
+ "map", ddr_map, DDRCTL_REG_MAP_SIZE, DDR_BASE},
[REGPHY_REG] = {
- "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE},
+ "static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE},
[REGPHY_TIMING] = {
- "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE},
+ "timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE},
[REGPHY_CAL] = {
- "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE},
+ "cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE},
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+[REG_DYN] = {
+ "dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE},
+[REGPHY_DYN] = {
+ "dyn", ddrphy_dyn, DDRPHY_REG_DYN_SIZE, DDRPHY_BASE},
+#endif
+
};
const char *base_name[] = {
@@ -246,6 +323,231 @@ static void set_reg(const struct ddr_info *priv,
}
}
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+static void stm32mp1_dump_reg_desc(u32 base_addr, const struct reg_desc *desc)
+{
+ unsigned int *ptr;
+
+ ptr = (unsigned int *)(base_addr + desc->offset);
+ printf("%s= 0x%08x\n", desc->name, readl(ptr));
+}
+
+static void stm32mp1_dump_param_desc(u32 par_addr, const struct reg_desc *desc)
+{
+ unsigned int *ptr;
+
+ ptr = (unsigned int *)(par_addr + desc->par_offset);
+ printf("%s= 0x%08x\n", desc->name, readl(ptr));
+}
+
+static const struct reg_desc *found_reg(const char *name, enum reg_type *type)
+{
+ unsigned int i, j;
+ const struct reg_desc *desc;
+
+ for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) {
+ desc = ddr_registers[i].desc;
+ for (j = 0; j < ddr_registers[i].size; j++) {
+ if (strcmp(name, desc[j].name) == 0) {
+ *type = i;
+ return &desc[j];
+ }
+ }
+ }
+ *type = REG_TYPE_NB;
+ return NULL;
+}
+
+int stm32mp1_dump_reg(const struct ddr_info *priv,
+ const char *name)
+{
+ unsigned int i, j;
+ const struct reg_desc *desc;
+ u32 base_addr;
+ enum base_type p_base;
+ enum reg_type type;
+ const char *p_name;
+ enum base_type filter = NONE_BASE;
+ int result = -1;
+
+ if (name) {
+ if (strcmp(name, base_name[DDR_BASE]) == 0)
+ filter = DDR_BASE;
+ else if (strcmp(name, base_name[DDRPHY_BASE]) == 0)
+ filter = DDRPHY_BASE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) {
+ p_base = ddr_registers[i].base;
+ p_name = ddr_registers[i].name;
+ if (!name || (filter == p_base || !strcmp(name, p_name))) {
+ result = 0;
+ desc = ddr_registers[i].desc;
+ base_addr = get_base_addr(priv, p_base);
+ printf("==%s.%s==\n", base_name[p_base], p_name);
+ for (j = 0; j < ddr_registers[i].size; j++)
+ stm32mp1_dump_reg_desc(base_addr, &desc[j]);
+ }
+ }
+ if (result) {
+ desc = found_reg(name, &type);
+ if (desc) {
+ p_base = ddr_registers[type].base;
+ base_addr = get_base_addr(priv, p_base);
+ stm32mp1_dump_reg_desc(base_addr, desc);
+ result = 0;
+ }
+ }
+ return result;
+}
+
+void stm32mp1_edit_reg(const struct ddr_info *priv,
+ char *name, char *string)
+{
+ unsigned long *ptr, value;
+ enum reg_type type;
+ enum base_type base;
+ const struct reg_desc *desc;
+ u32 base_addr;
+
+ desc = found_reg(name, &type);
+
+ if (!desc) {
+ printf("%s not found\n", name);
+ return;
+ }
+ if (strict_strtoul(string, 16, &value) < 0) {
+ printf("invalid value %s\n", string);
+ return;
+ }
+ base = ddr_registers[type].base;
+ base_addr = get_base_addr(priv, base);
+ ptr = (unsigned long *)(base_addr + desc->offset);
+ writel(value, ptr);
+ printf("%s= 0x%08x\n", desc->name, readl(ptr));
+}
+
+static u32 get_par_addr(const struct stm32mp1_ddr_config *config,
+ enum reg_type type)
+{
+ u32 par_addr = 0x0;
+
+ switch (type) {
+ case REG_REG:
+ par_addr = (u32)&config->c_reg;
+ break;
+ case REG_TIMING:
+ par_addr = (u32)&config->c_timing;
+ break;
+ case REG_PERF:
+ par_addr = (u32)&config->c_perf;
+ break;
+ case REG_MAP:
+ par_addr = (u32)&config->c_map;
+ break;
+ case REGPHY_REG:
+ par_addr = (u32)&config->p_reg;
+ break;
+ case REGPHY_TIMING:
+ par_addr = (u32)&config->p_timing;
+ break;
+ case REGPHY_CAL:
+ par_addr = (u32)&config->p_cal;
+ break;
+ case REG_DYN:
+ case REGPHY_DYN:
+ case REG_TYPE_NB:
+ par_addr = (u32)NULL;
+ break;
+ }
+
+ return par_addr;
+}
+
+int stm32mp1_dump_param(const struct stm32mp1_ddr_config *config,
+ const char *name)
+{
+ unsigned int i, j;
+ const struct reg_desc *desc;
+ u32 par_addr;
+ enum base_type p_base;
+ enum reg_type type;
+ const char *p_name;
+ enum base_type filter = NONE_BASE;
+ int result = -EINVAL;
+
+ if (name) {
+ if (strcmp(name, base_name[DDR_BASE]) == 0)
+ filter = DDR_BASE;
+ else if (strcmp(name, base_name[DDRPHY_BASE]) == 0)
+ filter = DDRPHY_BASE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ddr_registers); i++) {
+ par_addr = get_par_addr(config, i);
+ if (!par_addr)
+ continue;
+ p_base = ddr_registers[i].base;
+ p_name = ddr_registers[i].name;
+ if (!name || (filter == p_base || !strcmp(name, p_name))) {
+ result = 0;
+ desc = ddr_registers[i].desc;
+ printf("==%s.%s==\n", base_name[p_base], p_name);
+ for (j = 0; j < ddr_registers[i].size; j++)
+ stm32mp1_dump_param_desc(par_addr, &desc[j]);
+ }
+ }
+ if (result) {
+ desc = found_reg(name, &type);
+ if (desc) {
+ par_addr = get_par_addr(config, type);
+ if (par_addr) {
+ stm32mp1_dump_param_desc(par_addr, desc);
+ result = 0;
+ }
+ }
+ }
+ return result;
+}
+
+void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config,
+ char *name, char *string)
+{
+ unsigned long *ptr, value;
+ enum reg_type type;
+ const struct reg_desc *desc;
+ u32 par_addr;
+
+ desc = found_reg(name, &type);
+ if (!desc) {
+ printf("%s not found\n", name);
+ return;
+ }
+ if (strict_strtoul(string, 16, &value) < 0) {
+ printf("invalid value %s\n", string);
+ return;
+ }
+ par_addr = get_par_addr(config, type);
+ if (!par_addr) {
+ printf("no parameter %s\n", name);
+ return;
+ }
+ ptr = (unsigned long *)(par_addr + desc->par_offset);
+ writel(value, ptr);
+ printf("%s= 0x%08x\n", desc->name, readl(ptr));
+}
+#endif
+
+__weak bool stm32mp1_ddr_interactive(void *priv,
+ enum stm32mp1_ddr_interact_step step,
+ const struct stm32mp1_ddr_config *config)
+{
+ return false;
+}
+
+#define INTERACTIVE(step)\
+ stm32mp1_ddr_interactive(priv, step, config)
+
static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
{
u32 pgsr;
@@ -312,7 +614,7 @@ static void wait_operating_mode(struct ddr_info *priv, int 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;
+ val |= 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 |
@@ -355,7 +657,7 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
}
/* board-specific DDR power initializations. */
-__weak int board_ddr_power_init(void)
+__weak int board_ddr_power_init(enum ddr_type ddr_type)
{
return 0;
}
@@ -365,15 +667,21 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
const struct stm32mp1_ddr_config *config)
{
u32 pir;
- int ret;
+ int ret = -EINVAL;
- ret = board_ddr_power_init();
+ if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
+ ret = board_ddr_power_init(STM32MP_DDR3);
+ else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2)
+ ret = board_ddr_power_init(STM32MP_LPDDR2);
+ else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3)
+ ret = board_ddr_power_init(STM32MP_LPDDR3);
if (ret)
panic("ddr power init failed\n");
+start:
debug("name = %s\n", config->info.name);
- debug("speed = %d MHz\n", config->info.speed);
+ debug("speed = %d kHz\n", config->info.speed);
debug("size = 0x%x\n", config->info.size);
/*
* 1. Program the DWC_ddr_umctl2 registers
@@ -389,7 +697,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
/* 1.2. start CLOCK */
if (stm32mp1_ddr_clk_enable(priv, config->info.speed))
- panic("invalid DRAM clock : %d MHz\n",
+ panic("invalid DRAM clock : %d kHz\n",
config->info.speed);
/* 1.3. deassert reset */
@@ -401,11 +709,12 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
*/
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.4. wait 128 cycles to permit initialization of end logic */
+ udelay(2);
+ /* for PCLK = 133MHz => 1 us is enough, 2 to allow lower frequency */
+
+ if (INTERACTIVE(STEP_DDR_RESET))
+ goto start;
/* 1.5. initialize registers ddr_umctl2 */
/* Stop uMCTL2 before PHY is ready */
@@ -424,6 +733,9 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
set_reg(priv, REG_PERF, &config->c_perf);
+ if (INTERACTIVE(STEP_CTL_INIT))
+ goto start;
+
/* 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);
@@ -436,6 +748,9 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
set_reg(priv, REGPHY_TIMING, &config->p_timing);
set_reg(priv, REGPHY_CAL, &config->p_cal);
+ if (INTERACTIVE(STEP_PHY_INIT))
+ goto start;
+
/* 4. Monitor PHY init status by polling PUBL register PGSR.IDONE
* Perform DDR PHY DRAM initialization and Gate Training Evaluation
*/
@@ -492,4 +807,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
/* 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);
+
+ if (INTERACTIVE(STEP_DDR_READY))
+ goto start;
}
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
index 3cd0161299..a8eed89e3c 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
@@ -157,7 +157,7 @@ struct stm32mp1_ddrphy_cal {
struct stm32mp1_ddr_info {
const char *name;
- u16 speed; /* in MHZ */
+ u32 speed; /* in kHZ */
u32 size; /* memory size in byte = col * row * width */
};
@@ -172,7 +172,7 @@ struct stm32mp1_ddr_config {
struct stm32mp1_ddrphy_cal p_cal;
};
-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u16 mem_speed);
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 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,
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
index a606b2bcbe..9d33186b3a 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
@@ -234,6 +234,8 @@ struct stm32mp1_ddrphy {
/* DDRCTRL REGISTERS */
#define DDRCTRL_MSTR_DDR3 BIT(0)
+#define DDRCTRL_MSTR_LPDDR2 BIT(2)
+#define DDRCTRL_MSTR_LPDDR3 BIT(3)
#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)
@@ -330,6 +332,7 @@ struct stm32mp1_ddrphy {
#define DDRPHYC_DXNGCR_DXEN BIT(0)
+#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30)
#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31)
#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
new file mode 100644
index 0000000000..cc9b2e7c96
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
@@ -0,0 +1,483 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <console.h>
+#include <cli.h>
+#include <clk.h>
+#include <malloc.h>
+#include <ram.h>
+#include <reset.h>
+#include "stm32mp1_ddr.h"
+#include "stm32mp1_tests.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum ddr_command {
+ DDR_CMD_HELP,
+ DDR_CMD_INFO,
+ DDR_CMD_FREQ,
+ DDR_CMD_RESET,
+ DDR_CMD_PARAM,
+ DDR_CMD_PRINT,
+ DDR_CMD_EDIT,
+ DDR_CMD_STEP,
+ DDR_CMD_NEXT,
+ DDR_CMD_GO,
+ DDR_CMD_TEST,
+ DDR_CMD_TUNING,
+ DDR_CMD_UNKNOWN,
+};
+
+const char *step_str[] = {
+ [STEP_DDR_RESET] = "DDR_RESET",
+ [STEP_CTL_INIT] = "DDR_CTRL_INIT_DONE",
+ [STEP_PHY_INIT] = "DDR PHY_INIT_DONE",
+ [STEP_DDR_READY] = "DDR_READY",
+ [STEP_RUN] = "RUN"
+};
+
+enum ddr_command stm32mp1_get_command(char *cmd, int argc)
+{
+ const char *cmd_string[DDR_CMD_UNKNOWN] = {
+ [DDR_CMD_HELP] = "help",
+ [DDR_CMD_INFO] = "info",
+ [DDR_CMD_FREQ] = "freq",
+ [DDR_CMD_RESET] = "reset",
+ [DDR_CMD_PARAM] = "param",
+ [DDR_CMD_PRINT] = "print",
+ [DDR_CMD_EDIT] = "edit",
+ [DDR_CMD_STEP] = "step",
+ [DDR_CMD_NEXT] = "next",
+ [DDR_CMD_GO] = "go",
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+ [DDR_CMD_TEST] = "test",
+#endif
+#ifdef CONFIG_STM32MP1_DDR_TUNING
+ [DDR_CMD_TUNING] = "tuning",
+#endif
+ };
+ /* min and max number of argument */
+ const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
+ [DDR_CMD_HELP] = { 0, 0 },
+ [DDR_CMD_INFO] = { 0, 255 },
+ [DDR_CMD_FREQ] = { 0, 1 },
+ [DDR_CMD_RESET] = { 0, 0 },
+ [DDR_CMD_PARAM] = { 0, 2 },
+ [DDR_CMD_PRINT] = { 0, 1 },
+ [DDR_CMD_EDIT] = { 2, 2 },
+ [DDR_CMD_STEP] = { 0, 1 },
+ [DDR_CMD_NEXT] = { 0, 0 },
+ [DDR_CMD_GO] = { 0, 0 },
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+ [DDR_CMD_TEST] = { 0, 255 },
+#endif
+#ifdef CONFIG_STM32MP1_DDR_TUNING
+ [DDR_CMD_TUNING] = { 0, 255 },
+#endif
+ };
+ int i;
+
+ for (i = 0; i < DDR_CMD_UNKNOWN; i++)
+ if (!strcmp(cmd, cmd_string[i])) {
+ if (argc - 1 < cmd_arg[i][0]) {
+ printf("no enought argument (min=%d)\n",
+ cmd_arg[i][0]);
+ return DDR_CMD_UNKNOWN;
+ } else if (argc - 1 > cmd_arg[i][1]) {
+ printf("too many argument (max=%d)\n",
+ cmd_arg[i][1]);
+ return DDR_CMD_UNKNOWN;
+ } else {
+ return i;
+ }
+ }
+
+ printf("unknown command %s\n", cmd);
+ return DDR_CMD_UNKNOWN;
+}
+
+static void stm32mp1_do_usage(void)
+{
+ const char *usage = {
+ "commands:\n\n"
+ "help displays help\n"
+ "info displays DDR information\n"
+ "info <param> <val> changes DDR information\n"
+ " with <param> = step, name, size or speed\n"
+ "freq displays the DDR PHY frequency in kHz\n"
+ "freq <freq> changes the DDR PHY frequency\n"
+ "param [type|reg] prints input parameters\n"
+ "param <reg> <val> edits parameters in step 0\n"
+ "print [type|reg] dumps registers\n"
+ "edit <reg> <val> modifies one register\n"
+ "step lists the available step\n"
+ "step <n> go to the step <n>\n"
+ "next goes to the next step\n"
+ "go continues the U-Boot SPL execution\n"
+ "reset reboots machine\n"
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+ "test [help] | <n> [...] lists (with help) or executes test <n>\n"
+#endif
+#ifdef CONFIG_STM32MP1_DDR_TUNING
+ "tuning [help] | <n> [...] lists (with help) or execute tuning <n>\n"
+#endif
+ "\nwith for [type|reg]:\n"
+ " all registers if absent\n"
+ " <type> = ctl, phy\n"
+ " or one category (static, timing, map, perf, cal, dyn)\n"
+ " <reg> = name of the register\n"
+ };
+
+ puts(usage);
+}
+
+static bool stm32mp1_check_step(enum stm32mp1_ddr_interact_step step,
+ enum stm32mp1_ddr_interact_step expected)
+{
+ if (step != expected) {
+ printf("invalid step %d:%s expecting %d:%s\n",
+ step, step_str[step],
+ expected,
+ step_str[expected]);
+ return false;
+ }
+ return true;
+}
+
+static void stm32mp1_do_info(struct ddr_info *priv,
+ struct stm32mp1_ddr_config *config,
+ enum stm32mp1_ddr_interact_step step,
+ int argc, char * const argv[])
+{
+ unsigned long value;
+ static char *ddr_name;
+
+ if (argc == 1) {
+ printf("step = %d : %s\n", step, step_str[step]);
+ printf("name = %s\n", config->info.name);
+ printf("size = 0x%x\n", config->info.size);
+ printf("speed = %d kHz\n", config->info.speed);
+ return;
+ }
+
+ if (argc < 3) {
+ printf("no enought parameter\n");
+ return;
+ }
+ if (!strcmp(argv[1], "name")) {
+ u32 i, name_len = 0;
+
+ for (i = 2; i < argc; i++)
+ name_len += strlen(argv[i]) + 1;
+ if (ddr_name)
+ free(ddr_name);
+ ddr_name = malloc(name_len);
+ config->info.name = ddr_name;
+ if (!ddr_name) {
+ printf("alloc error, length %d\n", name_len);
+ return;
+ }
+ strcpy(ddr_name, argv[2]);
+ for (i = 3; i < argc; i++) {
+ strcat(ddr_name, " ");
+ strcat(ddr_name, argv[i]);
+ }
+ printf("name = %s\n", ddr_name);
+ return;
+ }
+ if (!strcmp(argv[1], "size")) {
+ if (strict_strtoul(argv[2], 16, &value) < 0) {
+ printf("invalid value %s\n", argv[2]);
+ } else {
+ config->info.size = value;
+ printf("size = 0x%x\n", config->info.size);
+ }
+ return;
+ }
+ if (!strcmp(argv[1], "speed")) {
+ if (strict_strtoul(argv[2], 10, &value) < 0) {
+ printf("invalid value %s\n", argv[2]);
+ } else {
+ config->info.speed = value;
+ printf("speed = %d kHz\n", config->info.speed);
+ value = clk_get_rate(&priv->clk);
+ printf("DDRPHY = %ld kHz\n", value / 1000);
+ }
+ return;
+ }
+ printf("argument %s invalid\n", argv[1]);
+}
+
+static bool stm32mp1_do_freq(struct ddr_info *priv,
+ int argc, char * const argv[])
+{
+ unsigned long ddrphy_clk;
+
+ if (argc == 2) {
+ if (strict_strtoul(argv[1], 0, &ddrphy_clk) < 0) {
+ printf("invalid argument %s", argv[1]);
+ return false;
+ }
+ if (clk_set_rate(&priv->clk, ddrphy_clk * 1000)) {
+ printf("ERROR: update failed!\n");
+ return false;
+ }
+ }
+ ddrphy_clk = clk_get_rate(&priv->clk);
+ printf("DDRPHY = %ld kHz\n", ddrphy_clk / 1000);
+ if (argc == 2)
+ return true;
+ return false;
+}
+
+static void stm32mp1_do_param(enum stm32mp1_ddr_interact_step step,
+ const struct stm32mp1_ddr_config *config,
+ int argc, char * const argv[])
+{
+ switch (argc) {
+ case 1:
+ stm32mp1_dump_param(config, NULL);
+ break;
+ case 2:
+ if (stm32mp1_dump_param(config, argv[1]))
+ printf("invalid argument %s\n",
+ argv[1]);
+ break;
+ case 3:
+ if (!stm32mp1_check_step(step, STEP_DDR_RESET))
+ return;
+ stm32mp1_edit_param(config, argv[1], argv[2]);
+ break;
+ }
+}
+
+static void stm32mp1_do_print(struct ddr_info *priv,
+ int argc, char * const argv[])
+{
+ switch (argc) {
+ case 1:
+ stm32mp1_dump_reg(priv, NULL);
+ break;
+ case 2:
+ if (stm32mp1_dump_reg(priv, argv[1]))
+ printf("invalid argument %s\n",
+ argv[1]);
+ break;
+ }
+}
+
+static int stm32mp1_do_step(enum stm32mp1_ddr_interact_step step,
+ int argc, char * const argv[])
+{
+ int i;
+ unsigned long value;
+
+ switch (argc) {
+ case 1:
+ for (i = 0; i < ARRAY_SIZE(step_str); i++)
+ printf("%d:%s\n", i, step_str[i]);
+ break;
+
+ case 2:
+ if ((strict_strtoul(argv[1], 0,
+ &value) < 0) ||
+ value >= ARRAY_SIZE(step_str)) {
+ printf("invalid argument %s\n",
+ argv[1]);
+ goto end;
+ }
+
+ if (value != STEP_DDR_RESET &&
+ value <= step) {
+ printf("invalid target %d:%s, current step is %d:%s\n",
+ (int)value, step_str[value],
+ step, step_str[step]);
+ goto end;
+ }
+ printf("step to %d:%s\n",
+ (int)value, step_str[value]);
+ return (int)value;
+ };
+
+end:
+ return step;
+}
+
+#if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING)
+static const char * const s_result[] = {
+ [TEST_PASSED] = "Pass",
+ [TEST_FAILED] = "Failed",
+ [TEST_ERROR] = "Error"
+};
+
+static void stm32mp1_ddr_subcmd(struct ddr_info *priv,
+ int argc, char *argv[],
+ const struct test_desc array[],
+ const int array_nb)
+{
+ int i;
+ unsigned long value;
+ int result;
+ char string[50] = "";
+
+ if (argc == 1) {
+ printf("%s:%d\n", argv[0], array_nb);
+ for (i = 0; i < array_nb; i++)
+ printf("%d:%s:%s\n",
+ i, array[i].name, array[i].usage);
+ return;
+ }
+ if (argc > 1 && !strcmp(argv[1], "help")) {
+ printf("%s:%d\n", argv[0], array_nb);
+ for (i = 0; i < array_nb; i++)
+ printf("%d:%s:%s:%s\n", i,
+ array[i].name, array[i].usage, array[i].help);
+ return;
+ }
+
+ if ((strict_strtoul(argv[1], 0, &value) < 0) ||
+ value >= array_nb) {
+ sprintf(string, "invalid argument %s",
+ argv[1]);
+ result = TEST_FAILED;
+ goto end;
+ }
+
+ if (argc > (array[value].max_args + 2)) {
+ sprintf(string, "invalid nb of args %d, max %d",
+ argc - 2, array[value].max_args);
+ result = TEST_FAILED;
+ goto end;
+ }
+
+ printf("execute %d:%s\n", (int)value, array[value].name);
+ clear_ctrlc();
+ result = array[value].fct(priv->ctl, priv->phy,
+ string, argc - 2, &argv[2]);
+
+end:
+ printf("Result: %s [%s]\n", s_result[result], string);
+}
+#endif
+
+bool stm32mp1_ddr_interactive(void *priv,
+ enum stm32mp1_ddr_interact_step step,
+ const struct stm32mp1_ddr_config *config)
+{
+ const char *prompt = "DDR>";
+ char buffer[CONFIG_SYS_CBSIZE];
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ int argc;
+ static int next_step = -1;
+
+ if (next_step < 0 && step == STEP_DDR_RESET) {
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE_FORCE
+ gd->flags &= ~(GD_FLG_SILENT |
+ GD_FLG_DISABLE_CONSOLE);
+ next_step = STEP_DDR_RESET;
+#else
+ unsigned long start = get_timer(0);
+
+ while (1) {
+ if (tstc() && (getc() == 'd')) {
+ next_step = STEP_DDR_RESET;
+ break;
+ }
+ if (get_timer(start) > 100)
+ break;
+ }
+#endif
+ }
+
+ debug("** step %d ** %s / %d\n", step, step_str[step], next_step);
+
+ if (next_step < 0)
+ return false;
+
+ if (step < 0 || step > ARRAY_SIZE(step_str)) {
+ printf("** step %d ** INVALID\n", step);
+ return false;
+ }
+
+ printf("%d:%s\n", step, step_str[step]);
+ printf("%s\n", prompt);
+
+ if (next_step > step)
+ return false;
+
+ while (next_step == step) {
+ cli_readline_into_buffer(prompt, buffer, 0);
+ argc = cli_simple_parse_line(buffer, argv);
+ if (!argc)
+ continue;
+
+ switch (stm32mp1_get_command(argv[0], argc)) {
+ case DDR_CMD_HELP:
+ stm32mp1_do_usage();
+ break;
+
+ case DDR_CMD_INFO:
+ stm32mp1_do_info(priv,
+ (struct stm32mp1_ddr_config *)config,
+ step, argc, argv);
+ break;
+
+ case DDR_CMD_FREQ:
+ if (stm32mp1_do_freq(priv, argc, argv))
+ next_step = STEP_DDR_RESET;
+ break;
+
+ case DDR_CMD_RESET:
+ do_reset(NULL, 0, 0, NULL);
+ break;
+
+ case DDR_CMD_PARAM:
+ stm32mp1_do_param(step, config, argc, argv);
+ break;
+
+ case DDR_CMD_PRINT:
+ stm32mp1_do_print(priv, argc, argv);
+ break;
+
+ case DDR_CMD_EDIT:
+ stm32mp1_edit_reg(priv, argv[1], argv[2]);
+ break;
+
+ case DDR_CMD_GO:
+ next_step = STEP_RUN;
+ break;
+
+ case DDR_CMD_NEXT:
+ next_step = step + 1;
+ break;
+
+ case DDR_CMD_STEP:
+ next_step = stm32mp1_do_step(step, argc, argv);
+ break;
+
+#ifdef CONFIG_STM32MP1_DDR_TESTS
+ case DDR_CMD_TEST:
+ if (!stm32mp1_check_step(step, STEP_DDR_READY))
+ continue;
+ stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
+ break;
+#endif
+
+#ifdef CONFIG_STM32MP1_DDR_TUNING
+ case DDR_CMD_TUNING:
+ if (!stm32mp1_check_step(step, STEP_DDR_READY))
+ continue;
+ stm32mp1_ddr_subcmd(priv, argc, argv,
+ tuning, tuning_nb);
+ break;
+#endif
+
+ default:
+ break;
+ }
+ }
+ return next_step == STEP_DDR_RESET;
+}
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
index e45a3b2658..84e39d093b 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ram.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -20,7 +20,7 @@ static const char *const clkname[] = {
"ddrphyc" /* LAST clock => used for get_rate() */
};
-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
{
unsigned long ddrphy_clk;
unsigned long ddr_clk;
@@ -43,13 +43,13 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
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));
+ debug("DDR: mem_speed (%d kHz), RCC %d kHz\n",
+ mem_speed, (u32)(ddrphy_clk / 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));
+ ddr_clk = abs(ddrphy_clk - mem_speed * 1000);
+ if (ddr_clk > (mem_speed * 100)) {
+ pr_err("DDR expected freq %d kHz, current is %d kHz\n",
+ mem_speed, (u32)(ddrphy_clk / 1000));
return -EINVAL;
}
@@ -102,8 +102,8 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
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);
+ pr_err("%s: Cannot read %s, error=%d\n",
+ __func__, param[idx].name, ret);
return -EINVAL;
}
}
diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c
new file mode 100644
index 0000000000..b6fb2a9c58
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_tests.c
@@ -0,0 +1,1426 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <console.h>
+#include <asm/io.h>
+#include <linux/log2.h>
+#include "stm32mp1_tests.h"
+
+#define ADDR_INVALID 0xFFFFFFFF
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int get_bufsize(char *string, int argc, char *argv[], int arg_nb,
+ size_t *bufsize, size_t default_size)
+{
+ unsigned long value;
+
+ if (argc > arg_nb) {
+ if (strict_strtoul(argv[arg_nb], 0, &value) < 0) {
+ sprintf(string, "invalid %d parameter %s",
+ arg_nb, argv[arg_nb]);
+ return -1;
+ }
+ if (value > STM32_DDR_SIZE || value == 0) {
+ sprintf(string, "invalid size %s", argv[arg_nb]);
+ return -1;
+ }
+ if (value & 0x3) {
+ sprintf(string, "unaligned size %s",
+ argv[arg_nb]);
+ return -1;
+ }
+ *bufsize = value;
+ } else {
+ if (default_size != STM32_DDR_SIZE)
+ *bufsize = default_size;
+ else
+ *bufsize = get_ram_size((long *)STM32_DDR_BASE,
+ STM32_DDR_SIZE);
+ }
+ return 0;
+}
+
+static int get_nb_loop(char *string, int argc, char *argv[], int arg_nb,
+ u32 *nb_loop, u32 default_nb_loop)
+{
+ unsigned long value;
+
+ if (argc > arg_nb) {
+ if (strict_strtoul(argv[arg_nb], 0, &value) < 0) {
+ sprintf(string, "invalid %d parameter %s",
+ arg_nb, argv[arg_nb]);
+ return -1;
+ }
+ if (value == 0)
+ printf("WARNING: infinite loop requested\n");
+ *nb_loop = value;
+ } else {
+ *nb_loop = default_nb_loop;
+ }
+
+ return 0;
+}
+
+static int get_addr(char *string, int argc, char *argv[], int arg_nb,
+ u32 *addr)
+{
+ unsigned long value;
+
+ if (argc > arg_nb) {
+ if (strict_strtoul(argv[arg_nb], 16, &value) < 0) {
+ sprintf(string, "invalid %d parameter %s",
+ arg_nb, argv[arg_nb]);
+ return -1;
+ }
+ if (value < STM32_DDR_BASE) {
+ sprintf(string, "too low address %s", argv[arg_nb]);
+ return -1;
+ }
+ if (value & 0x3 && value != ADDR_INVALID) {
+ sprintf(string, "unaligned address %s",
+ argv[arg_nb]);
+ return -1;
+ }
+ *addr = value;
+ } else {
+ *addr = STM32_DDR_BASE;
+ }
+
+ return 0;
+}
+
+static int get_pattern(char *string, int argc, char *argv[], int arg_nb,
+ u32 *pattern, u32 default_pattern)
+{
+ unsigned long value;
+
+ if (argc > arg_nb) {
+ if (strict_strtoul(argv[arg_nb], 16, &value) < 0) {
+ sprintf(string, "invalid %d parameter %s",
+ arg_nb, argv[arg_nb]);
+ return -1;
+ }
+ *pattern = value;
+ } else {
+ *pattern = default_pattern;
+ }
+
+ return 0;
+}
+
+static u32 check_addr(u32 addr, u32 value)
+{
+ u32 data = readl(addr);
+
+ if (value != data) {
+ printf("0x%08x: 0x%08x <=> 0x%08x", addr, data, value);
+ data = readl(addr);
+ printf("(2nd read: 0x%08x)", data);
+ if (value == data)
+ printf("- read error");
+ else
+ printf("- write error");
+ printf("\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int progress(u32 offset)
+{
+ if (!(offset & 0xFFFFFF)) {
+ putc('.');
+ if (ctrlc()) {
+ printf("\ntest interrupted!\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int test_loop_end(u32 *loop, u32 nb_loop, u32 progress)
+{
+ (*loop)++;
+ if (nb_loop && *loop >= nb_loop)
+ return 1;
+ if ((*loop) % progress)
+ return 0;
+ /* allow to interrupt the test only for progress step */
+ if (ctrlc()) {
+ printf("test interrupted!\n");
+ return 1;
+ }
+ printf("loop #%d\n", *loop);
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * Function: memTestDataBus()
+ *
+ * Description: Test the data bus wiring in a memory region by
+ * performing a walking 1's test at a fixed address
+ * within that region. The address is selected
+ * by the caller.
+ *
+ * Notes:
+ *
+ * Returns: 0 if the test succeeds.
+ * A non-zero result is the first pattern that failed.
+ *
+ **********************************************************************/
+static u32 databus(u32 *address)
+{
+ u32 pattern;
+ u32 read_value;
+
+ /* Perform a walking 1's test at the given address. */
+ for (pattern = 1; pattern != 0; pattern <<= 1) {
+ /* Write the test pattern. */
+ writel(pattern, address);
+
+ /* Read it back (immediately is okay for this test). */
+ read_value = readl(address);
+ debug("%x: %x <=> %x\n",
+ (u32)address, read_value, pattern);
+
+ if (read_value != pattern)
+ return pattern;
+ }
+
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * Function: memTestAddressBus()
+ *
+ * Description: Test the address bus wiring in a memory region by
+ * performing a walking 1's test on the relevant bits
+ * of the address and checking for aliasing. This test
+ * will find single-bit address failures such as stuck
+ * -high, stuck-low, and shorted pins. The base address
+ * and size of the region are selected by the caller.
+ *
+ * Notes: For best results, the selected base address should
+ * have enough LSB 0's to guarantee single address bit
+ * changes. For example, to test a 64-Kbyte region,
+ * select a base address on a 64-Kbyte boundary. Also,
+ * select the region size as a power-of-two--if at all
+ * possible.
+ *
+ * Returns: NULL if the test succeeds.
+ * A non-zero result is the first address at which an
+ * aliasing problem was uncovered. By examining the
+ * contents of memory, it may be possible to gather
+ * additional information about the problem.
+ *
+ **********************************************************************/
+static u32 *addressbus(u32 *address, u32 nb_bytes)
+{
+ u32 mask = (nb_bytes / sizeof(u32) - 1);
+ u32 offset;
+ u32 test_offset;
+ u32 read_value;
+
+ u32 pattern = 0xAAAAAAAA;
+ u32 antipattern = 0x55555555;
+
+ /* Write the default pattern at each of the power-of-two offsets. */
+ for (offset = 1; (offset & mask) != 0; offset <<= 1)
+ writel(pattern, &address[offset]);
+
+ /* Check for address bits stuck high. */
+ test_offset = 0;
+ writel(antipattern, &address[test_offset]);
+
+ for (offset = 1; (offset & mask) != 0; offset <<= 1) {
+ read_value = readl(&address[offset]);
+ debug("%x: %x <=> %x\n",
+ (u32)&address[offset], read_value, pattern);
+ if (read_value != pattern)
+ return &address[offset];
+ }
+
+ writel(pattern, &address[test_offset]);
+
+ /* Check for address bits stuck low or shorted. */
+ for (test_offset = 1; (test_offset & mask) != 0; test_offset <<= 1) {
+ writel(antipattern, &address[test_offset]);
+ if (readl(&address[0]) != pattern)
+ return &address[test_offset];
+
+ for (offset = 1; (offset & mask) != 0; offset <<= 1) {
+ if (readl(&address[offset]) != pattern &&
+ offset != test_offset)
+ return &address[test_offset];
+ }
+ writel(pattern, &address[test_offset]);
+ }
+
+ return NULL;
+}
+
+/**********************************************************************
+ *
+ * Function: memTestDevice()
+ *
+ * Description: Test the integrity of a physical memory device by
+ * performing an increment/decrement test over the
+ * entire region. In the process every storage bit
+ * in the device is tested as a zero and a one. The
+ * base address and the size of the region are
+ * selected by the caller.
+ *
+ * Notes:
+ *
+ * Returns: NULL if the test succeeds.
+ *
+ * A non-zero result is the first address at which an
+ * incorrect value was read back. By examining the
+ * contents of memory, it may be possible to gather
+ * additional information about the problem.
+ *
+ **********************************************************************/
+static u32 *memdevice(u32 *address, u32 nb_bytes)
+{
+ u32 offset;
+ u32 nb_words = nb_bytes / sizeof(u32);
+
+ u32 pattern;
+ u32 antipattern;
+
+ puts("Fill with pattern");
+ /* Fill memory with a known pattern. */
+ for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) {
+ writel(pattern, &address[offset]);
+ if (progress(offset))
+ return NULL;
+ }
+
+ puts("\nCheck and invert pattern");
+ /* Check each location and invert it for the second pass. */
+ for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) {
+ if (readl(&address[offset]) != pattern)
+ return &address[offset];
+
+ antipattern = ~pattern;
+ writel(antipattern, &address[offset]);
+ if (progress(offset))
+ return NULL;
+ }
+
+ puts("\nCheck inverted pattern");
+ /* Check each location for the inverted pattern and zero it. */
+ for (pattern = 1, offset = 0; offset < nb_words; pattern++, offset++) {
+ antipattern = ~pattern;
+ if (readl(&address[offset]) != antipattern)
+ return &address[offset];
+ if (progress(offset))
+ return NULL;
+ }
+ printf("\n");
+
+ return NULL;
+}
+
+static enum test_result databuswalk0(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ int i;
+ u32 loop = 0, nb_loop;
+ u32 addr;
+ u32 error = 0;
+ u32 data;
+
+ if (get_nb_loop(string, argc, argv, 0, &nb_loop, 100))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 1, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%x\n", nb_loop, addr);
+ while (!error) {
+ for (i = 0; i < 32; i++)
+ writel(~(1 << i), addr + 4 * i);
+ for (i = 0; i < 32; i++) {
+ data = readl(addr + 4 * i);
+ if (~(1 << i) != data) {
+ error |= 1 << i;
+ debug("%x: error %x expected %x => error:%x\n",
+ addr + 4 * i, data, ~(1 << i), error);
+ }
+ }
+ if (test_loop_end(&loop, nb_loop, 1000))
+ break;
+ for (i = 0; i < 32; i++)
+ writel(0, addr + 4 * i);
+ }
+ if (error) {
+ sprintf(string, "loop %d: error for bits 0x%x",
+ loop, error);
+ return TEST_FAILED;
+ }
+ sprintf(string, "no error for %d loops", loop);
+ return TEST_PASSED;
+}
+
+static enum test_result databuswalk1(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ int i;
+ u32 loop = 0, nb_loop;
+ u32 addr;
+ u32 error = 0;
+ u32 data;
+
+ if (get_nb_loop(string, argc, argv, 0, &nb_loop, 100))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 1, &addr))
+ return TEST_ERROR;
+ printf("running %d loops at 0x%x\n", nb_loop, addr);
+ while (!error) {
+ for (i = 0; i < 32; i++)
+ writel(1 << i, addr + 4 * i);
+ for (i = 0; i < 32; i++) {
+ data = readl(addr + 4 * i);
+ if ((1 << i) != data) {
+ error |= 1 << i;
+ debug("%x: error %x expected %x => error:%x\n",
+ addr + 4 * i, data, (1 << i), error);
+ }
+ }
+ if (test_loop_end(&loop, nb_loop, 1000))
+ break;
+ for (i = 0; i < 32; i++)
+ writel(0, addr + 4 * i);
+ }
+ if (error) {
+ sprintf(string, "loop %d: error for bits 0x%x",
+ loop, error);
+ return TEST_FAILED;
+ }
+ sprintf(string, "no error for %d loops", loop);
+ return TEST_PASSED;
+}
+
+static enum test_result test_databus(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 addr;
+ u32 error;
+
+ if (get_addr(string, argc, argv, 0, &addr))
+ return TEST_ERROR;
+ error = databus((u32 *)addr);
+ if (error) {
+ sprintf(string, "0x%x: error for bits 0x%x",
+ addr, error);
+ return TEST_FAILED;
+ }
+ sprintf(string, "address 0x%x", addr);
+ return TEST_PASSED;
+}
+
+static enum test_result test_addressbus(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 addr;
+ u32 bufsize;
+ u32 error;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (!is_power_of_2(bufsize)) {
+ sprintf(string, "size 0x%x is not a power of 2",
+ (u32)bufsize);
+ return TEST_ERROR;
+ }
+ if (get_addr(string, argc, argv, 1, &addr))
+ return TEST_ERROR;
+
+ error = (u32)addressbus((u32 *)addr, bufsize);
+ if (error) {
+ sprintf(string, "0x%x: error for address 0x%x",
+ addr, error);
+ return TEST_FAILED;
+ }
+ sprintf(string, "address 0x%x, size 0x%x",
+ addr, bufsize);
+ return TEST_PASSED;
+}
+
+static enum test_result test_memdevice(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 addr;
+ size_t bufsize;
+ u32 error;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 1, &addr))
+ return TEST_ERROR;
+ error = (u32)memdevice((u32 *)addr, (unsigned long)bufsize);
+ if (error) {
+ sprintf(string, "0x%x: error for address 0x%x",
+ addr, error);
+ return TEST_FAILED;
+ }
+ sprintf(string, "address 0x%x, size 0x%x",
+ addr, bufsize);
+ return TEST_PASSED;
+}
+
+/**********************************************************************
+ *
+ * Function: sso
+ *
+ * Description: Test the Simultaneous Switching Output.
+ * Verifies succes sive reads and writes to the same memory word,
+ * holding one bit constant while toggling all other data bits
+ * simultaneously
+ * => stress the data bus over an address range
+ *
+ * The CPU writes to each address in the given range.
+ * For each bit, first the CPU holds the bit at 1 while
+ * toggling the other bits, and then the CPU holds the bit at 0
+ * while toggling the other bits.
+ * After each write, the CPU reads the address that was written
+ * to verify that it contains the correct data
+ *
+ **********************************************************************/
+static enum test_result test_sso(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ int i, j;
+ u32 addr, bufsize, remaining, offset;
+ u32 error = 0;
+ u32 data;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 1, &addr))
+ return TEST_ERROR;
+
+ printf("running sso at 0x%x length 0x%x", addr, bufsize);
+ offset = addr;
+ remaining = bufsize;
+ while (remaining) {
+ for (i = 0; i < 32; i++) {
+ /* write pattern. */
+ for (j = 0; j < 6; j++) {
+ switch (j) {
+ case 0:
+ case 2:
+ data = 1 << i;
+ break;
+ case 3:
+ case 5:
+ data = ~(1 << i);
+ break;
+ case 1:
+ data = ~0x0;
+ break;
+ case 4:
+ data = 0x0;
+ break;
+ }
+
+ writel(data, offset);
+ error = check_addr(offset, data);
+ if (error)
+ goto end;
+ }
+ }
+ offset += 4;
+ remaining -= 4;
+ if (progress(offset << 7))
+ goto end;
+ }
+ puts("\n");
+
+end:
+ if (error) {
+ sprintf(string, "error for pattern 0x%x @0x%x",
+ data, offset);
+ return TEST_FAILED;
+ }
+ sprintf(string, "no error for sso at 0x%x length 0x%x", addr, bufsize);
+ return TEST_PASSED;
+}
+
+/**********************************************************************
+ *
+ * Function: Random
+ *
+ * Description: Verifies r/w with pseudo-ramdom value on one region
+ * + write the region (individual access)
+ * + memcopy to the 2nd region (try to use burst)
+ * + verify the 2 regions
+ *
+ **********************************************************************/
+static enum test_result test_random(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 addr, offset, value = 0;
+ size_t bufsize;
+ u32 loop = 0, nb_loop;
+ u32 error = 0;
+ unsigned int seed;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%x\n", nb_loop, addr);
+ while (!error) {
+ seed = rand();
+ for (offset = addr; offset < addr + bufsize; offset += 4)
+ writel(rand(), offset);
+
+ memcpy((void *)addr + bufsize, (void *)addr, bufsize);
+
+ srand(seed);
+ for (offset = addr; offset < addr + 2 * bufsize; offset += 4) {
+ if (offset == (addr + bufsize))
+ srand(seed);
+ value = rand();
+ error = check_addr(offset, value);
+ if (error)
+ break;
+ if (progress(offset))
+ return TEST_FAILED;
+ }
+ if (test_loop_end(&loop, nb_loop, 100))
+ break;
+ }
+
+ if (error) {
+ sprintf(string,
+ "loop %d: error for address 0x%x: 0x%x expected 0x%x",
+ loop, offset, readl(offset), value);
+ return TEST_FAILED;
+ }
+ sprintf(string, "no error for %d loops, size 0x%x",
+ loop, bufsize);
+ return TEST_PASSED;
+}
+
+/**********************************************************************
+ *
+ * Function: noise
+ *
+ * Description: Verifies r/w while forcing switching of all data bus lines.
+ * optimised 4 iteration write/read/write/read cycles...
+ * for pattern and inversed pattern
+ *
+ **********************************************************************/
+void do_noise(u32 addr, u32 pattern, u32 *result)
+{
+ __asm__("push {R0-R11}");
+ __asm__("mov r0, %0" : : "r" (addr));
+ __asm__("mov r1, %0" : : "r" (pattern));
+ __asm__("mov r11, %0" : : "r" (result));
+
+ __asm__("mvn r2, r1");
+
+ __asm__("str r1, [r0]");
+ __asm__("ldr r3, [r0]");
+ __asm__("str r2, [r0]");
+ __asm__("ldr r4, [r0]");
+
+ __asm__("str r1, [r0]");
+ __asm__("ldr r5, [r0]");
+ __asm__("str r2, [r0]");
+ __asm__("ldr r6, [r0]");
+
+ __asm__("str r1, [r0]");
+ __asm__("ldr r7, [r0]");
+ __asm__("str r2, [r0]");
+ __asm__("ldr r8, [r0]");
+
+ __asm__("str r1, [r0]");
+ __asm__("ldr r9, [r0]");
+ __asm__("str r2, [r0]");
+ __asm__("ldr r10, [r0]");
+
+ __asm__("stmia R11!, {R3-R10}");
+
+ __asm__("pop {R0-R11}");
+}
+
+static enum test_result test_noise(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 addr, pattern;
+ u32 result[8];
+ int i;
+ enum test_result res = TEST_PASSED;
+
+ if (get_pattern(string, argc, argv, 0, &pattern, 0xFFFFFFFF))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 1, &addr))
+ return TEST_ERROR;
+
+ printf("running noise for 0x%x at 0x%x\n", pattern, addr);
+
+ do_noise(addr, pattern, result);
+
+ for (i = 0; i < 0x8;) {
+ if (check_addr((u32)&result[i++], pattern))
+ res = TEST_FAILED;
+ if (check_addr((u32)&result[i++], ~pattern))
+ res = TEST_FAILED;
+ }
+
+ return res;
+}
+
+/**********************************************************************
+ *
+ * Function: noise_burst
+ *
+ * Description: Verifies r/w while forcing switching of all data bus lines.
+ * optimised write loop witrh store multiple to use burst
+ * for pattern and inversed pattern
+ *
+ **********************************************************************/
+void do_noise_burst(u32 addr, u32 pattern, size_t bufsize)
+{
+ __asm__("push {R0-R9}");
+ __asm__("mov r0, %0" : : "r" (addr));
+ __asm__("mov r1, %0" : : "r" (pattern));
+ __asm__("mov r9, %0" : : "r" (bufsize));
+
+ __asm__("mvn r2, r1");
+ __asm__("mov r3, r1");
+ __asm__("mov r4, r2");
+ __asm__("mov r5, r1");
+ __asm__("mov r6, r2");
+ __asm__("mov r7, r1");
+ __asm__("mov r8, r2");
+
+ __asm__("loop1:");
+ __asm__("stmia R0!, {R1-R8}");
+ __asm__("stmia R0!, {R1-R8}");
+ __asm__("stmia R0!, {R1-R8}");
+ __asm__("stmia R0!, {R1-R8}");
+ __asm__("subs r9, r9, #128");
+ __asm__("bge loop1");
+ __asm__("pop {R0-R9}");
+}
+
+/* chunk size enough to allow interruption with Ctrl-C*/
+#define CHUNK_SIZE 0x8000000
+static enum test_result test_noise_burst(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 addr, offset, pattern;
+ size_t bufsize, remaining, size;
+ int i;
+ enum test_result res = TEST_PASSED;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_pattern(string, argc, argv, 1, &pattern, 0xFFFFFFFF))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running noise burst for 0x%x at 0x%x + 0x%x",
+ pattern, addr, bufsize);
+
+ offset = addr;
+ remaining = bufsize;
+ size = CHUNK_SIZE;
+ while (remaining) {
+ if (remaining < size)
+ size = remaining;
+ do_noise_burst(offset, pattern, size);
+ remaining -= size;
+ offset += size;
+ if (progress(offset)) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ }
+ puts("\ncheck buffer");
+ for (i = 0; i < bufsize;) {
+ if (check_addr(addr + i, pattern))
+ res = TEST_FAILED;
+ i += 4;
+ if (check_addr(addr + i, ~pattern))
+ res = TEST_FAILED;
+ i += 4;
+ if (progress(i)) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ }
+end:
+ puts("\n");
+ return res;
+}
+
+/**********************************************************************
+ *
+ * Function: pattern test
+ *
+ * Description: optimized loop for read/write pattern (array of 8 u32)
+ *
+ **********************************************************************/
+#define PATTERN_SIZE 8
+static enum test_result test_loop(const u32 *pattern, u32 *address,
+ const u32 bufsize)
+{
+ int i;
+ int j;
+ enum test_result res = TEST_PASSED;
+ u32 *offset, testsize, remaining;
+
+ offset = address;
+ remaining = bufsize;
+ while (remaining) {
+ testsize = bufsize > 0x1000000 ? 0x1000000 : bufsize;
+
+ __asm__("push {R0-R10}");
+ __asm__("mov r0, %0" : : "r" (pattern));
+ __asm__("mov r1, %0" : : "r" (offset));
+ __asm__("mov r2, %0" : : "r" (testsize));
+ __asm__("ldmia r0!, {R3-R10}");
+
+ __asm__("loop2:");
+ __asm__("stmia r1!, {R3-R10}");
+ __asm__("stmia r1!, {R3-R10}");
+ __asm__("stmia r1!, {R3-R10}");
+ __asm__("stmia r1!, {R3-R10}");
+ __asm__("subs r2, r2, #8");
+ __asm__("bge loop2");
+ __asm__("pop {R0-R10}");
+
+ offset += testsize;
+ remaining -= testsize;
+ if (progress((u32)offset)) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ }
+
+ puts("\ncheck buffer");
+ for (i = 0; i < bufsize; i += PATTERN_SIZE * 4) {
+ for (j = 0; j < PATTERN_SIZE; j++, address++)
+ if (check_addr((u32)address, pattern[j])) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ if (progress(i)) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ }
+
+end:
+ puts("\n");
+ return res;
+}
+
+const u32 pattern_div1_x16[PATTERN_SIZE] = {
+ 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF,
+ 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF
+};
+
+const u32 pattern_div2_x16[PATTERN_SIZE] = {
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000
+};
+
+const u32 pattern_div4_x16[PATTERN_SIZE] = {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000
+};
+
+const u32 pattern_div4_x32[PATTERN_SIZE] = {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+const u32 pattern_mostly_zero_x16[PATTERN_SIZE] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x0000FFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+const u32 pattern_mostly_zero_x32[PATTERN_SIZE] = {
+ 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+const u32 pattern_mostly_one_x16[PATTERN_SIZE] = {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+const u32 pattern_mostly_one_x32[PATTERN_SIZE] = {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+#define NB_PATTERN 5
+static enum test_result test_freq_pattern(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ const u32 * const patterns_x16[NB_PATTERN] = {
+ pattern_div1_x16,
+ pattern_div2_x16,
+ pattern_div4_x16,
+ pattern_mostly_zero_x16,
+ pattern_mostly_one_x16,
+ };
+ const u32 * const patterns_x32[NB_PATTERN] = {
+ pattern_div2_x16,
+ pattern_div4_x16,
+ pattern_div4_x32,
+ pattern_mostly_zero_x32,
+ pattern_mostly_one_x32
+ };
+ const char *patterns_comments[NB_PATTERN] = {
+ "switching at frequency F/1",
+ "switching at frequency F/2",
+ "switching at frequency F/4",
+ "mostly zero",
+ "mostly one"
+ };
+
+ enum test_result res = TEST_PASSED, pattern_res;
+ int i, bus_width;
+ const u32 **patterns;
+ u32 bufsize;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+
+ switch (readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) {
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
+ bus_width = 16;
+ break;
+ default:
+ bus_width = 32;
+ break;
+ }
+
+ printf("running test pattern at 0x%08x length 0x%x width = %d\n",
+ STM32_DDR_BASE, bufsize, bus_width);
+
+ patterns =
+ (const u32 **)(bus_width == 16 ? patterns_x16 : patterns_x32);
+
+ for (i = 0; i < NB_PATTERN; i++) {
+ printf("test data pattern %s:", patterns_comments[i]);
+ pattern_res = test_loop(patterns[i], (u32 *)STM32_DDR_BASE,
+ bufsize);
+ if (pattern_res != TEST_PASSED) {
+ printf("Failed\n");
+ return pattern_res;
+ }
+ printf("Passed\n");
+ }
+
+ return res;
+}
+
+/**********************************************************************
+ *
+ * Function: pattern test with size
+ *
+ * Description: loop for write pattern
+ *
+ **********************************************************************/
+
+static enum test_result test_loop_size(const u32 *pattern, u32 size,
+ u32 *address,
+ const u32 bufsize)
+{
+ int i, j;
+ enum test_result res = TEST_PASSED;
+ u32 *p = address;
+
+ for (i = 0; i < bufsize; i += size * 4) {
+ for (j = 0; j < size ; j++, p++)
+ *p = pattern[j];
+ if (progress(i)) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ }
+
+ puts("\ncheck buffer");
+ p = address;
+ for (i = 0; i < bufsize; i += size * 4) {
+ for (j = 0; j < size; j++, p++)
+ if (check_addr((u32)p, pattern[j])) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ if (progress(i)) {
+ res = TEST_FAILED;
+ goto end;
+ }
+ }
+
+end:
+ puts("\n");
+ return res;
+}
+
+static enum test_result test_checkboard(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED;
+ u32 bufsize, nb_loop, loop = 0, addr;
+ int i;
+
+ u32 checkboard[2] = {0x55555555, 0xAAAAAAAA};
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%08x length 0x%x\n",
+ nb_loop, addr, bufsize);
+ while (1) {
+ for (i = 0; i < 2; i++) {
+ res = test_loop_size(checkboard, 2, (u32 *)addr,
+ bufsize);
+ if (res)
+ return res;
+ checkboard[0] = ~checkboard[0];
+ checkboard[1] = ~checkboard[1];
+ }
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
+ loop, addr, bufsize);
+
+ return res;
+}
+
+static enum test_result test_blockseq(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED;
+ u32 bufsize, nb_loop, loop = 0, addr, value;
+ int i;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%08x length 0x%x\n",
+ nb_loop, addr, bufsize);
+ while (1) {
+ for (i = 0; i < 256; i++) {
+ value = i | i << 8 | i << 16 | i << 24;
+ printf("pattern = %08x", value);
+ res = test_loop_size(&value, 1, (u32 *)addr, bufsize);
+ if (res != TEST_PASSED)
+ return res;
+ }
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
+ loop, addr, bufsize);
+
+ return res;
+}
+
+static enum test_result test_walkbit0(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED;
+ u32 bufsize, nb_loop, loop = 0, addr, value;
+ int i;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%08x length 0x%x\n",
+ nb_loop, addr, bufsize);
+ while (1) {
+ for (i = 0; i < 64; i++) {
+ if (i < 32)
+ value = 1 << i;
+ else
+ value = 1 << (63 - i);
+
+ printf("pattern = %08x", value);
+ res = test_loop_size(&value, 1, (u32 *)addr, bufsize);
+ if (res != TEST_PASSED)
+ return res;
+ }
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
+ loop, addr, bufsize);
+
+ return res;
+}
+
+static enum test_result test_walkbit1(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED;
+ u32 bufsize, nb_loop, loop = 0, addr, value;
+ int i;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%08x length 0x%x\n",
+ nb_loop, addr, bufsize);
+ while (1) {
+ for (i = 0; i < 64; i++) {
+ if (i < 32)
+ value = ~(1 << i);
+ else
+ value = ~(1 << (63 - i));
+
+ printf("pattern = %08x", value);
+ res = test_loop_size(&value, 1, (u32 *)addr, bufsize);
+ if (res != TEST_PASSED)
+ return res;
+ }
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
+ loop, addr, bufsize);
+
+ return res;
+}
+
+/*
+ * try to catch bad bits which are dependent on the current values of
+ * surrounding bits in either the same word32
+ */
+static enum test_result test_bitspread(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED;
+ u32 bufsize, nb_loop, loop = 0, addr, bitspread[4];
+ int i, j;
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%08x length 0x%x\n",
+ nb_loop, addr, bufsize);
+ while (1) {
+ for (i = 1; i < 32; i++) {
+ for (j = 0; j < i; j++) {
+ if (i < 32)
+ bitspread[0] = (1 << i) | (1 << j);
+ else
+ bitspread[0] = (1 << (63 - i)) |
+ (1 << (63 - j));
+ bitspread[1] = bitspread[0];
+ bitspread[2] = ~bitspread[0];
+ bitspread[3] = ~bitspread[0];
+ printf("pattern = %08x", bitspread[0]);
+
+ res = test_loop_size(bitspread, 4, (u32 *)addr,
+ bufsize);
+ if (res != TEST_PASSED)
+ return res;
+ }
+ }
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
+ loop, addr, bufsize);
+
+ return res;
+}
+
+static enum test_result test_bitflip(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED;
+ u32 bufsize, nb_loop, loop = 0, addr;
+ int i;
+
+ u32 bitflip[4];
+
+ if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024))
+ return TEST_ERROR;
+ if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1))
+ return TEST_ERROR;
+ if (get_addr(string, argc, argv, 2, &addr))
+ return TEST_ERROR;
+
+ printf("running %d loops at 0x%08x length 0x%x\n",
+ nb_loop, addr, bufsize);
+ while (1) {
+ for (i = 0; i < 32; i++) {
+ bitflip[0] = 1 << i;
+ bitflip[1] = bitflip[0];
+ bitflip[2] = ~bitflip[0];
+ bitflip[3] = bitflip[2];
+ printf("pattern = %08x", bitflip[0]);
+
+ res = test_loop_size(bitflip, 4, (u32 *)addr, bufsize);
+ if (res != TEST_PASSED)
+ return res;
+ }
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ sprintf(string, "no error for %d loops at 0x%08x length 0x%x",
+ loop, addr, bufsize);
+
+ return res;
+}
+
+/**********************************************************************
+ *
+ * Function: infinite read access to DDR
+ *
+ * Description: continuous read the same pattern at the same address
+ *
+ **********************************************************************/
+static enum test_result test_read(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 *addr;
+ u32 data;
+ u32 loop = 0;
+ bool random = false;
+
+ if (get_addr(string, argc, argv, 0, (u32 *)&addr))
+ return TEST_ERROR;
+
+ if ((u32)addr == ADDR_INVALID) {
+ printf("random ");
+ random = true;
+ }
+
+ printf("running at 0x%08x\n", (u32)addr);
+
+ while (1) {
+ if (random)
+ addr = (u32 *)(STM32_DDR_BASE +
+ (rand() & (STM32_DDR_SIZE - 1) & ~0x3));
+ data = readl(addr);
+ if (test_loop_end(&loop, 0, 1000))
+ break;
+ }
+ sprintf(string, "0x%x: %x", (u32)addr, data);
+
+ return TEST_PASSED;
+}
+
+/**********************************************************************
+ *
+ * Function: infinite write access to DDR
+ *
+ * Description: continuous write the same pattern at the same address
+ *
+ **********************************************************************/
+static enum test_result test_write(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 *addr;
+ u32 data = 0xA5A5AA55;
+ u32 loop = 0;
+ bool random = false;
+
+ if (get_addr(string, argc, argv, 0, (u32 *)&addr))
+ return TEST_ERROR;
+
+ if ((u32)addr == ADDR_INVALID) {
+ printf("random ");
+ random = true;
+ }
+
+ printf("running at 0x%08x\n", (u32)addr);
+
+ while (1) {
+ if (random) {
+ addr = (u32 *)(STM32_DDR_BASE +
+ (rand() & (STM32_DDR_SIZE - 1) & ~0x3));
+ data = rand();
+ }
+ writel(data, addr);
+ if (test_loop_end(&loop, 0, 1000))
+ break;
+ }
+ sprintf(string, "0x%x: %x", (u32)addr, data);
+
+ return TEST_PASSED;
+}
+
+#define NB_TEST_INFINITE 2
+static enum test_result test_all(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ enum test_result res = TEST_PASSED, result;
+ int i, nb_error = 0;
+ u32 loop = 0, nb_loop;
+
+ if (get_nb_loop(string, argc, argv, 0, &nb_loop, 1))
+ return TEST_ERROR;
+
+ while (!nb_error) {
+ /* execute all the test except the lasts which are infinite */
+ for (i = 1; i < test_nb - NB_TEST_INFINITE; i++) {
+ printf("execute %d:%s\n", (int)i, test[i].name);
+ result = test[i].fct(ctl, phy, string, 0, NULL);
+ printf("result %d:%s = ", (int)i, test[i].name);
+ if (result != TEST_PASSED) {
+ nb_error++;
+ res = TEST_FAILED;
+ puts("Failed");
+ } else {
+ puts("Passed");
+ }
+ puts("\n\n");
+ }
+ printf("loop %d: %d/%d test failed\n\n\n",
+ loop + 1, nb_error, test_nb - NB_TEST_INFINITE);
+ if (test_loop_end(&loop, nb_loop, 1))
+ break;
+ }
+ if (res != TEST_PASSED) {
+ sprintf(string, "loop %d: %d/%d test failed", loop, nb_error,
+ test_nb - NB_TEST_INFINITE);
+ } else {
+ sprintf(string, "loop %d: %d tests passed", loop,
+ test_nb - NB_TEST_INFINITE);
+ }
+ return res;
+}
+
+/****************************************************************
+ * TEST Description
+ ****************************************************************/
+
+const struct test_desc test[] = {
+ {test_all, "All", "[loop]", "Execute all tests", 1 },
+ {test_databus, "Simple DataBus", "[addr]",
+ "Verifies each data line by walking 1 on fixed address",
+ 1
+ },
+ {databuswalk0, "DataBusWalking0", "[loop] [addr]",
+ "Verifies each data bus signal can be driven low (32 word burst)",
+ 2
+ },
+ {databuswalk1, "DataBusWalking1", "[loop] [addr]",
+ "Verifies each data bus signal can be driven high (32 word burst)",
+ 2
+ },
+ {test_addressbus, "AddressBus", "[size] [addr]",
+ "Verifies each relevant bits of the address and checking for aliasing",
+ 2
+ },
+ {test_memdevice, "MemDevice", "[size] [addr]",
+ "Test the integrity of a physical memory (test every storage bit in the region)",
+ 2
+ },
+ {test_sso, "SimultaneousSwitchingOutput", "[size] [addr] ",
+ "Stress the data bus over an address range",
+ 2
+ },
+ {test_noise, "Noise", "[pattern] [addr]",
+ "Verifies r/w while forcing switching of all data bus lines.",
+ 3
+ },
+ {test_noise_burst, "NoiseBurst", "[size] [pattern] [addr]",
+ "burst transfers while forcing switching of the data bus lines",
+ 3
+ },
+ {test_random, "Random", "[size] [loop] [addr]",
+ "Verifies r/w and memcopy(burst for pseudo random value.",
+ 3
+ },
+ {test_freq_pattern, "FrequencySelectivePattern ", "[size]",
+ "write & test patterns: Mostly Zero, Mostly One and F/n",
+ 1
+ },
+ {test_blockseq, "BlockSequential", "[size] [loop] [addr]",
+ "test incremental pattern",
+ 3
+ },
+ {test_checkboard, "Checkerboard", "[size] [loop] [addr]",
+ "test checker pattern",
+ 3
+ },
+ {test_bitspread, "BitSpread", "[size] [loop] [addr]",
+ "test Bit Spread pattern",
+ 3
+ },
+ {test_bitflip, "BitFlip", "[size] [loop] [addr]",
+ "test Bit Flip pattern",
+ 3
+ },
+ {test_walkbit0, "WalkingOnes", "[size] [loop] [addr]",
+ "test Walking Ones pattern",
+ 3
+ },
+ {test_walkbit1, "WalkingZeroes", "[size] [loop] [addr]",
+ "test Walking Zeroes pattern",
+ 3
+ },
+ /* need to the the 2 last one (infinite) : skipped for test all */
+ {test_read, "infinite read", "[addr]",
+ "basic test : infinite read access", 1},
+ {test_write, "infinite write", "[addr]",
+ "basic test : infinite write access", 1},
+};
+
+const int test_nb = ARRAY_SIZE(test);
diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.h b/drivers/ram/stm32mp1/stm32mp1_tests.h
new file mode 100644
index 0000000000..55f5d6d93b
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_tests.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _RAM_STM32MP1_TESTS_H_
+#define _RAM_STM32MP1_TESTS_H_
+
+#include "stm32mp1_ddr_regs.h"
+
+enum test_result {
+ TEST_PASSED,
+ TEST_FAILED,
+ TEST_ERROR
+};
+
+struct test_desc {
+ enum test_result (*fct)(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string,
+ int argc, char *argv[]);
+ const char *name;
+ const char *usage;
+ const char *help;
+ u8 max_args;
+};
+
+extern const struct test_desc test[];
+extern const int test_nb;
+
+extern const struct test_desc tuning[];
+extern const int tuning_nb;
+
+#endif
diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c
new file mode 100644
index 0000000000..4e1c1fab54
--- /dev/null
+++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c
@@ -0,0 +1,1380 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <console.h>
+#include <clk.h>
+#include <ram.h>
+#include <reset.h>
+#include <asm/io.h>
+
+#include "stm32mp1_ddr_regs.h"
+#include "stm32mp1_ddr.h"
+#include "stm32mp1_tests.h"
+
+#define MAX_DQS_PHASE_IDX _144deg
+#define MAX_DQS_UNIT_IDX 7
+#define MAX_GSL_IDX 5
+#define MAX_GPS_IDX 3
+
+/* Number of bytes used in this SW. ( min 1--> max 4). */
+#define NUM_BYTES 4
+
+enum dqs_phase_enum {
+ _36deg = 0,
+ _54deg = 1,
+ _72deg = 2,
+ _90deg = 3,
+ _108deg = 4,
+ _126deg = 5,
+ _144deg = 6
+};
+
+/* BIST Result struct */
+struct BIST_result {
+ /* Overall test result:
+ * 0 Fail (any bit failed) ,
+ * 1 Success (All bits success)
+ */
+ bool test_result;
+ /* 1: true, all fail / 0: False, not all bits fail */
+ bool all_bits_fail;
+ bool bit_i_test_result[8]; /* 0 fail / 1 success */
+};
+
+/* a struct that defines tuning parameters of a byte. */
+struct tuning_position {
+ u8 phase; /* DQS phase */
+ u8 unit; /* DQS unit delay */
+ u32 bits_delay; /* Bits deskew in this byte */
+};
+
+/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */
+const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12};
+
+static u8 BIST_error_max = 1;
+static u32 BIST_seed = 0x1234ABCD;
+
+static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl)
+{
+ u32 data_bus = readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK;
+ u8 nb_bytes = NUM_BYTES;
+
+ switch (data_bus) {
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
+ nb_bytes /= 2;
+ break;
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
+ nb_bytes /= 4;
+ break;
+ default:
+ break;
+ }
+
+ return nb_bytes;
+}
+
+static void itm_soft_reset(struct stm32mp1_ddrphy *phy)
+{
+ stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST);
+}
+
+/* Read DQ unit delay register and provides the retrieved value for DQS
+ * We are assuming that we have the same delay when clocking
+ * by DQS and when clocking by DQSN
+ */
+static u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit)
+{
+ u32 index;
+ u32 addr = DXNDQTR(phy, byte);
+
+ /* We are assuming that we have the same delay when clocking by DQS
+ * and when clocking by DQSN : use only the low bits
+ */
+ index = (readl(addr) >> DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit))
+ & DDRPHYC_DXNDQTR_DQDLY_LOW_MASK;
+
+ pr_debug("%s: [%x]: %x => DQ unit index = %x\n",
+ __func__, addr, readl(addr), index);
+
+ return index;
+}
+
+/* Sets the DQS phase delay for a byte lane.
+ *phase delay is specified by giving the index of the desired delay
+ * in the dx_dll_phase array.
+ */
+static void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx)
+{
+ u8 sdphase_val = 0;
+
+ /* Write DXNDLLCR.SDPHASE = dx_dll_phase(phase_index); */
+ sdphase_val = dx_dll_phase[phase_idx];
+ clrsetbits_le32(DXNDLLCR(phy, byte),
+ DDRPHYC_DXNDLLCR_SDPHASE_MASK,
+ sdphase_val << DDRPHYC_DXNDLLCR_SDPHASE_SHIFT);
+}
+
+/* Sets the DQS unit delay for a byte lane.
+ * unit delay is specified by giving the index of the desired delay
+ * for dgsdly and dqsndly (same value).
+ */
+static void DQS_unit_delay(struct stm32mp1_ddrphy *phy,
+ u8 byte, u8 unit_dly_idx)
+{
+ /* Write the same value in DXNDQSTR.DQSDLY and DXNDQSTR.DQSNDLY */
+ clrsetbits_le32(DXNDQSTR(phy, byte),
+ DDRPHYC_DXNDQSTR_DQSDLY_MASK |
+ DDRPHYC_DXNDQSTR_DQSNDLY_MASK,
+ (unit_dly_idx << DDRPHYC_DXNDQSTR_DQSDLY_SHIFT) |
+ (unit_dly_idx << DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT));
+
+ /* After changing this value, an ITM soft reset (PIR.ITMSRST=1,
+ * plus PIR.INIT=1) must be issued.
+ */
+ stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST);
+}
+
+/* Sets the DQ unit delay for a bit line in particular byte lane.
+ * unit delay is specified by giving the desired delay
+ */
+static void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy,
+ u8 byte, u8 bit,
+ u8 dq_delay_index)
+{
+ u8 dq_bit_delay_val = dq_delay_index | (dq_delay_index << 2);
+
+ /* same value on delay for clock DQ an DQS_b */
+ clrsetbits_le32(DXNDQTR(phy, byte),
+ DDRPHYC_DXNDQTR_DQDLY_MASK
+ << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit),
+ dq_bit_delay_val << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit));
+}
+
+static void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy,
+ u8 byte, u8 r0dgsl_idx)
+{
+ clrsetbits_le32(DXNDQSTR(phy, byte),
+ DDRPHYC_DXNDQSTR_R0DGSL_MASK,
+ r0dgsl_idx << DDRPHYC_DXNDQSTR_R0DGSL_SHIFT);
+}
+
+static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy,
+ u8 byte, u8 r0dgps_idx)
+{
+ clrsetbits_le32(DXNDQSTR(phy, byte),
+ DDRPHYC_DXNDQSTR_R0DGPS_MASK,
+ r0dgps_idx << DDRPHYC_DXNDQSTR_R0DGPS_SHIFT);
+}
+
+/* Basic BIST configuration for data lane tests. */
+static void config_BIST(struct stm32mp1_ddrphy *phy)
+{
+ /* Selects the SDRAM bank address to be used during BIST. */
+ u32 bbank = 0;
+ /* Selects the SDRAM row address to be used during BIST. */
+ u32 brow = 0;
+ /* Selects the SDRAM column address to be used during BIST. */
+ u32 bcol = 0;
+ /* Selects the value by which the SDRAM address is incremented
+ * for each write/read access.
+ */
+ u32 bainc = 0x00000008;
+ /* Specifies the maximum SDRAM rank to be used during BIST.
+ * The default value is set to maximum ranks minus 1.
+ * must be 0 with single rank
+ */
+ u32 bmrank = 0;
+ /* Selects the SDRAM rank to be used during BIST.
+ * must be 0 with single rank
+ */
+ u32 brank = 0;
+ /* Specifies the maximum SDRAM bank address to be used during
+ * BIST before the address & increments to the next rank.
+ */
+ u32 bmbank = 1;
+ /* Specifies the maximum SDRAM row address to be used during
+ * BIST before the address & increments to the next bank.
+ */
+ u32 bmrow = 0x7FFF; /* To check */
+ /* Specifies the maximum SDRAM column address to be used during
+ * BIST before the address & increments to the next row.
+ */
+ u32 bmcol = 0x3FF; /* To check */
+ u32 bmode_conf = 0x00000001; /* DRam mode */
+ u32 bdxen_conf = 0x00000001; /* BIST on Data byte */
+ u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */
+
+ /*Setup BIST for DRAM mode, and LFSR-random data pattern.*/
+ /*Write BISTRR.BMODE = 1?b1;*/
+ /*Write BISTRR.BDXEN = 1?b1;*/
+ /*Write BISTRR.BDPAT = 2?b10;*/
+
+ /* reset BIST */
+ writel(0x3, &phy->bistrr);
+
+ writel((bmode_conf << 3) | (bdxen_conf << 14) | (bdpat_conf << 17),
+ &phy->bistrr);
+
+ /*Setup BIST Word Count*/
+ /*Write BISTWCR.BWCNT = 16?b0008;*/
+ writel(0x00000200, &phy->bistwcr); /* A multiple of BL/2 */
+
+ writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0);
+ writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1);
+
+ /* To check this line : */
+ writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2);
+}
+
+/* Select the Byte lane to be tested by BIST. */
+static void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8)
+{
+ clrsetbits_le32(&phy->bistrr,
+ DDRPHYC_BISTRR_BDXSEL_MASK,
+ datx8 << DDRPHYC_BISTRR_BDXSEL_SHIFT);
+
+ /*(For example, selecting Byte Lane 3, BISTRR.BDXSEL = 4?b0011)*/
+ /* Write BISTRR.BDXSEL = datx8; */
+}
+
+/* Perform BIST Write_Read test on a byte lane and return test result. */
+static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte,
+ struct BIST_result *bist)
+{
+ bool result = true; /* BIST_SUCCESS */
+ u32 cnt = 0;
+ u32 error = 0;
+
+ bist->test_result = true;
+
+run:
+ itm_soft_reset(phy);
+
+ /*Perform BIST Reset*/
+ /* Write BISTRR.BINST = 3?b011; */
+ clrsetbits_le32(&phy->bistrr,
+ 0x00000007,
+ 0x00000003);
+
+ /*Re-seed LFSR*/
+ /* Write BISTLSR.SEED = 32'h1234ABCD; */
+ if (BIST_seed)
+ writel(BIST_seed, &phy->bistlsr);
+ else
+ writel(rand(), &phy->bistlsr);
+
+ /* some delay to reset BIST */
+ mdelay(1);
+
+ /*Perform BIST Run*/
+ clrsetbits_le32(&phy->bistrr,
+ 0x00000007,
+ 0x00000001);
+ /* Write BISTRR.BINST = 3?b001; */
+
+ /* Wait for a number of CTL clocks before reading BIST register*/
+ /* Wait 300 ctl_clk cycles; ... IS it really needed?? */
+ /* Perform BIST Instruction Stop*/
+ /* Write BISTRR.BINST = 3?b010;*/
+
+ /* poll on BISTGSR.BDONE. If 0, wait. ++TODO Add timeout */
+ while (!(readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDDONE))
+ ;
+
+ /*Check if received correct number of words*/
+ /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */
+ if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) ==
+ readl(&phy->bistwcr)) {
+ /*Determine if there is a data comparison error*/
+ /* if (Read BISTGSR.BDXERR = 1?b0) */
+ if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR)
+ result = false; /* BIST_FAIL; */
+ else
+ result = true; /* BIST_SUCCESS; */
+ } else {
+ result = false; /* BIST_FAIL; */
+ }
+
+ /* loop while success */
+ cnt++;
+ if (result && cnt != 1000)
+ goto run;
+
+ if (!result)
+ error++;
+
+ if (error < BIST_error_max) {
+ if (cnt != 1000)
+ goto run;
+ bist->test_result = true;
+ } else {
+ bist->test_result = false;
+ }
+}
+
+/* After running the deskew algo, this function applies the new DQ delays
+ * by reading them from the array "deskew_delay"and writing in PHY registers.
+ * The bits that are not deskewed parfectly (too much skew on them,
+ * or data eye very wide) are marked in the array deskew_non_converge.
+ */
+static void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte,
+ u8 deskew_delay[NUM_BYTES][8],
+ u8 deskew_non_converge[NUM_BYTES][8])
+{
+ u8 bit_i;
+ u8 index;
+
+ for (bit_i = 0; bit_i < 8; bit_i++) {
+ set_DQ_unit_delay(phy, byte, bit_i, deskew_delay[byte][bit_i]);
+ index = DQ_unit_index(phy, byte, bit_i);
+ pr_debug("Byte %d ; bit %d : The new DQ delay (%d) index=%d [delta=%d, 3 is the default]",
+ byte, bit_i, deskew_delay[byte][bit_i],
+ index, index - 3);
+ printf("Byte %d, bit %d, DQ delay = %d",
+ byte, bit_i, deskew_delay[byte][bit_i]);
+ if (deskew_non_converge[byte][bit_i] == 1)
+ pr_debug(" - not converged : still more skew");
+ printf("\n");
+ }
+}
+
+/* DQ Bit de-skew algorithm.
+ * Deskews data lines as much as possible.
+ * 1. Add delay to DQS line until finding the failure
+ * (normally a hold time violation)
+ * 2. Reduce DQS line by small steps until finding the very first time
+ * we go back to "Pass" condition.
+ * 3. For each DQ line, Reduce DQ delay until finding the very first failure
+ * (normally a hold time fail)
+ * 4. When all bits are at their first failure delay, we can consider them
+ * aligned.
+ * Handle conrer situation (Can't find Pass-fail, or fail-pass transitions
+ * at any step)
+ * TODO Provide a return Status. Improve doc
+ */
+static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy, char *string)
+{
+ /* New DQ delay value (index), set during Deskew algo */
+ u8 deskew_delay[NUM_BYTES][8];
+ /*If there is still skew on a bit, mark this bit. */
+ u8 deskew_non_converge[NUM_BYTES][8];
+ struct BIST_result result;
+ s8 dqs_unit_delay_index = 0;
+ u8 datx8 = 0;
+ u8 bit_i = 0;
+ s8 phase_idx = 0;
+ s8 bit_i_delay_index = 0;
+ u8 success = 0;
+ struct tuning_position last_right_ok;
+ u8 force_stop = 0;
+ u8 fail_found;
+ u8 error = 0;
+ u8 nb_bytes = get_nb_bytes(ctl);
+ /* u8 last_pass_dqs_unit = 0; */
+
+ memset(deskew_delay, 0, sizeof(deskew_delay));
+ memset(deskew_non_converge, 0, sizeof(deskew_non_converge));
+
+ /*Disable DQS Drift Compensation*/
+ clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP);
+ /*Disable all bytes*/
+ /* Disable automatic power down of DLL and IOs when disabling
+ * a byte (To avoid having to add programming and delay
+ * for a DLL re-lock when later re-enabling a disabled Byte Lane)
+ */
+ clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX);
+
+ /* Disable all data bytes */
+ clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
+
+ /* Config the BIST block */
+ config_BIST(phy);
+ pr_debug("BIST Config done.\n");
+
+ /* Train each byte */
+ for (datx8 = 0; datx8 < nb_bytes; datx8++) {
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ datx8 + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ pr_debug("\n======================\n");
+ pr_debug("Start deskew byte %d .\n", datx8);
+ pr_debug("======================\n");
+ /* Enable Byte (DXNGCR, bit DXEN) */
+ setbits_le32(DXNGCR(phy, datx8), DDRPHYC_DXNGCR_DXEN);
+
+ /* Select the byte lane for comparison of read data */
+ BIST_datx8_sel(phy, datx8);
+
+ /* Set all DQDLYn to maximum value. All bits within the byte
+ * will be delayed with DQSTR = 2 instead of max = 3
+ * to avoid inter bits fail influence
+ */
+ writel(0xAAAAAAAA, DXNDQTR(phy, datx8));
+
+ /* Set the DQS phase delay to 90 DEG (default).
+ * What is defined here is the index of the desired config
+ * in the PHASE array.
+ */
+ phase_idx = _90deg;
+
+ /* Set DQS unit delay to the max value. */
+ dqs_unit_delay_index = MAX_DQS_UNIT_IDX;
+ DQS_unit_delay(phy, datx8, dqs_unit_delay_index);
+ DQS_phase_delay(phy, datx8, phase_idx);
+
+ /* Issue a DLL soft reset */
+ clrbits_le32(DXNDLLCR(phy, datx8), DDRPHYC_DXNDLLCR_DLLSRST);
+ setbits_le32(DXNDLLCR(phy, datx8), DDRPHYC_DXNDLLCR_DLLSRST);
+
+ /* Test this typical init condition */
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+
+ /* If the test pass in this typical condition,
+ * start the algo with it.
+ * Else, look for Pass init condition
+ */
+ if (!success) {
+ pr_debug("Fail at init condtion. Let's look for a good init condition.\n");
+ success = 0; /* init */
+ /* Make sure we start with a PASS condition before
+ * looking for a fail condition.
+ * Find the first PASS PHASE condition
+ */
+
+ /* escape if we find a PASS */
+ pr_debug("increase Phase idx\n");
+ while (!success && (phase_idx <= MAX_DQS_PHASE_IDX)) {
+ DQS_phase_delay(phy, datx8, phase_idx);
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+ phase_idx++;
+ }
+ /* if ended with success
+ * ==>> Restore the fist success condition
+ */
+ if (success)
+ phase_idx--; /* because it ended with ++ */
+ }
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ datx8 + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ /* We couldn't find a successful condition, its seems
+ * we have hold violation, lets try reduce DQS_unit Delay
+ */
+ if (!success) {
+ /* We couldn't find a successful condition, its seems
+ * we have hold violation, lets try reduce DQS_unit
+ * Delay
+ */
+ pr_debug("Still fail. Try decrease DQS Unit delay\n");
+
+ phase_idx = 0;
+ dqs_unit_delay_index = 0;
+ DQS_phase_delay(phy, datx8, phase_idx);
+
+ /* escape if we find a PASS */
+ while (!success &&
+ (dqs_unit_delay_index <=
+ MAX_DQS_UNIT_IDX)) {
+ DQS_unit_delay(phy, datx8,
+ dqs_unit_delay_index);
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+ dqs_unit_delay_index++;
+ }
+ if (success) {
+ /* Restore the first success condition*/
+ dqs_unit_delay_index--;
+ /* last_pass_dqs_unit = dqs_unit_delay_index;*/
+ DQS_unit_delay(phy, datx8,
+ dqs_unit_delay_index);
+ } else {
+ /* No need to continue,
+ * there is no pass region.
+ */
+ force_stop = 1;
+ }
+ }
+
+ /* There is an initial PASS condition
+ * Look for the first failing condition by PHASE stepping.
+ * This part of the algo can finish without converging.
+ */
+ if (force_stop) {
+ printf("Result: Failed ");
+ printf("[Cannot Deskew lines, ");
+ printf("there is no PASS region]\n");
+ error++;
+ continue;
+ }
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ datx8 + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+
+ pr_debug("there is a pass region for phase idx %d\n",
+ phase_idx);
+ pr_debug("Step1: Find the first failing condition\n");
+ /* Look for the first failing condition by PHASE stepping.
+ * This part of the algo can finish without converging.
+ */
+
+ /* escape if we find a fail (hold time violation)
+ * condition at any bit or if out of delay range.
+ */
+ while (success && (phase_idx <= MAX_DQS_PHASE_IDX)) {
+ DQS_phase_delay(phy, datx8, phase_idx);
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+ phase_idx++;
+ }
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ datx8 + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+
+ /* if the loop ended with a failing condition at any bit,
+ * lets look for the first previous success condition by unit
+ * stepping (minimal delay)
+ */
+ if (!success) {
+ pr_debug("Fail region (PHASE) found phase idx %d\n",
+ phase_idx);
+ pr_debug("Let's look for first success by DQS Unit steps\n");
+ /* This part, the algo always converge */
+ phase_idx--;
+
+ /* escape if we find a success condition
+ * or if out of delay range.
+ */
+ while (!success && dqs_unit_delay_index >= 0) {
+ DQS_unit_delay(phy, datx8,
+ dqs_unit_delay_index);
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+ dqs_unit_delay_index--;
+ }
+ /* if the loop ended with a success condition,
+ * the last delay Right OK (before hold violation)
+ * condition is then defined as following:
+ */
+ if (success) {
+ /* Hold the dely parameters of the the last
+ * delay Right OK condition.
+ * -1 to get back to current condition
+ */
+ last_right_ok.phase = phase_idx;
+ /*+1 to get back to current condition */
+ last_right_ok.unit = dqs_unit_delay_index + 1;
+ last_right_ok.bits_delay = 0xFFFFFFFF;
+ pr_debug("Found %d\n", dqs_unit_delay_index);
+ } else {
+ /* the last OK condition is then with the
+ * previous phase_idx.
+ * -2 instead of -1 because at the last
+ * iteration of the while(),
+ * we incremented phase_idx
+ */
+ last_right_ok.phase = phase_idx - 1;
+ /* Nominal+1. Because we want the previous
+ * delay after reducing the phase delay.
+ */
+ last_right_ok.unit = 1;
+ last_right_ok.bits_delay = 0xFFFFFFFF;
+ pr_debug("Not Found : try previous phase %d\n",
+ phase_idx - 1);
+
+ DQS_phase_delay(phy, datx8, phase_idx - 1);
+ dqs_unit_delay_index = 0;
+ success = true;
+ while (success &&
+ (dqs_unit_delay_index <
+ MAX_DQS_UNIT_IDX)) {
+ DQS_unit_delay(phy, datx8,
+ dqs_unit_delay_index);
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+ dqs_unit_delay_index++;
+ pr_debug("dqs_unit_delay_index = %d, result = %d\n",
+ dqs_unit_delay_index, success);
+ }
+
+ if (!success) {
+ last_right_ok.unit =
+ dqs_unit_delay_index - 1;
+ } else {
+ last_right_ok.unit = 0;
+ pr_debug("ERROR: failed region not FOUND");
+ }
+ }
+ } else {
+ /* we can't find a failing condition at all bits
+ * ==> Just hold the last test condition
+ * (the max DQS delay)
+ * which is the most likely,
+ * the closest to a hold violation
+ * If we can't find a Fail condition after
+ * the Pass region, stick at this position
+ * In order to have max chances to find a fail
+ * when reducing DQ delays.
+ */
+ last_right_ok.phase = MAX_DQS_PHASE_IDX;
+ last_right_ok.unit = MAX_DQS_UNIT_IDX;
+ last_right_ok.bits_delay = 0xFFFFFFFF;
+ pr_debug("Can't find the a fail condition\n");
+ }
+
+ /* step 2:
+ * if we arrive at this stage, it means that we found the last
+ * Right OK condition (by tweeking the DQS delay). Or we simply
+ * pushed DQS delay to the max
+ * This means that by reducing the delay on some DQ bits,
+ * we should find a failing condition.
+ */
+ printf("Byte %d, DQS unit = %d, phase = %d\n",
+ datx8, last_right_ok.unit, last_right_ok.phase);
+ pr_debug("Step2, unit = %d, phase = %d, bits delay=%x\n",
+ last_right_ok.unit, last_right_ok.phase,
+ last_right_ok.bits_delay);
+
+ /* Restore the last_right_ok condtion. */
+ DQS_unit_delay(phy, datx8, last_right_ok.unit);
+ DQS_phase_delay(phy, datx8, last_right_ok.phase);
+ writel(last_right_ok.bits_delay, DXNDQTR(phy, datx8));
+
+ /* train each bit
+ * reduce delay on each bit, and perform a write/read test
+ * and stop at the very first time it fails.
+ * the goal is the find the first failing condition
+ * for each bit.
+ * When we achieve this condition< for all the bits,
+ * we are sure they are aligned (+/- step resolution)
+ */
+ fail_found = 0;
+ for (bit_i = 0; bit_i < 8; bit_i++) {
+ if (ctrlc()) {
+ sprintf(string,
+ "interrupted at byte %d/%d, error=%d",
+ datx8 + 1, nb_bytes, error);
+ return error;
+ }
+ pr_debug("deskewing bit %d:\n", bit_i);
+ success = 1; /* init */
+ /* Set all DQDLYn to maximum value.
+ * Only bit_i will be down-delayed
+ * ==> if we have a fail, it will be definitely
+ * from bit_i
+ */
+ writel(0xFFFFFFFF, DXNDQTR(phy, datx8));
+ /* Arriving at this stage,
+ * we have a success condition with delay = 3;
+ */
+ bit_i_delay_index = 3;
+
+ /* escape if bit delay is out of range or
+ * if a fatil occurs
+ */
+ while ((bit_i_delay_index >= 0) && success) {
+ set_DQ_unit_delay(phy, datx8,
+ bit_i,
+ bit_i_delay_index);
+ BIST_test(phy, datx8, &result);
+ success = result.test_result;
+ bit_i_delay_index--;
+ }
+
+ /* if escape with a fail condition
+ * ==> save this position for bit_i
+ */
+ if (!success) {
+ /* save the delay position.
+ * Add 1 because the while loop ended with a --,
+ * and that we need to hold the last success
+ * delay
+ */
+ deskew_delay[datx8][bit_i] =
+ bit_i_delay_index + 2;
+ if (deskew_delay[datx8][bit_i] > 3)
+ deskew_delay[datx8][bit_i] = 3;
+
+ /* A flag that states we found at least a fail
+ * at one bit.
+ */
+ fail_found = 1;
+ pr_debug("Fail found on bit %d, for delay = %d => deskew[%d][%d] = %d\n",
+ bit_i, bit_i_delay_index + 1,
+ datx8, bit_i,
+ deskew_delay[datx8][bit_i]);
+ } else {
+ /* if we can find a success condition by
+ * back-delaying this bit, just set the delay
+ * to 0 (the best deskew
+ * possible) and mark the bit.
+ */
+ deskew_delay[datx8][bit_i] = 0;
+ /* set a flag that will be used later
+ * in the report.
+ */
+ deskew_non_converge[datx8][bit_i] = 1;
+ pr_debug("Fail not found on bit %d => deskew[%d][%d] = %d\n",
+ bit_i, datx8, bit_i,
+ deskew_delay[datx8][bit_i]);
+ }
+ }
+ pr_debug("**********byte %d tuning complete************\n",
+ datx8);
+ /* If we can't find any failure by back delaying DQ lines,
+ * hold the default values
+ */
+ if (!fail_found) {
+ for (bit_i = 0; bit_i < 8; bit_i++)
+ deskew_delay[datx8][bit_i] = 0;
+ pr_debug("The Deskew algorithm can't converge, there is too much margin in your design. Good job!\n");
+ }
+
+ apply_deskew_results(phy, datx8, deskew_delay,
+ deskew_non_converge);
+ /* Restore nominal value for DQS delay */
+ DQS_phase_delay(phy, datx8, 3);
+ DQS_unit_delay(phy, datx8, 3);
+ /* disable byte after byte bits deskew */
+ clrbits_le32(DXNGCR(phy, datx8), DDRPHYC_DXNGCR_DXEN);
+ } /* end of byte deskew */
+
+ /* re-enable all data bytes */
+ setbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
+ setbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
+ setbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
+ setbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
+
+ if (error) {
+ sprintf(string, "error = %d", error);
+ return TEST_FAILED;
+ }
+
+ return TEST_PASSED;
+} /* end function */
+
+/* Trim DQS timings and set it in the centre of data eye.
+ * Look for a PPPPF region, then look for a FPPP region and finally select
+ * the mid of the FPPPPPF region
+ */
+static enum test_result eye_training(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy, char *string)
+{
+ /*Stores the DQS trim values (PHASE index, unit index) */
+ u8 eye_training_val[NUM_BYTES][2];
+ u8 byte = 0;
+ struct BIST_result result;
+ s8 dqs_unit_delay_index = 0;
+ s8 phase_idx = 0;
+ s8 dqs_unit_delay_index_pass = 0;
+ s8 phase_idx_pass = 0;
+ u8 success = 0;
+ u8 left_phase_bound_found, right_phase_bound_found;
+ u8 left_unit_bound_found, right_unit_bound_found;
+ u8 left_bound_found, right_bound_found;
+ struct tuning_position left_bound, right_bound;
+ u8 error = 0;
+ u8 nb_bytes = get_nb_bytes(ctl);
+
+ /*Disable DQS Drift Compensation*/
+ clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP);
+ /*Disable all bytes*/
+ /* Disable automatic power down of DLL and IOs when disabling a byte
+ * (To avoid having to add programming and delay
+ * for a DLL re-lock when later re-enabling a disabled Byte Lane)
+ */
+ clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX);
+
+ /*Disable all data bytes */
+ clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
+
+ /* Config the BIST block */
+ config_BIST(phy);
+
+ for (byte = 0; byte < nb_bytes; byte++) {
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ byte + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ right_bound.phase = 0;
+ right_bound.unit = 0;
+
+ left_bound.phase = 0;
+ left_bound.unit = 0;
+
+ left_phase_bound_found = 0;
+ right_phase_bound_found = 0;
+
+ left_unit_bound_found = 0;
+ right_unit_bound_found = 0;
+
+ left_bound_found = 0;
+ right_bound_found = 0;
+
+ /* Enable Byte (DXNGCR, bit DXEN) */
+ setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN);
+
+ /* Select the byte lane for comparison of read data */
+ BIST_datx8_sel(phy, byte);
+
+ /* Set DQS phase delay to the nominal value. */
+ phase_idx = _90deg;
+ phase_idx_pass = phase_idx;
+
+ /* Set DQS unit delay to the nominal value. */
+ dqs_unit_delay_index = 3;
+ dqs_unit_delay_index_pass = dqs_unit_delay_index;
+ success = 0;
+
+ pr_debug("STEP0: Find Init delay\n");
+ /* STEP0: Find Init delay: a delay that put the system
+ * in a "Pass" condition then (TODO) update
+ * dqs_unit_delay_index_pass & phase_idx_pass
+ */
+ DQS_unit_delay(phy, byte, dqs_unit_delay_index);
+ DQS_phase_delay(phy, byte, phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ /* If we have a fail in the nominal condition */
+ if (!success) {
+ /* Look at the left */
+ while (phase_idx >= 0 && !success) {
+ phase_idx--;
+ DQS_phase_delay(phy, byte, phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ }
+ }
+ if (!success) {
+ /* if we can't find pass condition,
+ * then look at the right
+ */
+ phase_idx = _90deg;
+ while (phase_idx <= MAX_DQS_PHASE_IDX &&
+ !success) {
+ phase_idx++;
+ DQS_phase_delay(phy, byte,
+ phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ }
+ }
+ /* save the pass condition */
+ if (success) {
+ phase_idx_pass = phase_idx;
+ } else {
+ printf("Result: Failed ");
+ printf("[Cannot DQS timings, ");
+ printf("there is no PASS region]\n");
+ error++;
+ continue;
+ }
+
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ byte + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ pr_debug("STEP1: Find LEFT PHASE DQS Bound\n");
+ /* STEP1: Find LEFT PHASE DQS Bound */
+ while ((phase_idx >= 0) &&
+ (phase_idx <= MAX_DQS_PHASE_IDX) &&
+ !left_phase_bound_found) {
+ DQS_unit_delay(phy, byte,
+ dqs_unit_delay_index);
+ DQS_phase_delay(phy, byte,
+ phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+
+ /*TODO: Manage the case were at the beginning
+ * there is already a fail
+ */
+ if (!success) {
+ /* the last pass condition */
+ left_bound.phase = ++phase_idx;
+ left_phase_bound_found = 1;
+ } else if (success) {
+ phase_idx--;
+ }
+ }
+ if (!left_phase_bound_found) {
+ left_bound.phase = 0;
+ phase_idx = 0;
+ }
+ /* If not found, lets take 0 */
+
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ byte + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ pr_debug("STEP2: Find UNIT left bound\n");
+ /* STEP2: Find UNIT left bound */
+ while ((dqs_unit_delay_index >= 0) &&
+ !left_unit_bound_found) {
+ DQS_unit_delay(phy, byte,
+ dqs_unit_delay_index);
+ DQS_phase_delay(phy, byte, phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ if (!success) {
+ left_bound.unit =
+ ++dqs_unit_delay_index;
+ left_unit_bound_found = 1;
+ left_bound_found = 1;
+ } else if (success) {
+ dqs_unit_delay_index--;
+ }
+ }
+
+ /* If not found, lets take 0 */
+ if (!left_unit_bound_found)
+ left_bound.unit = 0;
+
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ byte + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ pr_debug("STEP3: Find PHase right bound\n");
+ /* STEP3: Find PHase right bound, start with "pass"
+ * condition
+ */
+
+ /* Set DQS phase delay to the pass value. */
+ phase_idx = phase_idx_pass;
+
+ /* Set DQS unit delay to the pass value. */
+ dqs_unit_delay_index = dqs_unit_delay_index_pass;
+
+ while ((phase_idx <= MAX_DQS_PHASE_IDX) &&
+ !right_phase_bound_found) {
+ DQS_unit_delay(phy, byte,
+ dqs_unit_delay_index);
+ DQS_phase_delay(phy, byte, phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ if (!success) {
+ /* the last pass condition */
+ right_bound.phase = --phase_idx;
+ right_phase_bound_found = 1;
+ } else if (success) {
+ phase_idx++;
+ }
+ }
+
+ /* If not found, lets take the max value */
+ if (!right_phase_bound_found) {
+ right_bound.phase = MAX_DQS_PHASE_IDX;
+ phase_idx = MAX_DQS_PHASE_IDX;
+ }
+
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d, error=%d",
+ byte + 1, nb_bytes, error);
+ return TEST_FAILED;
+ }
+ pr_debug("STEP4: Find UNIT right bound\n");
+ /* STEP4: Find UNIT right bound */
+ while ((dqs_unit_delay_index <= MAX_DQS_UNIT_IDX) &&
+ !right_unit_bound_found) {
+ DQS_unit_delay(phy, byte,
+ dqs_unit_delay_index);
+ DQS_phase_delay(phy, byte, phase_idx);
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ if (!success) {
+ right_bound.unit =
+ --dqs_unit_delay_index;
+ right_unit_bound_found = 1;
+ right_bound_found = 1;
+ } else if (success) {
+ dqs_unit_delay_index++;
+ }
+ }
+ /* If not found, lets take the max value */
+ if (!right_unit_bound_found)
+ right_bound.unit = MAX_DQS_UNIT_IDX;
+
+ /* If we found a regular FAil Pass FAil pattern
+ * FFPPPPPPFF
+ * OR PPPPPFF Or FFPPPPP
+ */
+
+ if (left_bound_found || right_bound_found) {
+ eye_training_val[byte][0] = (right_bound.phase +
+ left_bound.phase) / 2;
+ eye_training_val[byte][1] = (right_bound.unit +
+ left_bound.unit) / 2;
+
+ /* If we already lost 1/2PHASE Tuning,
+ * let's try to recover by ++ on unit
+ */
+ if (((right_bound.phase + left_bound.phase) % 2 == 1) &&
+ eye_training_val[byte][1] != MAX_DQS_UNIT_IDX)
+ eye_training_val[byte][1]++;
+ pr_debug("** found phase : %d - %d & unit %d - %d\n",
+ right_bound.phase, left_bound.phase,
+ right_bound.unit, left_bound.unit);
+ pr_debug("** calculating mid region: phase: %d unit: %d (nominal is 3)\n",
+ eye_training_val[byte][0],
+ eye_training_val[byte][1]);
+ } else {
+ /* PPPPPPPPPP, we're already good.
+ * Set nominal values.
+ */
+ eye_training_val[byte][0] = 3;
+ eye_training_val[byte][1] = 3;
+ }
+ DQS_phase_delay(phy, byte, eye_training_val[byte][0]);
+ DQS_unit_delay(phy, byte, eye_training_val[byte][1]);
+
+ printf("Byte %d, DQS unit = %d, phase = %d\n",
+ byte,
+ eye_training_val[byte][1],
+ eye_training_val[byte][0]);
+ }
+
+ if (error) {
+ sprintf(string, "error = %d", error);
+ return TEST_FAILED;
+ }
+
+ return TEST_PASSED;
+}
+
+static void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte)
+{
+ u8 i = 0;
+
+ printf("Byte %d Dekew result, bit0 delay, bit1 delay...bit8 delay\n ",
+ byte);
+
+ for (i = 0; i < 8; i++)
+ printf("%d ", DQ_unit_index(phy, byte, i));
+ printf("\n");
+
+ printf("dxndllcr: [%08x] val:%08x\n",
+ DXNDLLCR(phy, byte),
+ readl(DXNDLLCR(phy, byte)));
+ printf("dxnqdstr: [%08x] val:%08x\n",
+ DXNDQSTR(phy, byte),
+ readl(DXNDQSTR(phy, byte)));
+ printf("dxndqtr: [%08x] val:%08x\n",
+ DXNDQTR(phy, byte),
+ readl(DXNDQTR(phy, byte)));
+}
+
+/* analyse the dgs gating log table, and determine the midpoint.*/
+static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte,
+ u8 dqs_gating[NUM_BYTES]
+ [MAX_GSL_IDX + 1]
+ [MAX_GPS_IDX + 1])
+{
+ /* stores the dqs gate values (gsl index, gps index) */
+ u8 dqs_gate_values[NUM_BYTES][2];
+ u8 gsl_idx, gps_idx = 0;
+ u8 left_bound_idx[2] = {0, 0};
+ u8 right_bound_idx[2] = {0, 0};
+ u8 left_bound_found = 0;
+ u8 right_bound_found = 0;
+ u8 intermittent = 0;
+ u8 value;
+
+ for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) {
+ for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) {
+ value = dqs_gating[byte][gsl_idx][gps_idx];
+ if (value == 1 && left_bound_found == 0) {
+ left_bound_idx[0] = gsl_idx;
+ left_bound_idx[1] = gps_idx;
+ left_bound_found = 1;
+ } else if (value == 0 &&
+ left_bound_found == 1 &&
+ !right_bound_found) {
+ if (gps_idx == 0) {
+ right_bound_idx[0] = gsl_idx - 1;
+ right_bound_idx[1] = MAX_GPS_IDX;
+ } else {
+ right_bound_idx[0] = gsl_idx;
+ right_bound_idx[1] = gps_idx - 1;
+ }
+ right_bound_found = 1;
+ } else if (value == 1 &&
+ right_bound_found == 1) {
+ intermittent = 1;
+ }
+ }
+ }
+
+ /* if only ppppppp is found, there is no mid region. */
+ if (left_bound_idx[0] == 0 && left_bound_idx[1] == 0 &&
+ right_bound_idx[0] == 0 && right_bound_idx[1] == 0)
+ intermittent = 1;
+
+ /*if we found a regular fail pass fail pattern ffppppppff
+ * or pppppff or ffppppp
+ */
+ if (!intermittent) {
+ /*if we found a regular fail pass fail pattern ffppppppff
+ * or pppppff or ffppppp
+ */
+ if (left_bound_found || right_bound_found) {
+ pr_debug("idx0(%d): %d %d idx1(%d) : %d %d\n",
+ left_bound_found,
+ right_bound_idx[0], left_bound_idx[0],
+ right_bound_found,
+ right_bound_idx[1], left_bound_idx[1]);
+ dqs_gate_values[byte][0] =
+ (right_bound_idx[0] + left_bound_idx[0]) / 2;
+ dqs_gate_values[byte][1] =
+ (right_bound_idx[1] + left_bound_idx[1]) / 2;
+ /* if we already lost 1/2gsl tuning,
+ * let's try to recover by ++ on gps
+ */
+ if (((right_bound_idx[0] +
+ left_bound_idx[0]) % 2 == 1) &&
+ dqs_gate_values[byte][1] != MAX_GPS_IDX)
+ dqs_gate_values[byte][1]++;
+ /* if we already lost 1/2gsl tuning and gps is on max*/
+ else if (((right_bound_idx[0] +
+ left_bound_idx[0]) % 2 == 1) &&
+ dqs_gate_values[byte][1] == MAX_GPS_IDX) {
+ dqs_gate_values[byte][1] = 0;
+ dqs_gate_values[byte][0]++;
+ }
+ /* if we have gsl left and write limit too close
+ * (difference=1)
+ */
+ if (((right_bound_idx[0] - left_bound_idx[0]) == 1)) {
+ dqs_gate_values[byte][1] = (left_bound_idx[1] +
+ right_bound_idx[1] +
+ 4) / 2;
+ if (dqs_gate_values[byte][1] >= 4) {
+ dqs_gate_values[byte][0] =
+ right_bound_idx[0];
+ dqs_gate_values[byte][1] -= 4;
+ } else {
+ dqs_gate_values[byte][0] =
+ left_bound_idx[0];
+ }
+ }
+ pr_debug("*******calculating mid region: system latency: %d phase: %d********\n",
+ dqs_gate_values[byte][0],
+ dqs_gate_values[byte][1]);
+ pr_debug("*******the nominal values were system latency: 0 phase: 2*******\n");
+ set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]);
+ set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]);
+ }
+ } else {
+ /* if intermitant, restore defaut values */
+ pr_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n");
+ set_r0dgsl_delay(phy, byte, 0);
+ set_r0dgps_delay(phy, byte, 2);
+ }
+
+ /* return 0 if intermittent or if both left_bound
+ * and right_bound are not found
+ */
+ return !(intermittent || (left_bound_found && right_bound_found));
+}
+
+static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string)
+{
+ /* stores the log of pass/fail */
+ u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1];
+ u8 byte, gsl_idx, gps_idx = 0;
+ struct BIST_result result;
+ u8 success = 0;
+ u8 nb_bytes = get_nb_bytes(ctl);
+
+ memset(dqs_gating, 0x0, sizeof(dqs_gating));
+
+ /*disable dqs drift compensation*/
+ clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP);
+ /*disable all bytes*/
+ /* disable automatic power down of dll and ios when disabling a byte
+ * (to avoid having to add programming and delay
+ * for a dll re-lock when later re-enabling a disabled byte lane)
+ */
+ clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX);
+
+ /* disable all data bytes */
+ clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
+ clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
+
+ /* config the bist block */
+ config_BIST(phy);
+
+ for (byte = 0; byte < nb_bytes; byte++) {
+ if (ctrlc()) {
+ sprintf(string, "interrupted at byte %d/%d",
+ byte + 1, nb_bytes);
+ return TEST_FAILED;
+ }
+ /* enable byte x (dxngcr, bit dxen) */
+ setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN);
+
+ /* select the byte lane for comparison of read data */
+ BIST_datx8_sel(phy, byte);
+ for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) {
+ for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) {
+ if (ctrlc()) {
+ sprintf(string,
+ "interrupted at byte %d/%d",
+ byte + 1, nb_bytes);
+ return TEST_FAILED;
+ }
+ /* write cfg to dxndqstr */
+ set_r0dgsl_delay(phy, byte, gsl_idx);
+ set_r0dgps_delay(phy, byte, gps_idx);
+
+ BIST_test(phy, byte, &result);
+ success = result.test_result;
+ if (success)
+ dqs_gating[byte][gsl_idx][gps_idx] = 1;
+ itm_soft_reset(phy);
+ }
+ }
+ set_midpoint_read_dqs_gating(phy, byte, dqs_gating);
+ /* dummy reads */
+ readl(0xc0000000);
+ readl(0xc0000000);
+ }
+
+ /* re-enable drift compensation */
+ /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */
+ return TEST_PASSED;
+}
+
+/****************************************************************
+ * TEST
+ ****************************************************************
+ */
+static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc,
+ char *argv[])
+{
+ u32 rfshctl3 = readl(&ctl->rfshctl3);
+ u32 pwrctl = readl(&ctl->pwrctl);
+ enum test_result res;
+
+ stm32mp1_refresh_disable(ctl);
+ res = read_dqs_gating(ctl, phy, string);
+ stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+
+ return res;
+}
+
+static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 rfshctl3 = readl(&ctl->rfshctl3);
+ u32 pwrctl = readl(&ctl->pwrctl);
+ enum test_result res;
+
+ stm32mp1_refresh_disable(ctl);
+ res = bit_deskew(ctl, phy, string);
+ stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+
+ return res;
+}
+
+static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ u32 rfshctl3 = readl(&ctl->rfshctl3);
+ u32 pwrctl = readl(&ctl->pwrctl);
+ enum test_result res;
+
+ stm32mp1_refresh_disable(ctl);
+ res = eye_training(ctl, phy, string);
+ stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+
+ return res;
+}
+
+static enum test_result do_display(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ int byte;
+ u8 nb_bytes = get_nb_bytes(ctl);
+
+ for (byte = 0; byte < nb_bytes; byte++)
+ display_reg_results(phy, byte);
+
+ return TEST_PASSED;
+}
+
+static enum test_result do_bist_config(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy,
+ char *string, int argc, char *argv[])
+{
+ unsigned long value;
+
+ if (argc > 0) {
+ if (strict_strtoul(argv[0], 0, &value) < 0) {
+ sprintf(string, "invalid nbErr %s", argv[0]);
+ return TEST_FAILED;
+ }
+ BIST_error_max = value;
+ }
+ if (argc > 1) {
+ if (strict_strtoul(argv[1], 0, &value) < 0) {
+ sprintf(string, "invalid Seed %s", argv[1]);
+ return TEST_FAILED;
+ }
+ BIST_seed = value;
+ }
+ printf("Bist.nbErr = %d\n", BIST_error_max);
+ if (BIST_seed)
+ printf("Bist.Seed = 0x%x\n", BIST_seed);
+ else
+ printf("Bist.Seed = random\n");
+
+ return TEST_PASSED;
+}
+
+/****************************************************************
+ * TEST Description
+ ****************************************************************
+ */
+
+const struct test_desc tuning[] = {
+ {do_read_dqs_gating, "Read DQS gating",
+ "software read DQS Gating", "", 0 },
+ {do_bit_deskew, "Bit de-skew", "", "", 0 },
+ {do_eye_training, "Eye Training", "or DQS training", "", 0 },
+ {do_display, "Display registers", "", "", 0 },
+ {do_bist_config, "Bist config", "[nbErr] [seed]",
+ "configure Bist test", 2},
+};
+
+const int tuning_nb = ARRAY_SIZE(tuning);
diff --git a/drivers/remoteproc/k3_system_controller.c b/drivers/remoteproc/k3_system_controller.c
index 214ea18d8a..44e56c759f 100644
--- a/drivers/remoteproc/k3_system_controller.c
+++ b/drivers/remoteproc/k3_system_controller.c
@@ -301,7 +301,7 @@ static int k3_sysctrler_probe(struct udevice *dev)
static const struct k3_sysctrler_desc k3_sysctrler_am654_desc = {
.host_id = 4, /* HOST_ID_R5_1 */
- .max_rx_timeout_us = 400000,
+ .max_rx_timeout_us = 800000,
.max_msg_size = 60,
};
diff --git a/drivers/reset/reset-rockchip.c b/drivers/reset/reset-rockchip.c
index af07134049..3871fc00d0 100644
--- a/drivers/reset/reset-rockchip.c
+++ b/drivers/reset/reset-rockchip.c
@@ -7,7 +7,7 @@
#include <dm.h>
#include <reset-uclass.h>
#include <linux/io.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/hardware.h>
#include <dm/lists.h>
/*
* Each reg has 16 bits reset signal for devices
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index cb8312619f..ee4cbcb02f 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -107,14 +107,12 @@ static const struct reset_ops socfpga_reset_ops = {
static int socfpga_reset_probe(struct udevice *dev)
{
struct socfpga_reset_data *data = dev_get_priv(dev);
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(dev);
u32 modrst_offset;
void __iomem *membase;
membase = devfdt_get_addr_ptr(dev);
- modrst_offset = fdtdec_get_int(blob, node, "altr,modrst-offset", 0x10);
+ modrst_offset = dev_read_u32_default(dev, "altr,modrst-offset", 0x10);
data->modrst_base = membase + modrst_offset;
return 0;
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index 89e39c6b5a..ee1a423ffb 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -29,41 +29,34 @@ static int reset_of_xlate_default(struct reset_ctl *reset_ctl,
return 0;
}
-int reset_get_by_index(struct udevice *dev, int index,
- struct reset_ctl *reset_ctl)
+static int reset_get_by_index_tail(int ret, ofnode node,
+ struct ofnode_phandle_args *args,
+ const char *list_name, int index,
+ struct reset_ctl *reset_ctl)
{
- struct ofnode_phandle_args args;
- int ret;
struct udevice *dev_reset;
struct reset_ops *ops;
- debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index,
- reset_ctl);
+ assert(reset_ctl);
reset_ctl->dev = NULL;
-
- ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
- index, &args);
- if (ret) {
- debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n",
- __func__, ret);
+ if (ret)
return ret;
- }
- ret = uclass_get_device_by_ofnode(UCLASS_RESET, args.node,
+ ret = uclass_get_device_by_ofnode(UCLASS_RESET, args->node,
&dev_reset);
if (ret) {
debug("%s: uclass_get_device_by_ofnode() failed: %d\n",
__func__, ret);
- debug("%s %d\n", ofnode_get_name(args.node), args.args[0]);
+ debug("%s %d\n", ofnode_get_name(args->node), args->args[0]);
return ret;
}
ops = reset_dev_ops(dev_reset);
reset_ctl->dev = dev_reset;
if (ops->of_xlate)
- ret = ops->of_xlate(reset_ctl, &args);
+ ret = ops->of_xlate(reset_ctl, args);
else
- ret = reset_of_xlate_default(reset_ctl, &args);
+ ret = reset_of_xlate_default(reset_ctl, args);
if (ret) {
debug("of_xlate() failed: %d\n", ret);
return ret;
@@ -78,6 +71,32 @@ int reset_get_by_index(struct udevice *dev, int index,
return 0;
}
+int reset_get_by_index(struct udevice *dev, int index,
+ struct reset_ctl *reset_ctl)
+{
+ struct ofnode_phandle_args args;
+ int ret;
+
+ ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
+ index, &args);
+
+ return reset_get_by_index_tail(ret, dev_ofnode(dev), &args, "resets",
+ index > 0, reset_ctl);
+}
+
+int reset_get_by_index_nodev(ofnode node, int index,
+ struct reset_ctl *reset_ctl)
+{
+ struct ofnode_phandle_args args;
+ int ret;
+
+ ret = ofnode_parse_phandle_with_args(node, "resets", "#reset-cells", 0,
+ index > 0, &args);
+
+ return reset_get_by_index_tail(ret, node, &args, "resets",
+ index > 0, reset_ctl);
+}
+
int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
{
int i, ret, err, count;
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 6528ddfebb..1f7bdade29 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -23,7 +23,7 @@ static const unsigned char rtc_days_in_month[] = {
/*
* The number of days in the month.
*/
-static int rtc_month_days(unsigned int month, unsigned int year)
+int rtc_month_days(unsigned int month, unsigned int year)
{
return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index fcbb0a81ed..8a447fd6e3 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -559,6 +559,14 @@ config MVEBU_A3700_UART
Choose this option to add support for UART driver on the Marvell
Armada 3700 SoC. The base address is configured via DT.
+config MCFUART
+ bool "Freescale ColdFire UART support"
+ help
+ Choose this option to add support for UART driver on the ColdFire
+ SoC's family. The serial communication channel provides a full-duplex
+ asynchronous/synchronous receiver and transmitter deriving an
+ operating frequency from the internal bus clock or an external clock.
+
config MXC_UART
bool "IMX serial port support"
depends on MX5 || MX6
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
index 67d47199aa..436cf2331d 100644
--- a/drivers/serial/altera_uart.c
+++ b/drivers/serial/altera_uart.c
@@ -10,8 +10,6 @@
#include <serial.h>
#include <asm/io.h>
-DECLARE_GLOBAL_DATA_PTR;
-
/* status register */
#define ALTERA_UART_TMT BIT(5) /* tx empty */
#define ALTERA_UART_TRDY BIT(6) /* tx ready */
@@ -91,8 +89,7 @@ static int altera_uart_ofdata_to_platdata(struct udevice *dev)
plat->regs = map_physmem(devfdt_get_addr(dev),
sizeof(struct altera_uart_regs),
MAP_NOCACHE);
- plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "clock-frequency", 0);
+ plat->uartclk = dev_read_u32_default(dev, "clock-frequency", 0);
return 0;
}
diff --git a/drivers/serial/mcfuart.c b/drivers/serial/mcfuart.c
index 1371049de2..066e5a18d8 100644
--- a/drivers/serial/mcfuart.c
+++ b/drivers/serial/mcfuart.c
@@ -5,6 +5,9 @@
*
* Modified to add device model (DM) support
* (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it>
+ *
+ * Modified to add DM and fdt support, removed non DM code
+ * (C) Copyright 2018 Angelo Dureghello <angelo@sysam.it>
*/
/*
@@ -78,83 +81,6 @@ static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
}
-#ifndef CONFIG_DM_SERIAL
-
-static int mcf_serial_init(void)
-{
- uart_t *uart_base;
- int port_idx;
-
- uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
- port_idx = CONFIG_SYS_UART_PORT;
-
- return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
-}
-
-static void mcf_serial_putc(const char c)
-{
- uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
-
- if (c == '\n')
- serial_putc('\r');
-
- /* Wait for last character to go. */
- while (!(readb(&uart->usr) & UART_USR_TXRDY))
- ;
-
- writeb(c, &uart->utb);
-}
-
-static int mcf_serial_getc(void)
-{
- uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
-
- /* Wait for a character to arrive. */
- while (!(readb(&uart->usr) & UART_USR_RXRDY))
- ;
-
- return readb(&uart->urb);
-}
-
-static void mcf_serial_setbrg(void)
-{
- uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
-
- mcf_serial_setbrg_common(uart, gd->baudrate);
-}
-
-static int mcf_serial_tstc(void)
-{
- uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
-
- return readb(&uart->usr) & UART_USR_RXRDY;
-}
-
-static struct serial_device mcf_serial_drv = {
- .name = "mcf_serial",
- .start = mcf_serial_init,
- .stop = NULL,
- .setbrg = mcf_serial_setbrg,
- .putc = mcf_serial_putc,
- .puts = default_serial_puts,
- .getc = mcf_serial_getc,
- .tstc = mcf_serial_tstc,
-};
-
-void mcf_serial_initialize(void)
-{
- serial_register(&mcf_serial_drv);
-}
-
-__weak struct serial_device *default_serial_console(void)
-{
- return &mcf_serial_drv;
-}
-
-#endif
-
-#ifdef CONFIG_DM_SERIAL
-
static int coldfire_serial_probe(struct udevice *dev)
{
struct coldfire_serial_platdata *plat = dev->platdata;
@@ -212,6 +138,23 @@ static int coldfire_serial_pending(struct udevice *dev, bool input)
return 0;
}
+static int coldfire_ofdata_to_platdata(struct udevice *dev)
+{
+ struct coldfire_serial_platdata *plat = dev_get_platdata(dev);
+ fdt_addr_t addr_base;
+
+ addr_base = devfdt_get_addr(dev);
+ if (addr_base == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ plat->base = (uint32_t)addr_base;
+
+ plat->port = dev->seq;
+ plat->baudrate = gd->baudrate;
+
+ return 0;
+}
+
static const struct dm_serial_ops coldfire_serial_ops = {
.putc = coldfire_serial_putc,
.pending = coldfire_serial_pending,
@@ -219,11 +162,18 @@ static const struct dm_serial_ops coldfire_serial_ops = {
.setbrg = coldfire_serial_setbrg,
};
+static const struct udevice_id coldfire_serial_ids[] = {
+ { .compatible = "fsl,mcf-uart" },
+ { }
+};
+
U_BOOT_DRIVER(serial_coldfire) = {
.name = "serial_coldfire",
.id = UCLASS_SERIAL,
+ .of_match = coldfire_serial_ids,
+ .ofdata_to_platdata = coldfire_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct coldfire_serial_platdata),
.probe = coldfire_serial_probe,
.ops = &coldfire_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
-#endif
diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c
index 35fefd74c6..b1718f72d1 100644
--- a/drivers/serial/serial_rockchip.c
+++ b/drivers/serial/serial_rockchip.c
@@ -9,7 +9,7 @@
#include <dt-structs.h>
#include <ns16550.h>
#include <serial.h>
-#include <asm/arch/clock.h>
+#include <asm/arch-rockchip/clock.h>
#if defined(CONFIG_ROCKCHIP_RK3188)
struct rockchip_uart_platdata {
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index c934d5f25a..acfcc2954a 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -19,10 +19,7 @@
DECLARE_GLOBAL_DATA_PTR;
-#if defined(CONFIG_CPU_SH7760) || \
- defined(CONFIG_CPU_SH7780) || \
- defined(CONFIG_CPU_SH7785) || \
- defined(CONFIG_CPU_SH7786)
+#if defined(CONFIG_CPU_SH7780)
static int scif_rxfill(struct uart_port *port)
{
return sci_in(port, SCRFDR) & 0xff;
@@ -39,14 +36,6 @@ static int scif_rxfill(struct uart_port *port)
return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
}
}
-#elif defined(CONFIG_ARCH_SH7372)
-static int scif_rxfill(struct uart_port *port)
-{
- if (port->type == PORT_SCIFA)
- return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
- else
- return sci_in(port, SCRFDR);
-}
#else
static int scif_rxfill(struct uart_port *port)
{
@@ -63,6 +52,9 @@ static void sh_serial_init_generic(struct uart_port *port)
sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST);
sci_in(port, SCFCR);
sci_out(port, SCFCR, 0);
+#if defined(CONFIG_RZA1)
+ sci_out(port, SCSPTR, 0x0003);
+#endif
}
static void
diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h
index deb4b647c6..11deaa9511 100644
--- a/drivers/serial/serial_sh.h
+++ b/drivers/serial/serial_sh.h
@@ -12,53 +12,16 @@ struct uart_port {
enum sh_clk_mode clk_mode; /* clock mode */
};
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#endif
-#if defined(CONFIG_H8S2678)
-#include <asm/regs267x.h>
-#endif
-
-#if defined(CONFIG_CPU_SH7706) || \
- defined(CONFIG_CPU_SH7707) || \
- defined(CONFIG_CPU_SH7708) || \
- defined(CONFIG_CPU_SH7709)
-# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
-# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
-# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-#elif defined(CONFIG_CPU_SH7705)
-# define SCIF0 0xA4400000
-# define SCIF2 0xA4410000
-# define SCSMR_Ir 0xA44A0000
-# define IRDA_SCIF SCIF0
-# define SCPCR 0xA4000116
-# define SCPDR 0xA4000136
-
-/* Set the clock source,
- * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input
- * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output
- */
-# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
-#elif defined(CONFIG_CPU_SH7720) || \
- defined(CONFIG_CPU_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372) || \
+#if defined(CONFIG_CPU_SH7721) || \
defined(CONFIG_SH73A0) || \
defined(CONFIG_R8A7740)
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define PORT_PTCR 0xA405011EUL
# define PORT_PVCR 0xA4050122UL
# define SCIF_ORER 0x0200 /* overrun error bit */
-#elif defined(CONFIG_SH_RTS7751R2D)
-# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SH7750) || \
defined(CONFIG_CPU_SH7750R) || \
defined(CONFIG_CPU_SH7750S) || \
- defined(CONFIG_CPU_SH7091) || \
defined(CONFIG_CPU_SH7751) || \
defined(CONFIG_CPU_SH7751R)
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
@@ -67,24 +30,6 @@ struct uart_port {
# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */)
-#elif defined(CONFIG_CPU_SH7760)
-# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
-# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
-# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7710) || defined(CONFIG_CPU_SH7712)
-# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define PACR 0xa4050100
-# define PBCR 0xa4050102
-# define SCSCR_INIT(port) 0x3B
-#elif defined(CONFIG_CPU_SH7343)
-# define SCSPTR0 0xffe00010 /* 16 bit SCIF */
-# define SCSPTR1 0xffe10010 /* 16 bit SCIF */
-# define SCSPTR2 0xffe20010 /* 16 bit SCIF */
-# define SCSPTR3 0xffe30010 /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
#elif defined(CONFIG_CPU_SH7722)
# define PADR 0xA4050120
# undef PSDR
@@ -93,11 +38,6 @@ struct uart_port {
# define PSCR 0xA405011E
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7366)
-# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */
-# define SCSPTR0 SCPDR0
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_CPU_SH7723)
# define SCSPTR0 0xa4050160
# define SCSPTR1 0xa405013e
@@ -107,11 +47,6 @@ struct uart_port {
# define SCSPTR5 0xa4050128
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7724)
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \
- 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
- 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */)
#elif defined(CONFIG_CPU_SH7734)
# define SCSPTR0 0xFFE40020
# define SCSPTR1 0xFFE41020
@@ -121,26 +56,6 @@ struct uart_port {
# define SCSPTR5 0xFFE45020
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH4_202)
-# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH5_101) || defined(CONFIG_CPU_SH5_103)
-# define SCIF_BASE_ADDR 0x01030000
-# define SCIF_ADDR_SH5 (PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR)
-# define SCIF_PTR2_OFFS 0x0000020
-# define SCIF_LSR2_OFFS 0x0000024
-# define SCSPTR\
- ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
-# define SCLSR2\
- ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
-# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define H8300_SCI_DR(ch) (*(volatile char *)(P1DR + h8300_sci_pins[ch].port))
-#elif defined(CONFIG_H8S2678)
-# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define H8300_SCI_DR(ch) (*(volatile char *)(P1DR + h8300_sci_pins[ch].port))
#elif defined(CONFIG_CPU_SH7757) || \
defined(CONFIG_CPU_SH7752) || \
defined(CONFIG_CPU_SH7753)
@@ -156,52 +71,15 @@ struct uart_port {
# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7770)
-# define SCSPTR0 0xff923020 /* 16 bit SCIF */
-# define SCSPTR1 0xff924020 /* 16 bit SCIF */
-# define SCSPTR2 0xff925020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */
#elif defined(CONFIG_CPU_SH7780)
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* Overrun error bit */
-#if defined(CONFIG_SH_SH2007)
-/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
-# define SCSCR_INIT(port) 0x38
-#else
/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
# define SCSCR_INIT(port) 0x3a
-#endif
-#elif defined(CONFIG_CPU_SH7785) || \
- defined(CONFIG_CPU_SH7786)
-# define SCSPTR0 0xffea0024 /* 16 bit SCIF */
-# define SCSPTR1 0xffeb0024 /* 16 bit SCIF */
-# define SCSPTR2 0xffec0024 /* 16 bit SCIF */
-# define SCSPTR3 0xffed0024 /* 16 bit SCIF */
-# define SCSPTR4 0xffee0024 /* 16 bit SCIF */
-# define SCSPTR5 0xffef0024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* Overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7201) || \
- defined(CONFIG_CPU_SH7203) || \
- defined(CONFIG_CPU_SH7206) || \
- defined(CONFIG_CPU_SH7263) || \
- defined(CONFIG_CPU_SH7264)
-# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
-# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
-# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
-# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
-# if defined(CONFIG_CPU_SH7201)
-# define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
-# define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
-# define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
-# define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
-# endif
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7269)
+#elif defined(CONFIG_RZA1)
# define SCSPTR0 0xe8007020 /* 16 bit SCIF */
# define SCSPTR1 0xe8007820 /* 16 bit SCIF */
# define SCSPTR2 0xe8008020 /* 16 bit SCIF */
@@ -211,19 +89,7 @@ struct uart_port {
# define SCSPTR6 0xe800a020 /* 16 bit SCIF */
# define SCSPTR7 0xe800a820 /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SH7619)
-# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
-# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
-# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SHX3)
-# define SCSPTR0 0xffc30020 /* 16 bit SCIF */
-# define SCSPTR1 0xffc40020 /* 16 bit SCIF */
-# define SCSPTR2 0xffc50020 /* 16 bit SCIF */
-# define SCSPTR3 0xffc60020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001 /* Overrun error bit */
-# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_RCAR_GEN2) || defined(CONFIG_RCAR_GEN3) || \
defined(CONFIG_R7S72100)
# if defined(CONFIG_SCIF_A)
@@ -243,7 +109,6 @@ struct uart_port {
#define SCI_CTRL_FLAGS_TE 0x20 /* all */
#define SCI_CTRL_FLAGS_RE 0x10 /* all */
#if defined(CONFIG_CPU_SH7750) || \
- defined(CONFIG_CPU_SH7091) || \
defined(CONFIG_CPU_SH7750R) || \
defined(CONFIG_CPU_SH7722) || \
defined(CONFIG_CPU_SH7734) || \
@@ -251,13 +116,8 @@ struct uart_port {
defined(CONFIG_CPU_SH7751) || \
defined(CONFIG_CPU_SH7751R) || \
defined(CONFIG_CPU_SH7763) || \
- defined(CONFIG_CPU_SH7780) || \
- defined(CONFIG_CPU_SH7785) || \
- defined(CONFIG_CPU_SH7786) || \
- defined(CONFIG_CPU_SHX3)
+ defined(CONFIG_CPU_SH7780)
#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
-#elif defined(CONFIG_CPU_SH7724)
-#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8)
#else
#define SCI_CTRL_FLAGS_REIE 0
#endif
@@ -288,12 +148,7 @@ struct uart_port {
#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#if defined(CONFIG_CPU_SH7705) || \
- defined(CONFIG_CPU_SH7720) || \
- defined(CONFIG_CPU_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372) || \
+#if defined(CONFIG_CPU_SH7721) || \
defined(CONFIG_SH73A0) || \
defined(CONFIG_R8A7740)
# define SCIF_ORER 0x0200
@@ -341,12 +196,7 @@ struct uart_port {
#define SCxSR_ORER(port)\
(((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER)
-#if defined(CONFIG_CPU_SH7705) || \
- defined(CONFIG_CPU_SH7720) || \
- defined(CONFIG_CPU_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372) || \
+#if defined(CONFIG_CPU_SH7721) || \
defined(CONFIG_SH73A0) || \
defined(CONFIG_R8A7740)
# define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc)
@@ -410,16 +260,6 @@ static inline void sci_##name##_out(struct uart_port *port,\
}\
}
-#ifdef CONFIG_H8300
-/* h8300 don't have SCIF */
-#define CPU_SCIF_FNS(name) \
- static inline unsigned int sci_##name##_in(struct uart_port *port) {\
- return 0;\
- }\
- static inline void sci_##name##_out(struct uart_port *port,\
- unsigned int value) {\
- }
-#else
#define CPU_SCIF_FNS(name, scif_offset, scif_size) \
static inline unsigned int sci_##name##_in(struct uart_port *port) {\
SCI_IN(scif_size, scif_offset);\
@@ -428,7 +268,6 @@ static inline void sci_##name##_out(struct uart_port *port,\
unsigned int value) {\
SCI_OUT(scif_size, scif_offset, value);\
}
-#endif
#define CPU_SCI_FNS(name, sci_offset, sci_size)\
static inline unsigned int sci_##name##_in(struct uart_port *port) {\
@@ -439,33 +278,13 @@ static inline void sci_##name##_out(struct uart_port *port,\
SCI_OUT(sci_size, sci_offset, value);\
}
-#if defined(CONFIG_CPU_SH3) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372) || \
- defined(CONFIG_SH73A0) || \
+#if defined(CONFIG_SH73A0) || \
defined(CONFIG_R8A7740)
-#if defined(CONFIG_CPU_SH7710) || defined(CONFIG_CPU_SH7712)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size,\
- sh4_sci_offset, sh4_sci_size, \
- sh3_scif_offset, sh3_scif_size, \
- sh4_scif_offset, sh4_scif_size, \
- h8_sci_offset, h8_sci_size) \
- CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size,\
- sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size,\
- sh4_scif_offset, sh4_scif_size) \
- CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SH7705) || \
- defined(CONFIG_CPU_SH7720) || \
- defined(CONFIG_CPU_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
+#if defined(CONFIG_CPU_SH7721) || \
defined(CONFIG_SH73A0)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
-#elif defined(CONFIG_ARCH_SH7372) || \
- defined(CONFIG_R8A7740)
+#elif defined(CONFIG_R8A7740)
#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
sh4_scifb_offset, sh4_scifb_size) \
CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
@@ -484,17 +303,7 @@ static inline void sci_##name##_out(struct uart_port *port,\
sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
#endif
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size,\
- sh4_sci_offset, sh4_sci_size, \
- sh3_scif_offset, sh3_scif_size,\
- sh4_scif_offset, sh4_scif_size, \
- h8_sci_offset, h8_sci_size) \
- CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size,\
- sh4_scif_offset, sh4_scif_size) \
- CPU_SCIF_FNS(name)
-#elif defined(CONFIG_CPU_SH7723) || defined(CONFIG_CPU_SH7724)
+#elif defined(CONFIG_CPU_SH7723)
#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
sh4_scif_offset, sh4_scif_size) \
CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
@@ -514,11 +323,7 @@ static inline void sci_##name##_out(struct uart_port *port,\
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-#if defined(CONFIG_CPU_SH7705) || \
- defined(CONFIG_CPU_SH7720) || \
- defined(CONFIG_CPU_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
+#if defined(CONFIG_CPU_SH7721) || \
defined(CONFIG_SH73A0)
SCIF_FNS(SCSMR, 0x00, 16)
@@ -533,8 +338,7 @@ SCIF_FNS(SCxTDR, 0x20, 8)
SCIF_FNS(SCxRDR, 0x24, 8)
SCIF_FNS(SCLSR, 0x00, 0)
SCIF_FNS(DL, 0x00, 0) /* dummy */
-#elif defined(CONFIG_ARCH_SH7372) || \
- defined(CONFIG_R8A7740)
+#elif defined(CONFIG_R8A7740)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
SCIF_FNS(SCSCR, 0x08, 16)
@@ -549,8 +353,7 @@ SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8)
SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8)
SCIF_FNS(SCLSR, 0x00, 0)
SCIF_FNS(DL, 0x00, 0) /* dummy */
-#elif defined(CONFIG_CPU_SH7723) ||\
- defined(CONFIG_CPU_SH7724)
+#elif defined(CONFIG_CPU_SH7723)
SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16)
SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8)
SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16)
@@ -592,10 +395,7 @@ SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8)
SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8)
SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8)
SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
-#if defined(CONFIG_CPU_SH7760) || \
- defined(CONFIG_CPU_SH7780) || \
- defined(CONFIG_CPU_SH7785) || \
- defined(CONFIG_CPU_SH7786)
+#if defined(CONFIG_CPU_SH7780)
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16)
@@ -624,76 +424,17 @@ SCIF_FNS(DL, 0, 0, 0x0, 0) /* dummy */
#define sci_in(port, reg) sci_##reg##_in(port)
#define sci_out(port, reg, value) sci_##reg##_out(port, value)
-/* H8/300 series SCI pins assignment */
-#if defined(__H8300H__) || defined(__H8300S__)
-static const struct __attribute__((packed)) {
- int port; /* GPIO port no */
- unsigned short rx, tx; /* GPIO bit no */
-} h8300_sci_pins[] = {
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
- { /* SCI0 */
- .port = H8300_GPIO_P9,
- .rx = H8300_GPIO_B2,
- .tx = H8300_GPIO_B0,
- },
- { /* SCI1 */
- .port = H8300_GPIO_P9,
- .rx = H8300_GPIO_B3,
- .tx = H8300_GPIO_B1,
- },
- { /* SCI2 */
- .port = H8300_GPIO_PB,
- .rx = H8300_GPIO_B7,
- .tx = H8300_GPIO_B6,
- }
-#elif defined(CONFIG_H8S2678)
- { /* SCI0 */
- .port = H8300_GPIO_P3,
- .rx = H8300_GPIO_B2,
- .tx = H8300_GPIO_B0,
- },
- { /* SCI1 */
- .port = H8300_GPIO_P3,
- .rx = H8300_GPIO_B3,
- .tx = H8300_GPIO_B1,
- },
- { /* SCI2 */
- .port = H8300_GPIO_P5,
- .rx = H8300_GPIO_B1,
- .tx = H8300_GPIO_B0,
- }
-#endif
-};
-#endif
-
-#if defined(CONFIG_CPU_SH7706) || \
- defined(CONFIG_CPU_SH7707) || \
- defined(CONFIG_CPU_SH7708) || \
- defined(CONFIG_CPU_SH7709)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xfffffe80)
- return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
- return 1;
-}
-#elif defined(CONFIG_CPU_SH7750) || \
+#if defined(CONFIG_CPU_SH7750) || \
defined(CONFIG_CPU_SH7751) || \
defined(CONFIG_CPU_SH7751R) || \
defined(CONFIG_CPU_SH7750R) || \
- defined(CONFIG_CPU_SH7750S) || \
- defined(CONFIG_CPU_SH7091)
+ defined(CONFIG_CPU_SH7750S)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
return 1;
}
-#elif defined(__H8300H__) || defined(__H8300S__)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- int ch = (port->mapbase - SMR0) >> 3;
- return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
-}
#else /* default case for non-SCI processors */
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -733,22 +474,13 @@ static inline int sci_rxd_in(struct uart_port *port)
* -- Mitch Davis - 15 Jul 2000
*/
-#if (defined(CONFIG_CPU_SH7780) || \
- defined(CONFIG_CPU_SH7785) || \
- defined(CONFIG_CPU_SH7786)) && \
- !defined(CONFIG_SH_SH2007)
+#if defined(CONFIG_CPU_SH7780)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
-#elif defined(CONFIG_CPU_SH7705) || \
- defined(CONFIG_CPU_SH7720) || \
- defined(CONFIG_CPU_SH7721) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372) || \
+#elif defined(CONFIG_CPU_SH7721) || \
defined(CONFIG_SH73A0) || \
defined(CONFIG_R8A7740)
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
-#elif defined(CONFIG_CPU_SH7723) ||\
- defined(CONFIG_CPU_SH7724)
+#elif defined(CONFIG_CPU_SH7723)
static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
{
if (port->type == PORT_SCIF)
@@ -757,8 +489,6 @@ static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
return ((clk*2)+16*bps)/(16*bps)-1;
}
#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
#elif defined(CONFIG_RCAR_GEN2)
#define DL_VALUE(bps, clk) (clk / bps / 16) /* External Clock */
#if defined(CONFIG_SCIF_A)
diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c
index 537bc7a975..fdfef69aaa 100644
--- a/drivers/serial/serial_sifive.c
+++ b/drivers/serial/serial_sifive.c
@@ -3,8 +3,8 @@
* Copyright (C) 2018 Anup Patel <anup@brainfault.org>
*/
-#include <clk.h>
#include <common.h>
+#include <clk.h>
#include <debug_uart.h>
#include <dm.h>
#include <errno.h>
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index e31c87b9ac..cca8b707ac 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -269,7 +269,6 @@ static inline void _debug_uart_init(void)
_stm32_serial_setbrg(base, uart_info,
CONFIG_DEBUG_UART_CLOCK,
CONFIG_BAUDRATE);
- printf("DEBUG done\n");
}
static inline void _debug_uart_putc(int c)
@@ -278,7 +277,7 @@ static inline void _debug_uart_putc(int c)
struct stm32_uart_info *uart_info = _debug_uart_info();
while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN)
- WATCHDOG_RESET();
+ ;
}
DEBUG_UART_FUNCS
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 6e9dcefcb9..4ebc719be2 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -71,6 +71,15 @@ config SOUND_IVYBRIDGE
sometimes called Azalia. The audio codec is detected using a
semi-automatic mechanism.
+config I2S_TEGRA
+ bool "Enable I2S support for Nvidia Tegra SoCs"
+ depends on I2S
+ select TEGRA124_DMA
+ help
+ Nvidia Tegra SoCs support several I2S interfaces for sending audio
+ data to an audio codec. This option enables support for this,
+ using one of the available audio codec drivers.
+
config SOUND_MAX98088
bool "Support Maxim max98088 audio codec"
depends on I2S
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index e155041ff5..73ed7fe53c 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
obj-$(CONFIG_I2S_ROCKCHIP) += rockchip_i2s.o rockchip_sound.o
obj-$(CONFIG_I2S_SAMSUNG) += samsung_sound.o
+obj-$(CONFIG_I2S_TEGRA) += tegra_ahub.o tegra_i2s.o tegra_sound.o
obj-$(CONFIG_SOUND_WM8994) += wm8994.o
obj-$(CONFIG_SOUND_MAX98088) += max98088.o maxim_codec.o
obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o
diff --git a/drivers/sound/rockchip_sound.c b/drivers/sound/rockchip_sound.c
index e7fb9fb164..a092dbc445 100644
--- a/drivers/sound/rockchip_sound.c
+++ b/drivers/sound/rockchip_sound.c
@@ -13,7 +13,7 @@
#include <i2s.h>
#include <misc.h>
#include <sound.h>
-#include <asm/arch/periph.h>
+#include <asm/arch-rockchip/periph.h>
#include <dm/pinctrl.h>
static int rockchip_sound_setup(struct udevice *dev)
diff --git a/drivers/sound/tegra_ahub.c b/drivers/sound/tegra_ahub.c
new file mode 100644
index 0000000000..c71fce9bb1
--- /dev/null
+++ b/drivers/sound/tegra_ahub.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0+159
+/*
+ * Take from dc tegra_ahub.c
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_MISC
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <misc.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/tegra_ahub.h>
+#include <asm/arch-tegra/tegra_i2s.h>
+#include "tegra_i2s_priv.h"
+
+struct tegra_ahub_priv {
+ struct apbif_regs *apbif_regs;
+ struct xbar_regs *xbar_regs;
+ u32 full_mask;
+ int capacity_words; /* FIFO capacity in words */
+
+ /*
+ * This is unset intially, but is set by tegra_ahub_ioctl() called
+ * from the misc_ioctl() in tegra_sound_probe()
+ */
+ struct udevice *i2s;
+ struct udevice *dma;
+};
+
+static int tegra_ahub_xbar_enable_i2s(struct xbar_regs *regs, int i2s_id)
+{
+ /*
+ * Enables I2S as the receiver of APBIF by writing APBIF_TX0 (0x01) to
+ * the rx0 register
+ */
+ switch (i2s_id) {
+ case 0:
+ writel(1, &regs->i2s0_rx0);
+ break;
+ case 1:
+ writel(1, &regs->i2s1_rx0);
+ break;
+ case 2:
+ writel(1, &regs->i2s2_rx0);
+ break;
+ case 3:
+ writel(1, &regs->i2s3_rx0);
+ break;
+ case 4:
+ writel(1, &regs->i2s4_rx0);
+ break;
+ default:
+ log_err("Invalid I2S component id: %d\n", i2s_id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int tegra_ahub_apbif_is_full(struct udevice *dev)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+
+ return readl(&priv->apbif_regs->apbdma_live_stat) & priv->full_mask;
+}
+
+/**
+ * tegra_ahub_wait_for_space() - Wait for space in the FIFO
+ *
+ * @return 0 if OK, -ETIMEDOUT if no space was available in time
+ */
+static int tegra_ahub_wait_for_space(struct udevice *dev)
+{
+ int i = 100000;
+ ulong start;
+
+ /* Busy-wait initially, since this should take almost no time */
+ while (i--) {
+ if (!tegra_ahub_apbif_is_full(dev))
+ return 0;
+ }
+
+ /* Failed, so do a slower loop for 100ms */
+ start = get_timer(0);
+ while (tegra_ahub_apbif_is_full(dev)) {
+ if (get_timer(start) > 100)
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int tegra_ahub_apbif_send(struct udevice *dev, int offset,
+ const void *buf, int len)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+ const u32 *data = (const u32 *)buf;
+ ssize_t written = 0;
+
+ if (len % sizeof(*data)) {
+ log_err("Data size (%zd) must be aligned to %zd.\n", len,
+ sizeof(*data));
+ return -EFAULT;
+ }
+ while (written < len) {
+ int ret = tegra_ahub_wait_for_space(dev);
+
+ if (ret)
+ return ret;
+
+ writel(*data++, &priv->apbif_regs->channel0_txfifo);
+ written += sizeof(*data);
+ }
+
+ return written;
+}
+
+static void tegra_ahub_apbif_set_cif(struct udevice *dev, u32 value)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+
+ writel(value, &priv->apbif_regs->channel0_cif_tx0_ctrl);
+}
+
+static void tegra_ahub_apbif_enable_channel0(struct udevice *dev,
+ int fifo_threshold)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+
+ u32 ctrl = TEGRA_AHUB_CHANNEL_CTRL_TX_PACK_EN |
+ TEGRA_AHUB_CHANNEL_CTRL_TX_PACK_16 |
+ TEGRA_AHUB_CHANNEL_CTRL_TX_EN;
+
+ fifo_threshold--; /* fifo_threshold starts from 1 */
+ ctrl |= (fifo_threshold << TEGRA_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT);
+ writel(ctrl, &priv->apbif_regs->channel0_ctrl);
+}
+
+static u32 tegra_ahub_get_cif(bool is_receive, uint channels,
+ uint bits_per_sample, uint fifo_threshold)
+{
+ uint audio_bits = (bits_per_sample >> 2) - 1;
+ u32 val;
+
+ channels--; /* Channels in CIF starts from 1 */
+ fifo_threshold--; /* FIFO threshold starts from 1 */
+ /* Assume input and output are always using same channel / bits */
+ val = channels << TEGRA_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT |
+ channels << TEGRA_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT |
+ audio_bits << TEGRA_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT |
+ audio_bits << TEGRA_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT |
+ fifo_threshold << TEGRA_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT |
+ (is_receive ? TEGRA_AUDIOCIF_DIRECTION_RX <<
+ TEGRA_AUDIOCIF_CTRL_DIRECTION_SHIFT : 0);
+
+ return val;
+}
+
+static int tegra_ahub_enable(struct udevice *dev)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+ struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(priv->i2s);
+ u32 cif_ctrl = 0;
+ int ret;
+
+ /* We use APBIF channel0 as a sender */
+ priv->full_mask = TEGRA_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL;
+ priv->capacity_words = 8;
+
+ /*
+ * FIFO is inactive until (fifo_threshold) of words are sent. For
+ * better performance, we want to set it to half of capacity.
+ */
+ u32 fifo_threshold = priv->capacity_words / 2;
+
+ /*
+ * Setup audio client interface (ACIF): APBIF (channel0) as sender and
+ * I2S as receiver
+ */
+ cif_ctrl = tegra_ahub_get_cif(true, uc_priv->channels,
+ uc_priv->bitspersample, fifo_threshold);
+ tegra_i2s_set_cif_tx_ctrl(priv->i2s, cif_ctrl);
+
+ cif_ctrl = tegra_ahub_get_cif(false, uc_priv->channels,
+ uc_priv->bitspersample, fifo_threshold);
+ tegra_ahub_apbif_set_cif(dev, cif_ctrl);
+ tegra_ahub_apbif_enable_channel0(dev, fifo_threshold);
+
+ ret = tegra_ahub_xbar_enable_i2s(priv->xbar_regs, uc_priv->id);
+ if (ret)
+ return ret;
+ log_debug("ahub: channels=%d, bitspersample=%d, cif_ctrl=%x, fifo_threshold=%d, id=%d\n",
+ uc_priv->channels, uc_priv->bitspersample, cif_ctrl,
+ fifo_threshold, uc_priv->id);
+
+ return 0;
+}
+
+static int tegra_ahub_ioctl(struct udevice *dev, unsigned long request,
+ void *buf)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+
+ if (request != AHUB_MISCOP_SET_I2S)
+ return -ENOSYS;
+
+ priv->i2s = *(struct udevice **)buf;
+ log_debug("i2s set to '%s'\n", priv->i2s->name);
+
+ return tegra_ahub_enable(dev);
+}
+
+static int tegra_ahub_probe(struct udevice *dev)
+{
+ struct tegra_ahub_priv *priv = dev_get_priv(dev);
+ ulong addr;
+
+ addr = dev_read_addr_index(dev, 0);
+ if (addr == FDT_ADDR_T_NONE) {
+ log_debug("Invalid apbif address\n");
+ return -EINVAL;
+ }
+ priv->apbif_regs = (struct apbif_regs *)addr;
+
+ addr = dev_read_addr_index(dev, 1);
+ if (addr == FDT_ADDR_T_NONE) {
+ log_debug("Invalid xbar address\n");
+ return -EINVAL;
+ }
+ priv->xbar_regs = (struct xbar_regs *)addr;
+ log_debug("ahub apbif_regs=%p, xbar_regs=%p\n", priv->apbif_regs,
+ priv->xbar_regs);
+
+ return 0;
+}
+
+static struct misc_ops tegra_ahub_ops = {
+ .write = tegra_ahub_apbif_send,
+ .ioctl = tegra_ahub_ioctl,
+};
+
+static const struct udevice_id tegra_ahub_ids[] = {
+ { .compatible = "nvidia,tegra124-ahub" },
+ { }
+};
+
+U_BOOT_DRIVER(tegra_ahub) = {
+ .name = "tegra_ahub",
+ .id = UCLASS_MISC,
+ .of_match = tegra_ahub_ids,
+ .ops = &tegra_ahub_ops,
+ .probe = tegra_ahub_probe,
+ .priv_auto_alloc_size = sizeof(struct tegra_ahub_priv),
+};
diff --git a/drivers/sound/tegra_i2s.c b/drivers/sound/tegra_i2s.c
new file mode 100644
index 0000000000..8022dbba64
--- /dev/null
+++ b/drivers/sound/tegra_i2s.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+#define LOG_CATEGORY UCLASS_I2S
+#define LOG_DEBUG
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <misc.h>
+#include <sound.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/tegra_i2s.h>
+#include "tegra_i2s_priv.h"
+
+int tegra_i2s_set_cif_tx_ctrl(struct udevice *dev, u32 value)
+{
+ struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+ struct i2s_ctlr *regs = (struct i2s_ctlr *)priv->base_address;
+
+ writel(value, &regs->cif_tx_ctrl);
+
+ return 0;
+}
+
+static void tegra_i2s_transmit_enable(struct i2s_ctlr *regs, int on)
+{
+ clrsetbits_le32(&regs->ctrl, I2S_CTRL_XFER_EN_TX,
+ on ? I2S_CTRL_XFER_EN_TX : 0);
+}
+
+static int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
+{
+ struct i2s_ctlr *regs = (struct i2s_ctlr *)pi2s_tx->base_address;
+ u32 audio_bits = (pi2s_tx->bitspersample >> 2) - 1;
+ u32 ctrl = readl(&regs->ctrl);
+
+ /* Set format to LRCK / Left Low */
+ ctrl &= ~(I2S_CTRL_FRAME_FORMAT_MASK | I2S_CTRL_LRCK_MASK);
+ ctrl |= I2S_CTRL_FRAME_FORMAT_LRCK;
+ ctrl |= I2S_CTRL_LRCK_L_LOW;
+
+ /* Disable all transmission until we are ready to transfer */
+ ctrl &= ~(I2S_CTRL_XFER_EN_TX | I2S_CTRL_XFER_EN_RX);
+
+ /* Serve as master */
+ ctrl |= I2S_CTRL_MASTER_ENABLE;
+
+ /* Configure audio bits size */
+ ctrl &= ~I2S_CTRL_BIT_SIZE_MASK;
+ ctrl |= audio_bits << I2S_CTRL_BIT_SIZE_SHIFT;
+ writel(ctrl, &regs->ctrl);
+
+ /* Timing in LRCK mode: */
+ writel(pi2s_tx->bitspersample, &regs->timing);
+
+ /* I2S mode has [TX/RX]_DATA_OFFSET both set to 1 */
+ writel(((1 << I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
+ (1 << I2S_OFFSET_TX_DATA_OFFSET_SHIFT)), &regs->offset);
+
+ /* FSYNC_WIDTH = 2 clocks wide, TOTAL_SLOTS = 2 slots per fsync */
+ writel((2 - 1) << I2S_CH_CTRL_FSYNC_WIDTH_SHIFT, &regs->ch_ctrl);
+
+ return 0;
+}
+
+static int tegra_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+ struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+ struct i2s_ctlr *regs = (struct i2s_ctlr *)priv->base_address;
+ int ret;
+
+ tegra_i2s_transmit_enable(regs, 1);
+ ret = misc_write(dev_get_parent(dev), 0, data, data_size);
+ tegra_i2s_transmit_enable(regs, 0);
+ if (ret < 0)
+ return ret;
+ else if (ret < data_size)
+ return -EIO;
+
+ return 0;
+}
+
+static int tegra_i2s_probe(struct udevice *dev)
+{
+ struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+ ulong base;
+
+ base = dev_read_addr(dev);
+ if (base == FDT_ADDR_T_NONE) {
+ debug("%s: Missing i2s base\n", __func__);
+ return -EINVAL;
+ }
+ priv->base_address = base;
+ priv->id = 1;
+ priv->audio_pll_clk = 4800000;
+ priv->samplingrate = 48000;
+ priv->bitspersample = 16;
+ priv->channels = 2;
+ priv->rfs = 256;
+ priv->bfs = 32;
+
+ return i2s_tx_init(priv);
+}
+
+static const struct i2s_ops tegra_i2s_ops = {
+ .tx_data = tegra_i2s_tx_data,
+};
+
+static const struct udevice_id tegra_i2s_ids[] = {
+ { .compatible = "nvidia,tegra124-i2s" },
+ { }
+};
+
+U_BOOT_DRIVER(tegra_i2s) = {
+ .name = "tegra_i2s",
+ .id = UCLASS_I2S,
+ .of_match = tegra_i2s_ids,
+ .probe = tegra_i2s_probe,
+ .ops = &tegra_i2s_ops,
+};
diff --git a/drivers/sound/tegra_i2s_priv.h b/drivers/sound/tegra_i2s_priv.h
new file mode 100644
index 0000000000..7cd3fc808c
--- /dev/null
+++ b/drivers/sound/tegra_i2s_priv.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __TEGRA_I2S_PRIV_H
+#define __TEGRA_I2S_PRIV_H
+
+enum {
+ /* Set i2s device (in buf) */
+ AHUB_MISCOP_SET_I2S,
+};
+
+/*
+ * tegra_i2s_set_cif_tx_ctrl() - Set the I2C port to send to
+ *
+ * The CIF is not really part of I2S -- it's for Audio Hub to control
+ * the interface between I2S and Audio Hub. However since it's put in
+ * the I2S registers domain instead of the Audio Hub, we need to export
+ * this as a function.
+ *
+ * @dev: I2S device
+ * @value: Value to write to CIF_TX_CTRL register
+ * @return 0
+ */
+int tegra_i2s_set_cif_tx_ctrl(struct udevice *dev, u32 value);
+
+#endif
diff --git a/drivers/sound/tegra_sound.c b/drivers/sound/tegra_sound.c
new file mode 100644
index 0000000000..7c2ed53f5a
--- /dev/null
+++ b/drivers/sound/tegra_sound.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google, LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_I2S
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <misc.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include "tegra_i2s_priv.h"
+
+static int tegra_sound_setup(struct udevice *dev)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
+ int ret;
+
+ if (uc_priv->setup_done)
+ return -EALREADY;
+ ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
+ i2c_priv->samplingrate,
+ i2c_priv->samplingrate * i2c_priv->rfs,
+ i2c_priv->bitspersample,
+ i2c_priv->channels);
+ if (ret)
+ return ret;
+ uc_priv->setup_done = true;
+
+ return 0;
+}
+
+static int tegra_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int tegra_sound_probe(struct udevice *dev)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct gpio_desc en_gpio;
+ struct udevice *ahub;
+ int ret;
+
+ ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+ ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
+ "nvidia,audio-codec",
+ &uc_priv->codec);
+ if (ret) {
+ log_debug("Failed to probe audio codec\n");
+ return ret;
+ }
+ ret = uclass_get_device_by_phandle(UCLASS_I2S, dev,
+ "nvidia,i2s-controller",
+ &uc_priv->i2s);
+ if (ret) {
+ log_debug("Cannot find i2s: %d\n", ret);
+ return ret;
+ }
+
+ /* Set up the audio hub, telling it the currect i2s to use */
+ ahub = dev_get_parent(uc_priv->i2s);
+ ret = misc_ioctl(ahub, AHUB_MISCOP_SET_I2S, &uc_priv->i2s);
+ if (ret) {
+ log_debug("Cannot set i2c: %d\n", ret);
+ return ret;
+ }
+
+ log_debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+ uc_priv->codec->name, uc_priv->i2s->name);
+
+ return 0;
+}
+
+static const struct sound_ops tegra_sound_ops = {
+ .setup = tegra_sound_setup,
+ .play = tegra_sound_play,
+};
+
+static const struct udevice_id tegra_sound_ids[] = {
+ { .compatible = "nvidia,tegra-audio-max98090-nyan-big" },
+ { }
+};
+
+U_BOOT_DRIVER(tegra_sound) = {
+ .name = "tegra_sound",
+ .id = UCLASS_SOUND,
+ .of_match = tegra_sound_ids,
+ .probe = tegra_sound_probe,
+ .ops = &tegra_sound_ops,
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index fb794adae7..7044da35d6 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -87,6 +87,12 @@ config CADENCE_QSPI
used to access the SPI NOR flash on platforms embedding this
Cadence IP core.
+config CF_SPI
+ bool "ColdFire SPI driver"
+ help
+ Enable the ColdFire SPI driver. This driver can be used on
+ some m68k SoCs.
+
config DESIGNWARE_SPI
bool "Designware SPI driver"
help
@@ -133,7 +139,7 @@ config MPC8XX_SPI
config MT7621_SPI
bool "MediaTek MT7621 SPI driver"
- depends on ARCH_MT7620
+ depends on SOC_MT7628
help
Enable the MT7621 SPI driver. This driver can be used to access
the SPI NOR flash on platforms embedding this Ralink / MediaTek
@@ -173,7 +179,7 @@ config PL022_SPI
config RENESAS_RPC_SPI
bool "Renesas RPC SPI driver"
- depends on RCAR_GEN3
+ depends on RCAR_GEN3 || RZA1
imply SPI_FLASH_BAR
help
Enable the Renesas RPC SPI driver, used to access SPI NOR flash
@@ -222,7 +228,7 @@ config SPI_SUNXI
config STM32_QSPI
bool "STM32F7 QSPI driver"
- depends on STM32F7 || ARCH_STM32MP
+ depends on STM32F4 || STM32F7 || ARCH_STM32MP
help
Enable the STM32F7 Quad-SPI (QSPI) driver. This driver can be
used to access the SPI NOR flash chips on platforms embedding
diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c
index af96c6d21e..e0cc323444 100644
--- a/drivers/spi/atcspi200_spi.c
+++ b/drivers/spi/atcspi200_spi.c
@@ -6,8 +6,8 @@
* Author: Rick Chen (rick@andestech.com)
*/
-#include <clk.h>
#include <common.h>
+#include <clk.h>
#include <malloc.h>
#include <spi.h>
#include <asm/io.h>
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 41c87004d8..e2e54cd277 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -18,8 +18,6 @@
#define CQSPI_INDIRECT_READ 2
#define CQSPI_INDIRECT_WRITE 3
-DECLARE_GLOBAL_DATA_PTR;
-
static int cadence_spi_write_speed(struct udevice *bus, uint hz)
{
struct cadence_spi_platdata *plat = bus->platdata;
@@ -295,36 +293,37 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
{
struct cadence_spi_platdata *plat = bus->platdata;
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(bus);
- int subnode;
+ ofnode subnode;
plat->regbase = (void *)devfdt_get_addr_index(bus, 0);
plat->ahbbase = (void *)devfdt_get_addr_index(bus, 1);
- plat->is_decoded_cs = fdtdec_get_bool(blob, node, "cdns,is-decoded-cs");
- plat->fifo_depth = fdtdec_get_uint(blob, node, "cdns,fifo-depth", 128);
- plat->fifo_width = fdtdec_get_uint(blob, node, "cdns,fifo-width", 4);
- plat->trigger_address = fdtdec_get_uint(blob, node,
- "cdns,trigger-address", 0);
+ plat->is_decoded_cs = dev_read_bool(bus, "cdns,is-decoded-cs");
+ plat->fifo_depth = dev_read_u32_default(bus, "cdns,fifo-depth", 128);
+ plat->fifo_width = dev_read_u32_default(bus, "cdns,fifo-width", 4);
+ plat->trigger_address = dev_read_u32_default(bus,
+ "cdns,trigger-address",
+ 0);
/* All other paramters are embedded in the child node */
- subnode = fdt_first_subnode(blob, node);
- if (subnode < 0) {
+ subnode = dev_read_first_subnode(bus);
+ if (!ofnode_valid(subnode)) {
printf("Error: subnode with SPI flash config missing!\n");
return -ENODEV;
}
/* Use 500 KHz as a suitable default */
- plat->max_hz = fdtdec_get_uint(blob, subnode, "spi-max-frequency",
- 500000);
+ plat->max_hz = ofnode_read_u32_default(subnode, "spi-max-frequency",
+ 500000);
/* Read other parameters from DT */
- plat->page_size = fdtdec_get_uint(blob, subnode, "page-size", 256);
- plat->block_size = fdtdec_get_uint(blob, subnode, "block-size", 16);
- plat->tshsl_ns = fdtdec_get_uint(blob, subnode, "cdns,tshsl-ns", 200);
- plat->tsd2d_ns = fdtdec_get_uint(blob, subnode, "cdns,tsd2d-ns", 255);
- plat->tchsh_ns = fdtdec_get_uint(blob, subnode, "cdns,tchsh-ns", 20);
- plat->tslch_ns = fdtdec_get_uint(blob, subnode, "cdns,tslch-ns", 20);
+ plat->page_size = ofnode_read_u32_default(subnode, "page-size", 256);
+ plat->block_size = ofnode_read_u32_default(subnode, "block-size", 16);
+ plat->tshsl_ns = ofnode_read_u32_default(subnode, "cdns,tshsl-ns",
+ 200);
+ plat->tsd2d_ns = ofnode_read_u32_default(subnode, "cdns,tsd2d-ns",
+ 255);
+ plat->tchsh_ns = ofnode_read_u32_default(subnode, "cdns,tchsh-ns", 20);
+ plat->tslch_ns = ofnode_read_u32_default(subnode, "cdns,tslch-ns", 20);
debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d\n",
__func__, plat->regbase, plat->ahbbase, plat->max_hz,
diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c
index 522631cbbf..923ff6f311 100644
--- a/drivers/spi/cf_spi.c
+++ b/drivers/spi/cf_spi.c
@@ -6,23 +6,28 @@
*
* Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
* TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ *
+ * Support for DM and DT, non-DM code removed.
+ * Copyright (C) 2018 Angelo Dureghello <angelo@sysam.it>
+ *
+ * TODO: fsl_dspi.c should work as a driver for the DSPI module.
*/
#include <common.h>
+#include <dm.h>
+#include <dm/platform_data/spi_coldfire.h>
#include <spi.h>
#include <malloc.h>
-#include <asm/immap.h>
+#include <asm/coldfire/dspi.h>
+#include <asm/io.h>
-struct cf_spi_slave {
- struct spi_slave slave;
+struct coldfire_spi_priv {
+ struct dspi *regs;
uint baudrate;
+ int mode;
int charbit;
};
-extern void cfspi_port_conf(void);
-extern int cfspi_claim_bus(uint bus, uint cs);
-extern void cfspi_release_bus(uint bus, uint cs);
-
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SPI_IDLE_VAL
@@ -33,163 +38,193 @@ DECLARE_GLOBAL_DATA_PTR;
#endif
#endif
-#if defined(CONFIG_CF_DSPI)
-/* DSPI specific mode */
-#define SPI_MODE_MOD 0x00200000
-#define SPI_DBLRATE 0x00100000
-
-static inline struct cf_spi_slave *to_cf_spi_slave(struct spi_slave *slave)
+/*
+ * DSPI specific mode
+ *
+ * bit 31 - 28: Transfer size 3 to 16 bits
+ * 27 - 26: PCS to SCK delay prescaler
+ * 25 - 24: After SCK delay prescaler
+ * 23 - 22: Delay after transfer prescaler
+ * 21 : Allow overwrite for bit 31-22 and bit 20-8
+ * 20 : Double baud rate
+ * 19 - 16: PCS to SCK delay scaler
+ * 15 - 12: After SCK delay scaler
+ * 11 - 8: Delay after transfer scaler
+ * 7 - 0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST
+ */
+#define SPI_MODE_MOD 0x00200000
+#define SPI_MODE_DBLRATE 0x00100000
+
+#define SPI_MODE_XFER_SZ_MASK 0xf0000000
+#define SPI_MODE_DLY_PRE_MASK 0x0fc00000
+#define SPI_MODE_DLY_SCA_MASK 0x000fff00
+
+#define MCF_FRM_SZ_16BIT DSPI_CTAR_TRSZ(0xf)
+#define MCF_DSPI_SPEED_BESTMATCH 0x7FFFFFFF
+#define MCF_DSPI_MAX_CTAR_REGS 8
+
+/* Default values */
+#define MCF_DSPI_DEFAULT_SCK_FREQ 10000000
+#define MCF_DSPI_DEFAULT_MAX_CS 4
+#define MCF_DSPI_DEFAULT_MODE 0
+
+#define MCF_DSPI_DEFAULT_CTAR (DSPI_CTAR_TRSZ(7) | \
+ DSPI_CTAR_PCSSCK_1CLK | \
+ DSPI_CTAR_PASC(0) | \
+ DSPI_CTAR_PDT(0) | \
+ DSPI_CTAR_CSSCK(0) | \
+ DSPI_CTAR_ASC(0) | \
+ DSPI_CTAR_DT(1) | \
+ DSPI_CTAR_BR(6))
+
+#define MCF_CTAR_MODE_MASK (MCF_FRM_SZ_16BIT | \
+ DSPI_CTAR_PCSSCK(3) | \
+ DSPI_CTAR_PASC_7CLK | \
+ DSPI_CTAR_PDT(3) | \
+ DSPI_CTAR_CSSCK(0x0f) | \
+ DSPI_CTAR_ASC(0x0f) | \
+ DSPI_CTAR_DT(0x0f))
+
+#define setup_ctrl(ctrl, cs) ((ctrl & 0xFF000000) | ((1 << cs) << 16))
+
+static inline void cfspi_tx(struct coldfire_spi_priv *cfspi,
+ u32 ctrl, u16 data)
{
- return container_of(slave, struct cf_spi_slave, slave);
+ /*
+ * Need to check fifo level here
+ */
+ while ((readl(&cfspi->regs->sr) & 0x0000F000) >= 0x4000)
+ ;
+
+ writel(ctrl | data, &cfspi->regs->tfr);
}
-static void cfspi_init(void)
+static inline u16 cfspi_rx(struct coldfire_spi_priv *cfspi)
{
- volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
- cfspi_port_conf(); /* port configuration */
-
- dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 |
- DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 |
- DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 |
- DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+ while ((readl(&cfspi->regs->sr) & 0x000000F0) == 0)
+ ;
- /* Default setting in platform configuration */
-#ifdef CONFIG_SYS_DSPI_CTAR0
- dspi->ctar[0] = CONFIG_SYS_DSPI_CTAR0;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR1
- dspi->ctar[1] = CONFIG_SYS_DSPI_CTAR1;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR2
- dspi->ctar[2] = CONFIG_SYS_DSPI_CTAR2;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR3
- dspi->ctar[3] = CONFIG_SYS_DSPI_CTAR3;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR4
- dspi->ctar[4] = CONFIG_SYS_DSPI_CTAR4;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR5
- dspi->ctar[5] = CONFIG_SYS_DSPI_CTAR5;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR6
- dspi->ctar[6] = CONFIG_SYS_DSPI_CTAR6;
-#endif
-#ifdef CONFIG_SYS_DSPI_CTAR7
- dspi->ctar[7] = CONFIG_SYS_DSPI_CTAR7;
-#endif
+ return readw(&cfspi->regs->rfr);
}
-static void cfspi_tx(u32 ctrl, u16 data)
+static int coldfire_spi_claim_bus(struct udevice *dev)
{
- volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+ struct udevice *bus = dev->parent;
+ struct coldfire_spi_priv *cfspi = dev_get_priv(bus);
+ struct dspi *dspi = cfspi->regs;
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
- while ((dspi->sr & 0x0000F000) >= 4) ;
+ if ((in_be32(&dspi->sr) & DSPI_SR_TXRXS) != DSPI_SR_TXRXS)
+ return -1;
- dspi->tfr = (ctrl | data);
+ /* Clear FIFO and resume transfer */
+ clrbits_be32(&dspi->mcr, DSPI_MCR_CTXF | DSPI_MCR_CRXF);
+
+ dspi_chip_select(slave_plat->cs);
+
+ return 0;
}
-static u16 cfspi_rx(void)
+static int coldfire_spi_release_bus(struct udevice *dev)
{
- volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+ struct udevice *bus = dev->parent;
+ struct coldfire_spi_priv *cfspi = dev_get_priv(bus);
+ struct dspi *dspi = cfspi->regs;
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
- while ((dspi->sr & 0x000000F0) == 0) ;
+ /* Clear FIFO */
+ clrbits_be32(&dspi->mcr, DSPI_MCR_CTXF | DSPI_MCR_CRXF);
- return (dspi->rfr & 0xFFFF);
+ dspi_chip_unselect(slave_plat->cs);
+
+ return 0;
}
-static int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
- void *din, ulong flags)
+static int coldfire_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din,
+ unsigned long flags)
{
- struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
+ struct udevice *bus = dev_get_parent(dev);
+ struct coldfire_spi_priv *cfspi = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
u8 *spi_rd = NULL, *spi_wr = NULL;
- static u32 ctrl = 0;
+ static u32 ctrl;
uint len = bitlen >> 3;
- if (cfslave->charbit == 16) {
+ if (cfspi->charbit == 16) {
bitlen >>= 1;
- spi_wr16 = (u16 *) dout;
- spi_rd16 = (u16 *) din;
+ spi_wr16 = (u16 *)dout;
+ spi_rd16 = (u16 *)din;
} else {
- spi_wr = (u8 *) dout;
- spi_rd = (u8 *) din;
+ spi_wr = (u8 *)dout;
+ spi_rd = (u8 *)din;
}
if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
ctrl |= DSPI_TFR_CONT;
- ctrl = (ctrl & 0xFF000000) | ((1 << slave->cs) << 16);
+ ctrl = setup_ctrl(ctrl, slave_plat->cs);
if (len > 1) {
int tmp_len = len - 1;
+
while (tmp_len--) {
- if (dout != NULL) {
- if (cfslave->charbit == 16)
- cfspi_tx(ctrl, *spi_wr16++);
+ if (dout) {
+ if (cfspi->charbit == 16)
+ cfspi_tx(cfspi, ctrl, *spi_wr16++);
else
- cfspi_tx(ctrl, *spi_wr++);
- cfspi_rx();
+ cfspi_tx(cfspi, ctrl, *spi_wr++);
+ cfspi_rx(cfspi);
}
- if (din != NULL) {
- cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
- if (cfslave->charbit == 16)
- *spi_rd16++ = cfspi_rx();
+ if (din) {
+ cfspi_tx(cfspi, ctrl, CONFIG_SPI_IDLE_VAL);
+ if (cfspi->charbit == 16)
+ *spi_rd16++ = cfspi_rx(cfspi);
else
- *spi_rd++ = cfspi_rx();
+ *spi_rd++ = cfspi_rx(cfspi);
}
}
len = 1; /* remaining byte */
}
- if ((flags & SPI_XFER_END) == SPI_XFER_END)
+ if (flags & SPI_XFER_END)
ctrl &= ~DSPI_TFR_CONT;
if (len) {
- if (dout != NULL) {
- if (cfslave->charbit == 16)
- cfspi_tx(ctrl, *spi_wr16);
+ if (dout) {
+ if (cfspi->charbit == 16)
+ cfspi_tx(cfspi, ctrl, *spi_wr16);
else
- cfspi_tx(ctrl, *spi_wr);
- cfspi_rx();
+ cfspi_tx(cfspi, ctrl, *spi_wr);
+ cfspi_rx(cfspi);
}
- if (din != NULL) {
- cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
- if (cfslave->charbit == 16)
- *spi_rd16 = cfspi_rx();
+ if (din) {
+ cfspi_tx(cfspi, ctrl, CONFIG_SPI_IDLE_VAL);
+ if (cfspi->charbit == 16)
+ *spi_rd16 = cfspi_rx(cfspi);
else
- *spi_rd = cfspi_rx();
+ *spi_rd = cfspi_rx(cfspi);
}
} else {
/* dummy read */
- cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
- cfspi_rx();
+ cfspi_tx(cfspi, ctrl, CONFIG_SPI_IDLE_VAL);
+ cfspi_rx(cfspi);
}
return 0;
}
-static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
- uint mode)
+static int coldfire_spi_set_speed(struct udevice *bus, uint max_hz)
{
- /*
- * bit definition for mode:
- * bit 31 - 28: Transfer size 3 to 16 bits
- * 27 - 26: PCS to SCK delay prescaler
- * 25 - 24: After SCK delay prescaler
- * 23 - 22: Delay after transfer prescaler
- * 21 : Allow overwrite for bit 31-22 and bit 20-8
- * 20 : Double baud rate
- * 19 - 16: PCS to SCK delay scaler
- * 15 - 12: After SCK delay scaler
- * 11 - 8: Delay after transfer scaler
- * 7 - 0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST
- */
- volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
+ struct coldfire_spi_priv *cfspi = dev_get_priv(bus);
+ struct dspi *dspi = cfspi->regs;
int prescaler[] = { 2, 3, 5, 7 };
int scaler[] = {
2, 4, 6, 8,
@@ -198,57 +233,41 @@ static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
4096, 8192, 16384, 32768
};
int i, j, pbrcnt, brcnt, diff, tmp, dbr = 0;
- int best_i, best_j, bestmatch = 0x7FFFFFFF, baud_speed;
- u32 bus_setup = 0;
+ int best_i, best_j, bestmatch = MCF_DSPI_SPEED_BESTMATCH, baud_speed;
+ u32 bus_setup;
+
+ cfspi->baudrate = max_hz;
+
+ /* Read current setup */
+ bus_setup = readl(&dspi->ctar[bus->seq]);
tmp = (prescaler[3] * scaler[15]);
/* Maximum and minimum baudrate it can handle */
- if ((cfslave->baudrate > (gd->bus_clk >> 1)) ||
- (cfslave->baudrate < (gd->bus_clk / tmp))) {
+ if ((cfspi->baudrate > (gd->bus_clk >> 1)) ||
+ (cfspi->baudrate < (gd->bus_clk / tmp))) {
printf("Exceed baudrate limitation: Max %d - Min %d\n",
(int)(gd->bus_clk >> 1), (int)(gd->bus_clk / tmp));
- return NULL;
+ return -1;
}
/* Activate Double Baud when it exceed 1/4 the bus clk */
- if ((CONFIG_SYS_DSPI_CTAR0 & DSPI_CTAR_DBR) ||
- (cfslave->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) {
+ if ((bus_setup & DSPI_CTAR_DBR) ||
+ (cfspi->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) {
bus_setup |= DSPI_CTAR_DBR;
dbr = 1;
}
- if (mode & SPI_CPOL)
- bus_setup |= DSPI_CTAR_CPOL;
- if (mode & SPI_CPHA)
- bus_setup |= DSPI_CTAR_CPHA;
- if (mode & SPI_LSB_FIRST)
- bus_setup |= DSPI_CTAR_LSBFE;
-
/* Overwrite default value set in platform configuration file */
- if (mode & SPI_MODE_MOD) {
-
- if ((mode & 0xF0000000) == 0)
- bus_setup |=
- dspi->ctar[cfslave->slave.bus] & 0x78000000;
- else
- bus_setup |= ((mode & 0xF0000000) >> 1);
-
+ if (cfspi->mode & SPI_MODE_MOD) {
/*
* Check to see if it is enabled by default in platform
* config, or manual setting passed by mode parameter
*/
- if (mode & SPI_DBLRATE) {
+ if (cfspi->mode & SPI_MODE_DBLRATE) {
bus_setup |= DSPI_CTAR_DBR;
dbr = 1;
}
- bus_setup |= (mode & 0x0FC00000) >> 4; /* PSCSCK, PASC, PDT */
- bus_setup |= (mode & 0x000FFF00) >> 4; /* CSSCK, ASC, DT */
- } else
- bus_setup |= (dspi->ctar[cfslave->slave.bus] & 0x78FCFFF0);
-
- cfslave->charbit =
- ((dspi->ctar[cfslave->slave.bus] & 0x78000000) ==
- 0x78000000) ? 16 : 8;
+ }
pbrcnt = sizeof(prescaler) / sizeof(int);
brcnt = sizeof(scaler) / sizeof(int);
@@ -259,10 +278,10 @@ static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
for (j = 0; j < brcnt; j++) {
tmp = (baud_speed / scaler[j]) * (1 + dbr);
- if (tmp > cfslave->baudrate)
- diff = tmp - cfslave->baudrate;
+ if (tmp > cfspi->baudrate)
+ diff = tmp - cfspi->baudrate;
else
- diff = cfslave->baudrate - tmp;
+ diff = cfspi->baudrate - tmp;
if (diff < bestmatch) {
bestmatch = diff;
@@ -271,65 +290,174 @@ static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
}
}
}
+
+ bus_setup &= ~(DSPI_CTAR_PBR(0x03) | DSPI_CTAR_BR(0x0f));
bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
- dspi->ctar[cfslave->slave.bus] = bus_setup;
+ writel(bus_setup, &dspi->ctar[bus->seq]);
- return &cfslave->slave;
+ return 0;
}
-#endif /* CONFIG_CF_DSPI */
-#ifdef CONFIG_CMD_SPI
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static int coldfire_spi_set_mode(struct udevice *bus, uint mode)
{
- if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
- return 1;
- else
- return 0;
-}
+ struct coldfire_spi_priv *cfspi = dev_get_priv(bus);
+ struct dspi *dspi = cfspi->regs;
+ u32 bus_setup = 0;
-void spi_init(void)
-{
- cfspi_init();
-}
+ cfspi->mode = mode;
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct cf_spi_slave *cfslave;
+ if (cfspi->mode & SPI_CPOL)
+ bus_setup |= DSPI_CTAR_CPOL;
+ if (cfspi->mode & SPI_CPHA)
+ bus_setup |= DSPI_CTAR_CPHA;
+ if (cfspi->mode & SPI_LSB_FIRST)
+ bus_setup |= DSPI_CTAR_LSBFE;
- if (!spi_cs_is_valid(bus, cs))
- return NULL;
+ /* Overwrite default value set in platform configuration file */
+ if (cfspi->mode & SPI_MODE_MOD) {
+ if ((cfspi->mode & SPI_MODE_XFER_SZ_MASK) == 0)
+ bus_setup |=
+ readl(&dspi->ctar[bus->seq]) & MCF_FRM_SZ_16BIT;
+ else
+ bus_setup |=
+ ((cfspi->mode & SPI_MODE_XFER_SZ_MASK) >> 1);
- cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs);
- if (!cfslave)
- return NULL;
+ /* PSCSCK, PASC, PDT */
+ bus_setup |= (cfspi->mode & SPI_MODE_DLY_PRE_MASK) >> 4;
+ /* CSSCK, ASC, DT */
+ bus_setup |= (cfspi->mode & SPI_MODE_DLY_SCA_MASK) >> 4;
+ } else {
+ bus_setup |=
+ (readl(&dspi->ctar[bus->seq]) & MCF_CTAR_MODE_MASK);
+ }
+
+ cfspi->charbit =
+ ((readl(&dspi->ctar[bus->seq]) & MCF_FRM_SZ_16BIT) ==
+ MCF_FRM_SZ_16BIT) ? 16 : 8;
- cfslave->baudrate = max_hz;
+ setbits_be32(&dspi->ctar[bus->seq], bus_setup);
- /* specific setup */
- return cfspi_setup_slave(cfslave, mode);
+ return 0;
}
-void spi_free_slave(struct spi_slave *slave)
+static int coldfire_spi_probe(struct udevice *bus)
{
- struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
+ struct coldfire_spi_platdata *plat = dev_get_platdata(bus);
+ struct coldfire_spi_priv *cfspi = dev_get_priv(bus);
+ struct dspi *dspi = cfspi->regs;
+ int i;
- free(cfslave);
-}
+ cfspi->regs = (struct dspi *)plat->regs_addr;
-int spi_claim_bus(struct spi_slave *slave)
-{
- return cfspi_claim_bus(slave->bus, slave->cs);
+ cfspi->baudrate = plat->speed_hz;
+ cfspi->mode = plat->mode;
+
+ for (i = 0; i < MCF_DSPI_MAX_CTAR_REGS; i++) {
+ unsigned int ctar = 0;
+
+ if (plat->ctar[i][0] == 0)
+ break;
+
+ ctar = DSPI_CTAR_TRSZ(plat->ctar[i][0]) |
+ DSPI_CTAR_PCSSCK(plat->ctar[i][1]) |
+ DSPI_CTAR_PASC(plat->ctar[i][2]) |
+ DSPI_CTAR_PDT(plat->ctar[i][3]) |
+ DSPI_CTAR_CSSCK(plat->ctar[i][4]) |
+ DSPI_CTAR_ASC(plat->ctar[i][5]) |
+ DSPI_CTAR_DT(plat->ctar[i][6]) |
+ DSPI_CTAR_BR(plat->ctar[i][7]);
+
+ writel(ctar, &cfspi->regs->ctar[i]);
+ }
+
+ /* Default CTARs */
+ for (i = 0; i < MCF_DSPI_MAX_CTAR_REGS; i++)
+ writel(MCF_DSPI_DEFAULT_CTAR, &dspi->ctar[i]);
+
+ dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 |
+ DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 |
+ DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 |
+ DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+
+ return 0;
}
-void spi_release_bus(struct spi_slave *slave)
+void spi_init(void)
{
- cfspi_release_bus(slave->bus, slave->cs);
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int coldfire_dspi_ofdata_to_platdata(struct udevice *bus)
{
- return cfspi_xfer(slave, bitlen, dout, din, flags);
+ fdt_addr_t addr;
+ struct coldfire_spi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = dev_of_offset(bus);
+ int *ctar, len;
+
+ addr = devfdt_get_addr(bus);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENOMEM;
+
+ plat->regs_addr = addr;
+
+ plat->num_cs = fdtdec_get_int(blob, node, "num-cs",
+ MCF_DSPI_DEFAULT_MAX_CS);
+
+ plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
+ MCF_DSPI_DEFAULT_SCK_FREQ);
+
+ plat->mode = fdtdec_get_int(blob, node, "spi-mode",
+ MCF_DSPI_DEFAULT_MODE);
+
+ memset(plat->ctar, 0, sizeof(plat->ctar));
+
+ ctar = (int *)fdt_getprop(blob, node, "ctar-params", &len);
+
+ if (ctar && len) {
+ int i, q, ctar_regs;
+
+ ctar_regs = len / sizeof(unsigned int) / MAX_CTAR_FIELDS;
+
+ if (ctar_regs > MAX_CTAR_REGS)
+ ctar_regs = MAX_CTAR_REGS;
+
+ for (i = 0; i < ctar_regs; i++) {
+ for (q = 0; q < MAX_CTAR_FIELDS; q++)
+ plat->ctar[i][q] = *ctar++;
+ }
+ }
+
+ debug("DSPI: regs=%pa, max-frequency=%d, num-cs=%d, mode=%d\n",
+ (void *)plat->regs_addr,
+ plat->speed_hz, plat->num_cs, plat->mode);
+
+ return 0;
}
-#endif /* CONFIG_CMD_SPI */
+
+static const struct udevice_id coldfire_spi_ids[] = {
+ { .compatible = "fsl,mcf-dspi" },
+ { }
+};
+#endif
+
+static const struct dm_spi_ops coldfire_spi_ops = {
+ .claim_bus = coldfire_spi_claim_bus,
+ .release_bus = coldfire_spi_release_bus,
+ .xfer = coldfire_spi_xfer,
+ .set_speed = coldfire_spi_set_speed,
+ .set_mode = coldfire_spi_set_mode,
+};
+
+U_BOOT_DRIVER(coldfire_spi) = {
+ .name = "spi_coldfire",
+ .id = UCLASS_SPI,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .of_match = coldfire_spi_ids,
+ .ofdata_to_platdata = coldfire_dspi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct coldfire_spi_platdata),
+#endif
+ .probe = coldfire_spi_probe,
+ .ops = &coldfire_spi_ops,
+ .priv_auto_alloc_size = sizeof(struct coldfire_spi_priv),
+};
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index dadb6fa18b..7d58cfae55 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -22,8 +22,6 @@
#include <linux/iopoll.h>
#include <asm/io.h>
-DECLARE_GLOBAL_DATA_PTR;
-
/* Register offsets */
#define DW_SPI_CTRL0 0x00
#define DW_SPI_CTRL1 0x04
@@ -155,14 +153,12 @@ static int request_gpio_cs(struct udevice *bus)
static int dw_spi_ofdata_to_platdata(struct udevice *bus)
{
struct dw_spi_platdata *plat = bus->platdata;
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(bus);
plat->regs = (struct dw_spi *)devfdt_get_addr(bus);
/* Use 500KHz as a suitable default */
- plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
- 500000);
+ plat->frequency = dev_read_u32_default(bus, "spi-max-frequency",
+ 500000);
debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs,
plat->frequency);
diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c
index bec9095ff4..bb2e7748fe 100644
--- a/drivers/spi/renesas_rpc_spi.c
+++ b/drivers/spi/renesas_rpc_spi.c
@@ -409,27 +409,30 @@ static int rpc_spi_probe(struct udevice *dev)
priv->regs = plat->regs;
priv->extr = plat->extr;
-
+#if CONFIG_IS_ENABLED(CLK)
clk_enable(&priv->clk);
-
+#endif
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);
+#if CONFIG_IS_ENABLED(CLK)
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
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;
}
+#endif
plat->freq = dev_read_u32_default(bus, "spi-max-freq", 50000000);
@@ -448,6 +451,7 @@ static const struct udevice_id rpc_spi_ids[] = {
{ .compatible = "renesas,rpc-r8a77965" },
{ .compatible = "renesas,rpc-r8a77970" },
{ .compatible = "renesas,rpc-r8a77995" },
+ { .compatible = "renesas,rpc-r7s72100" },
{ }
};
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index 14437c0a9a..a68553b75b 100644
--- a/drivers/spi/rk_spi.c
+++ b/drivers/spi/rk_spi.c
@@ -2,6 +2,8 @@
/*
* spi driver for rockchip
*
+ * (C) 2019 Theobroma Systems Design und Consulting GmbH
+ *
* (C) Copyright 2015 Google, Inc
*
* (C) Copyright 2008-2013 Rockchip Electronics
@@ -16,14 +18,19 @@
#include <spi.h>
#include <linux/errno.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/periph.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/periph.h>
#include <dm/pinctrl.h>
#include "rk_spi.h"
/* Change to 1 to output registers at the start of each transaction */
#define DEBUG_RK_SPI 0
+struct rockchip_spi_params {
+ /* RXFIFO overruns and TXFIFO underruns stop the master clock */
+ bool master_manages_fifo;
+};
+
struct rockchip_spi_platdata {
#if CONFIG_IS_ENABLED(OF_PLATDATA)
struct dtd_rockchip_rk3288_spi of_plat;
@@ -40,11 +47,8 @@ struct rockchip_spi_priv {
unsigned int max_freq;
unsigned int mode;
ulong last_transaction_us; /* Time of last transaction end */
- u8 bits_per_word; /* max 16 bits per word */
- u8 n_bytes;
unsigned int speed_hz;
unsigned int last_speed_hz;
- unsigned int tmode;
uint input_rate;
};
@@ -130,8 +134,13 @@ static void spi_cs_activate(struct udevice *dev, uint cs)
if (plat->deactivate_delay_us && priv->last_transaction_us) {
ulong delay_us; /* The delay completed so far */
delay_us = timer_get_us() - priv->last_transaction_us;
- if (delay_us < plat->deactivate_delay_us)
- udelay(plat->deactivate_delay_us - delay_us);
+ if (delay_us < plat->deactivate_delay_us) {
+ ulong additional_delay_us =
+ plat->deactivate_delay_us - delay_us;
+ debug("%s: delaying by %ld us\n",
+ __func__, additional_delay_us);
+ udelay(additional_delay_us);
+ }
}
debug("activate cs%u\n", cs);
@@ -263,8 +272,6 @@ static int rockchip_spi_probe(struct udevice *bus)
}
priv->input_rate = ret;
debug("%s: rate = %u\n", __func__, priv->input_rate);
- priv->bits_per_word = 8;
- priv->tmode = TMOD_TR; /* Tx & Rx */
return 0;
}
@@ -274,28 +281,10 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
struct udevice *bus = dev->parent;
struct rockchip_spi_priv *priv = dev_get_priv(bus);
struct rockchip_spi *regs = priv->regs;
- u8 spi_dfs, spi_tf;
uint ctrlr0;
/* Disable the SPI hardware */
- rkspi_enable_chip(regs, 0);
-
- switch (priv->bits_per_word) {
- case 8:
- priv->n_bytes = 1;
- spi_dfs = DFS_8BIT;
- spi_tf = HALF_WORD_OFF;
- break;
- case 16:
- priv->n_bytes = 2;
- spi_dfs = DFS_16BIT;
- spi_tf = HALF_WORD_ON;
- break;
- default:
- debug("%s: unsupported bits: %dbits\n", __func__,
- priv->bits_per_word);
- return -EPROTONOSUPPORT;
- }
+ rkspi_enable_chip(regs, false);
if (priv->speed_hz != priv->last_speed_hz)
rkspi_set_clk(priv, priv->speed_hz);
@@ -304,7 +293,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
ctrlr0 = OMOD_MASTER << OMOD_SHIFT;
/* Data Frame Size */
- ctrlr0 |= spi_dfs << DFS_SHIFT;
+ ctrlr0 |= DFS_8BIT << DFS_SHIFT;
/* set SPI mode 0..3 */
if (priv->mode & SPI_CPOL)
@@ -325,7 +314,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
ctrlr0 |= FBM_MSB << FBM_SHIFT;
/* Byte and Halfword Transform */
- ctrlr0 |= spi_tf << HALF_WORD_TX_SHIFT;
+ ctrlr0 |= HALF_WORD_OFF << HALF_WORD_TX_SHIFT;
/* Rxd Sample Delay */
ctrlr0 |= 0 << RXDSD_SHIFT;
@@ -334,7 +323,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
ctrlr0 |= FRF_SPI << FRF_SHIFT;
/* Tx and Rx mode */
- ctrlr0 |= (priv->tmode & TMOD_MASK) << TMOD_SHIFT;
+ ctrlr0 |= TMOD_TR << TMOD_SHIFT;
writel(ctrlr0, &regs->ctrlr0);
@@ -351,6 +340,83 @@ static int rockchip_spi_release_bus(struct udevice *dev)
return 0;
}
+static inline int rockchip_spi_16bit_reader(struct udevice *dev,
+ u8 **din, int *len)
+{
+ struct udevice *bus = dev->parent;
+ const struct rockchip_spi_params * const data =
+ (void *)dev_get_driver_data(bus);
+ struct rockchip_spi_priv *priv = dev_get_priv(bus);
+ struct rockchip_spi *regs = priv->regs;
+ const u32 saved_ctrlr0 = readl(&regs->ctrlr0);
+#if defined(DEBUG)
+ u32 statistics_rxlevels[33] = { };
+#endif
+ u32 frames = *len / 2;
+ u8 *in = (u8 *)(*din);
+ u32 max_chunk_size = SPI_FIFO_DEPTH;
+
+ if (!frames)
+ return 0;
+
+ /*
+ * If we know that the hardware will manage RXFIFO overruns
+ * (i.e. stop the SPI clock until there's space in the FIFO),
+ * we the allow largest possible chunk size that can be
+ * represented in CTRLR1.
+ */
+ if (data && data->master_manages_fifo)
+ max_chunk_size = 0x10000;
+
+ // rockchip_spi_configure(dev, mode, size)
+ rkspi_enable_chip(regs, false);
+ clrsetbits_le32(&regs->ctrlr0,
+ TMOD_MASK << TMOD_SHIFT,
+ TMOD_RO << TMOD_SHIFT);
+ /* 16bit data frame size */
+ clrsetbits_le32(&regs->ctrlr0, DFS_MASK, DFS_16BIT);
+
+ /* Update caller's context */
+ const u32 bytes_to_process = 2 * frames;
+ *din += bytes_to_process;
+ *len -= bytes_to_process;
+
+ /* Process our frames */
+ while (frames) {
+ u32 chunk_size = min(frames, max_chunk_size);
+
+ frames -= chunk_size;
+
+ writew(chunk_size - 1, &regs->ctrlr1);
+ rkspi_enable_chip(regs, true);
+
+ do {
+ u32 rx_level = readw(&regs->rxflr);
+#if defined(DEBUG)
+ statistics_rxlevels[rx_level]++;
+#endif
+ chunk_size -= rx_level;
+ while (rx_level--) {
+ u16 val = readw(regs->rxdr);
+ *in++ = val & 0xff;
+ *in++ = val >> 8;
+ }
+ } while (chunk_size);
+
+ rkspi_enable_chip(regs, false);
+ }
+
+#if defined(DEBUG)
+ debug("%s: observed rx_level during processing:\n", __func__);
+ for (int i = 0; i <= 32; ++i)
+ if (statistics_rxlevels[i])
+ debug("\t%2d: %d\n", i, statistics_rxlevels[i]);
+#endif
+ /* Restore the original transfer setup and return error-free. */
+ writel(saved_ctrlr0, &regs->ctrlr0);
+ return 0;
+}
+
static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
@@ -362,7 +428,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
const u8 *out = dout;
u8 *in = din;
int toread, towrite;
- int ret;
+ int ret = 0;
debug("%s: dout=%p, din=%p, len=%x, flags=%lx\n", __func__, dout, din,
len, flags);
@@ -373,8 +439,18 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(dev, slave_plat->cs);
+ /*
+ * To ensure fast loading of firmware images (e.g. full U-Boot
+ * stage, ATF, Linux kernel) from SPI flash, we optimise the
+ * case of read-only transfers by using the full 16bits of each
+ * FIFO element.
+ */
+ if (!out)
+ ret = rockchip_spi_16bit_reader(dev, &in, &len);
+
+ /* This is the original 8bit reader/writer code */
while (len > 0) {
- int todo = min(len, 0xffff);
+ int todo = min(len, 0x10000);
rkspi_enable_chip(regs, false);
writel(todo - 1, &regs->ctrlr1);
@@ -397,9 +473,18 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
toread--;
}
}
- ret = rkspi_wait_till_not_busy(regs);
- if (ret)
- break;
+
+ /*
+ * In case that there's a transmit-component, we need to wait
+ * until the control goes idle before we can disable the SPI
+ * control logic (as this will implictly flush the FIFOs).
+ */
+ if (out) {
+ ret = rkspi_wait_till_not_busy(regs);
+ if (ret)
+ break;
+ }
+
len -= todo;
}
@@ -446,10 +531,16 @@ static const struct dm_spi_ops rockchip_spi_ops = {
*/
};
+const struct rockchip_spi_params rk3399_spi_params = {
+ .master_manages_fifo = true,
+};
+
static const struct udevice_id rockchip_spi_ids[] = {
{ .compatible = "rockchip,rk3288-spi" },
- { .compatible = "rockchip,rk3368-spi" },
- { .compatible = "rockchip,rk3399-spi" },
+ { .compatible = "rockchip,rk3368-spi",
+ .data = (ulong)&rk3399_spi_params },
+ { .compatible = "rockchip,rk3399-spi",
+ .data = (ulong)&rk3399_spi_params },
{ }
};
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 8ce3e2e207..30aed2c4c1 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -13,11 +13,29 @@ config SYSRESET
to effect a reset. The uclass will try all available drivers when
reset_walk() is called.
+config SPL_SYSRESET
+ bool "Enable support for system reset drivers in SPL mode"
+ depends on SYSRESET && SPL_DM
+ help
+ Enable system reset drivers which can be used to reset the CPU or
+ board. Each driver can provide a reset method which will be called
+ to effect a reset. The uclass will try all available drivers when
+ reset_walk() is called.
+
+config TPL_SYSRESET
+ bool "Enable support for system reset drivers in TPL mode"
+ depends on SYSRESET && TPL_DM
+ help
+ Enable system reset drivers which can be used to reset the CPU or
+ board. Each driver can provide a reset method which will be called
+ to effect a reset. The uclass will try all available drivers when
+ reset_walk() is called.
+
if SYSRESET
config SYSRESET_GPIO
bool "Enable support for GPIO reset driver"
- select GPIO
+ select DM_GPIO
help
Reset support via GPIO pin connected reset logic. This is used for
example on Microblaze where reset logic can be controlled via GPIO
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index b3728ac17f..8e1c845dfe 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -2,7 +2,7 @@
#
# (C) Copyright 2016 Cadence Design Systems Inc.
-obj-$(CONFIG_SYSRESET) += sysreset-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET) += sysreset-uclass.o
obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
diff --git a/drivers/sysreset/sysreset_rockchip.c b/drivers/sysreset/sysreset_rockchip.c
index 93d7cfe463..0fc6b683f2 100644
--- a/drivers/sysreset/sysreset_rockchip.c
+++ b/drivers/sysreset/sysreset_rockchip.c
@@ -8,9 +8,9 @@
#include <errno.h>
#include <sysreset.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3328.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3328.h>
+#include <asm/arch-rockchip/hardware.h>
#include <linux/err.h>
int rockchip_sysreset_request(struct udevice *dev, enum sysreset_t type)
diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c
index 009f376602..072f7948ef 100644
--- a/drivers/sysreset/sysreset_x86.c
+++ b/drivers/sysreset/sysreset_x86.c
@@ -7,15 +7,75 @@
#include <common.h>
#include <dm.h>
+#include <efi_loader.h>
+#include <pch.h>
#include <sysreset.h>
+#include <asm/acpi_s3.h>
#include <asm/io.h>
#include <asm/processor.h>
-#include <efi_loader.h>
-static __efi_runtime int x86_sysreset_request(struct udevice *dev,
- enum sysreset_t type)
+struct x86_sysreset_platdata {
+ struct udevice *pch;
+};
+
+/*
+ * Power down the machine by using the power management sleep control
+ * of the chipset. This will currently only work on Intel chipsets.
+ * However, adapting it to new chipsets is fairly simple. You will
+ * have to find the IO address of the power management register block
+ * in your southbridge, and look up the appropriate SLP_TYP_S5 value
+ * from your southbridge's data sheet.
+ *
+ * This function never returns.
+ */
+int pch_sysreset_power_off(struct udevice *dev)
+{
+ struct x86_sysreset_platdata *plat = dev_get_platdata(dev);
+ struct pch_pmbase_info pm;
+ u32 reg32;
+ int ret;
+
+ if (!plat->pch)
+ return -ENOENT;
+ ret = pch_ioctl(plat->pch, PCH_REQ_PMBASE_INFO, &pm, sizeof(pm));
+ if (ret)
+ return ret;
+
+ /*
+ * Mask interrupts or system might stay in a coma, not executing code
+ * anymore, but not powered off either.
+ */
+ asm("cli");
+
+ /*
+ * Avoid any GPI waking the system from S5* or the system might stay in
+ * a coma
+ */
+ outl(0x00000000, pm.base + pm.gpio0_en_ofs);
+
+ /* Clear Power Button Status */
+ outw(PWRBTN_STS, pm.base + pm.pm1_sts_ofs);
+
+ /* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 111 -> S5, soft_off */
+ reg32 = inl(pm.base + pm.pm1_cnt_ofs);
+
+ /* Set Sleeping Type to S5 (poweroff) */
+ reg32 &= ~(SLP_EN | SLP_TYP);
+ reg32 |= SLP_TYP_S5;
+ outl(reg32, pm.base + pm.pm1_cnt_ofs);
+
+ /* Now set the Sleep Enable bit */
+ reg32 |= SLP_EN;
+ outl(reg32, pm.base + pm.pm1_cnt_ofs);
+
+ for (;;)
+ asm("hlt");
+}
+
+static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
int value;
+ int ret;
switch (type) {
case SYSRESET_WARM:
@@ -24,6 +84,11 @@ static __efi_runtime int x86_sysreset_request(struct udevice *dev,
case SYSRESET_COLD:
value = SYS_RST | RST_CPU | FULL_RST;
break;
+ case SYSRESET_POWER_OFF:
+ ret = pch_sysreset_power_off(dev);
+ if (ret)
+ return ret;
+ return -EINPROGRESS;
default:
return -ENOSYS;
}
@@ -33,17 +98,29 @@ static __efi_runtime int x86_sysreset_request(struct udevice *dev,
return -EINPROGRESS;
}
+static int x86_sysreset_get_last(struct udevice *dev)
+{
+ return SYSRESET_POWER;
+}
+
#ifdef CONFIG_EFI_LOADER
void __efi_runtime EFIAPI efi_reset_system(
enum efi_reset_type reset_type,
efi_status_t reset_status,
unsigned long data_size, void *reset_data)
{
+ int value;
+
+ /*
+ * inline this code since we are not caused in the context of a
+ * udevice and passing NULL to x86_sysreset_request() is too horrible.
+ */
if (reset_type == EFI_RESET_COLD ||
reset_type == EFI_RESET_PLATFORM_SPECIFIC)
- x86_sysreset_request(NULL, SYSRESET_COLD);
- else if (reset_type == EFI_RESET_WARM)
- x86_sysreset_request(NULL, SYSRESET_WARM);
+ value = SYS_RST | RST_CPU | FULL_RST;
+ else /* assume EFI_RESET_WARM since we cannot return an error */
+ value = SYS_RST | RST_CPU;
+ outb(value, IO_PORT_RESET);
/* TODO EFI_RESET_SHUTDOWN */
@@ -51,6 +128,15 @@ void __efi_runtime EFIAPI efi_reset_system(
}
#endif
+static int x86_sysreset_probe(struct udevice *dev)
+{
+ struct x86_sysreset_platdata *plat = dev_get_platdata(dev);
+
+ /* Locate the PCH if there is one. It isn't essential */
+ uclass_first_device(UCLASS_PCH, &plat->pch);
+
+ return 0;
+}
static const struct udevice_id x86_sysreset_ids[] = {
{ .compatible = "x86,reset" },
@@ -59,6 +145,7 @@ static const struct udevice_id x86_sysreset_ids[] = {
static struct sysreset_ops x86_sysreset_ops = {
.request = x86_sysreset_request,
+ .get_last = x86_sysreset_get_last,
};
U_BOOT_DRIVER(x86_sysreset) = {
@@ -66,4 +153,6 @@ U_BOOT_DRIVER(x86_sysreset) = {
.id = UCLASS_SYSRESET,
.of_match = x86_sysreset_ids,
.ops = &x86_sysreset_ops,
+ .probe = x86_sysreset_probe,
+ .platdata_auto_alloc_size = sizeof(struct x86_sysreset_platdata),
};
diff --git a/drivers/tee/sandbox.c b/drivers/tee/sandbox.c
index a136bc9609..2f3355c7b7 100644
--- a/drivers/tee/sandbox.c
+++ b/drivers/tee/sandbox.c
@@ -178,7 +178,7 @@ static u32 ta_avb_invoke_func(struct udevice *dev, u32 func, uint num_params,
if (!ep)
return TEE_ERROR_ITEM_NOT_FOUND;
- value_sz = strlen(ep->data);
+ value_sz = strlen(ep->data) + 1;
memcpy(value, ep->data, value_sz);
return TEE_SUCCESS;
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index df37a798bd..5f4bc6edb6 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -110,6 +110,13 @@ config MPC83XX_TIMER
Select this to enable support for the timer found on
devices based on the MPC83xx family of SoCs.
+config RENESAS_OSTM_TIMER
+ bool "Renesas RZ/A1 R7S72100 OSTM Timer"
+ depends on TIMER
+ help
+ Enables support for the Renesas OSTM Timer driver.
+ This timer is present on Renesas RZ/A1 R7S72100 SoCs.
+
config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index d0bf218b11..fa35bea6c5 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
+obj-$(CONFIG_RENESAS_OSTM_TIMER) += ostm_timer.o
obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
diff --git a/drivers/timer/dw-apb-timer.c b/drivers/timer/dw-apb-timer.c
index cb48801af1..86312b8dc7 100644
--- a/drivers/timer/dw-apb-timer.c
+++ b/drivers/timer/dw-apb-timer.c
@@ -17,8 +17,6 @@
#define DW_APB_CURR_VAL 0x4
#define DW_APB_CTRL 0x8
-DECLARE_GLOBAL_DATA_PTR;
-
struct dw_apb_timer_priv {
fdt_addr_t regs;
};
diff --git a/drivers/timer/ostm_timer.c b/drivers/timer/ostm_timer.c
new file mode 100644
index 0000000000..f0e25093ca
--- /dev/null
+++ b/drivers/timer/ostm_timer.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas RZ/A1 R7S72100 OSTM Timer driver
+ *
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <clk.h>
+#include <timer.h>
+
+#define OSTM_CMP 0x00
+#define OSTM_CNT 0x04
+#define OSTM_TE 0x10
+#define OSTM_TS 0x14
+#define OSTM_TT 0x18
+#define OSTM_CTL 0x20
+#define OSTM_CTL_D BIT(1)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct ostm_priv {
+ fdt_addr_t regs;
+};
+
+static int ostm_get_count(struct udevice *dev, u64 *count)
+{
+ struct ostm_priv *priv = dev_get_priv(dev);
+
+ *count = timer_conv_64(readl(priv->regs + OSTM_CNT));
+
+ return 0;
+}
+
+static int ostm_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ostm_priv *priv = dev_get_priv(dev);
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ uc_priv->clock_rate = clk_get_rate(&clk);
+
+ clk_free(&clk);
+#else
+ uc_priv->clock_rate = CONFIG_SYS_CLK_FREQ / 2;
+#endif
+
+ readb(priv->regs + OSTM_CTL);
+ writeb(OSTM_CTL_D, priv->regs + OSTM_CTL);
+
+ setbits_8(priv->regs + OSTM_TT, BIT(0));
+ writel(0xffffffff, priv->regs + OSTM_CMP);
+ setbits_8(priv->regs + OSTM_TS, BIT(0));
+
+ return 0;
+}
+
+static int ostm_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ostm_priv *priv = dev_get_priv(dev);
+
+ priv->regs = dev_read_addr(dev);
+
+ return 0;
+}
+
+static const struct timer_ops ostm_ops = {
+ .get_count = ostm_get_count,
+};
+
+static const struct udevice_id ostm_ids[] = {
+ { .compatible = "renesas,ostm" },
+ {}
+};
+
+U_BOOT_DRIVER(ostm_timer) = {
+ .name = "ostm-timer",
+ .id = UCLASS_TIMER,
+ .ops = &ostm_ops,
+ .probe = ostm_probe,
+ .of_match = ostm_ids,
+ .ofdata_to_platdata = ostm_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct ostm_priv),
+};
diff --git a/drivers/timer/rockchip_timer.c b/drivers/timer/rockchip_timer.c
index 69019740b0..54956e557a 100644
--- a/drivers/timer/rockchip_timer.c
+++ b/drivers/timer/rockchip_timer.c
@@ -7,7 +7,7 @@
#include <dm.h>
#include <dm/ofnode.h>
#include <mapmem.h>
-#include <asm/arch/timer.h>
+#include <asm/arch-rockchip/timer.h>
#include <dt-structs.h>
#include <timer.h>
#include <asm/io.h>
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index bbd8105c06..25e1a38aee 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -44,6 +44,14 @@ config USB_DWC3_GENERIC
Select this for Xilinx ZynqMP and similar Platforms.
This wrapper supports Host and Peripheral operation modes.
+config USB_DWC3_MESON_G12A
+ bool "Amlogic Meson G12A USB wrapper"
+ depends on DM_USB && USB_DWC3 && ARCH_MESON
+ imply PHY
+ help
+ Select this for Amlogic Meson G12A Platforms.
+ This wrapper supports Host and Peripheral operation modes.
+
config USB_DWC3_UNIPHIER
bool "DesignWare USB3 Host Support on UniPhier Platforms"
depends on ARCH_UNIPHIER && USB_XHCI_DWC3
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 60b5515a67..0b652a6f36 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -7,6 +7,7 @@ dwc3-y := core.o
obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o
obj-$(CONFIG_USB_DWC3_GENERIC) += dwc3-generic.o
obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o
obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
new file mode 100644
index 0000000000..832bcd70ff
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Amlogic G12A DWC3 Glue layer
+ *
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <asm-generic/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dwc3-uboot.h>
+#include <generic-phy.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <regmap.h>
+#include <usb.h>
+#include "core.h"
+#include "gadget.h"
+#include <reset.h>
+#include <clk.h>
+#include <power/regulator.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+/* USB2 Ports Control Registers */
+
+#define U2P_REG_SIZE 0x20
+
+#define U2P_R0 0x0
+ #define U2P_R0_HOST_DEVICE BIT(0)
+ #define U2P_R0_POWER_OK BIT(1)
+ #define U2P_R0_HAST_MODE BIT(2)
+ #define U2P_R0_POWER_ON_RESET BIT(3)
+ #define U2P_R0_ID_PULLUP BIT(4)
+ #define U2P_R0_DRV_VBUS BIT(5)
+
+#define U2P_R1 0x4
+ #define U2P_R1_PHY_READY BIT(0)
+ #define U2P_R1_ID_DIG BIT(1)
+ #define U2P_R1_OTG_SESSION_VALID BIT(2)
+ #define U2P_R1_VBUS_VALID BIT(3)
+
+/* USB Glue Control Registers */
+
+#define USB_R0 0x80
+ #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 0x84
+ #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(4, 2)
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7)
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 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 0x88
+ #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 0x8c
+ #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_R4 0x90
+ #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 0x94
+ #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)
+
+enum {
+ USB2_HOST_PHY = 0,
+ USB2_OTG_PHY,
+ USB3_HOST_PHY,
+ PHY_COUNT,
+};
+
+static const char *phy_names[PHY_COUNT] = {
+ "usb2-phy0", "usb2-phy1", "usb3-phy0",
+};
+
+struct dwc3_meson_g12a {
+ struct udevice *dev;
+ struct regmap *regmap;
+ struct clk clk;
+ struct reset_ctl reset;
+ struct phy phys[PHY_COUNT];
+ enum usb_dr_mode otg_mode;
+ enum usb_dr_mode otg_phy_mode;
+ unsigned int usb2_ports;
+ unsigned int usb3_ports;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ struct udevice *vbus_supply;
+#endif
+};
+
+#define U2P_REG_SIZE 0x20
+#define USB_REG_OFFSET 0x80
+
+static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
+ int i, enum usb_dr_mode mode)
+{
+ switch (mode) {
+ case USB_DR_MODE_HOST:
+ case USB_DR_MODE_OTG:
+ case USB_DR_MODE_UNKNOWN:
+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+ U2P_R0_HOST_DEVICE,
+ U2P_R0_HOST_DEVICE);
+ break;
+
+ case USB_DR_MODE_PERIPHERAL:
+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+ U2P_R0_HOST_DEVICE, 0);
+ break;
+ }
+}
+
+static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
+{
+ int i;
+
+ if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
+ priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
+ else
+ priv->otg_phy_mode = USB_DR_MODE_HOST;
+
+ for (i = 0 ; i < USB3_HOST_PHY ; ++i) {
+ if (!priv->phys[i].dev)
+ continue;
+
+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+ U2P_R0_POWER_ON_RESET,
+ U2P_R0_POWER_ON_RESET);
+
+ if (i == USB2_OTG_PHY) {
+ regmap_update_bits(priv->regmap,
+ U2P_R0 + (U2P_REG_SIZE * i),
+ U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
+ U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
+
+ dwc3_meson_g12a_usb2_set_mode(priv, i,
+ priv->otg_phy_mode);
+ } else
+ dwc3_meson_g12a_usb2_set_mode(priv, i,
+ USB_DR_MODE_HOST);
+
+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+ U2P_R0_POWER_ON_RESET, 0);
+ }
+
+ return 0;
+}
+
+static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
+{
+ regmap_update_bits(priv->regmap, USB_R3,
+ USB_R3_P30_SSC_RANGE_MASK |
+ USB_R3_P30_REF_SSP_EN,
+ USB_R3_P30_SSC_ENABLE |
+ FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
+ USB_R3_P30_REF_SSP_EN);
+ udelay(2);
+
+ regmap_update_bits(priv->regmap, USB_R2,
+ USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
+ FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
+
+ regmap_update_bits(priv->regmap, USB_R2,
+ USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
+ FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
+
+ udelay(2);
+
+ regmap_update_bits(priv->regmap, USB_R1,
+ USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
+ USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
+
+ regmap_update_bits(priv->regmap, USB_R1,
+ USB_R1_P30_PCS_TX_SWING_FULL_MASK,
+ FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
+}
+
+static void dwc3_meson_g12a_usb_init_mode(struct dwc3_meson_g12a *priv)
+{
+ if (priv->otg_phy_mode == USB_DR_MODE_PERIPHERAL) {
+ regmap_update_bits(priv->regmap, USB_R0,
+ USB_R0_U2D_ACT, USB_R0_U2D_ACT);
+ regmap_update_bits(priv->regmap, USB_R0,
+ USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
+ regmap_update_bits(priv->regmap, USB_R4,
+ USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
+ } else {
+ regmap_update_bits(priv->regmap, USB_R0,
+ USB_R0_U2D_ACT, 0);
+ regmap_update_bits(priv->regmap, USB_R4,
+ USB_R4_P21_SLEEP_M0, 0);
+ }
+}
+
+static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
+{
+ int ret;
+
+ ret = dwc3_meson_g12a_usb2_init(priv);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regmap, USB_R1,
+ USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
+ FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
+
+ regmap_update_bits(priv->regmap, USB_R5,
+ USB_R5_ID_DIG_EN_0,
+ USB_R5_ID_DIG_EN_0);
+ regmap_update_bits(priv->regmap, USB_R5,
+ USB_R5_ID_DIG_EN_1,
+ USB_R5_ID_DIG_EN_1);
+ regmap_update_bits(priv->regmap, USB_R5,
+ USB_R5_ID_DIG_TH_MASK,
+ FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
+
+ /* If we have an actual SuperSpeed port, initialize it */
+ if (priv->usb3_ports)
+ dwc3_meson_g12a_usb3_init(priv);
+
+ dwc3_meson_g12a_usb_init_mode(priv);
+
+ return 0;
+}
+
+int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
+{
+ struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
+
+ if (!priv)
+ return -EINVAL;
+
+ if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
+ return -EINVAL;
+
+ if (!priv->phys[USB2_OTG_PHY].dev)
+ return -EINVAL;
+
+ if (mode == priv->otg_mode)
+ return 0;
+
+ if (mode == USB_DR_MODE_HOST)
+ debug("%s: switching to Host Mode\n", __func__);
+ else
+ debug("%s: switching to Device Mode\n", __func__);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ if (priv->vbus_supply) {
+ int ret = regulator_set_enable(priv->vbus_supply,
+ (mode == USB_DR_MODE_PERIPHERAL));
+ if (ret)
+ return ret;
+ }
+#endif
+ priv->otg_phy_mode = mode;
+
+ dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode);
+
+ dwc3_meson_g12a_usb_init_mode(priv);
+
+ return 0;
+}
+
+static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
+{
+ int i, ret;
+
+ for (i = 0 ; i < PHY_COUNT ; ++i) {
+ ret = generic_phy_get_by_name(priv->dev, phy_names[i],
+ &priv->phys[i]);
+ if (ret == -ENOENT)
+ continue;
+
+ if (ret)
+ return ret;
+
+ if (i == USB3_HOST_PHY)
+ priv->usb3_ports++;
+ else
+ priv->usb2_ports++;
+ }
+
+ debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
+ debug("%s: usb3 ports: %d\n", __func__, priv->usb3_ports);
+
+ return 0;
+}
+
+static int dwc3_meson_g12a_reset_init(struct dwc3_meson_g12a *priv)
+{
+ int ret;
+
+ ret = reset_get_by_index(priv->dev, 0, &priv->reset);
+ if (ret)
+ return ret;
+
+ ret = reset_assert(&priv->reset);
+ udelay(1);
+ ret |= reset_deassert(&priv->reset);
+ if (ret) {
+ reset_free(&priv->reset);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv)
+{
+ int ret;
+
+ ret = clk_get_by_index(priv->dev, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_enable(&priv->clk);
+ if (ret) {
+ clk_free(&priv->clk);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static int dwc3_meson_g12a_probe(struct udevice *dev)
+{
+ struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
+ int ret, i;
+
+ priv->dev = dev;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+ if (ret)
+ return ret;
+
+ ret = dwc3_meson_g12a_clk_init(priv);
+ if (ret)
+ return ret;
+
+ ret = dwc3_meson_g12a_reset_init(priv);
+ if (ret)
+ return ret;
+
+ ret = dwc3_meson_g12a_get_phys(priv);
+ if (ret)
+ return ret;
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ ret = device_get_supply_regulator(dev, "vbus-supply",
+ &priv->vbus_supply);
+ if (ret && ret != -ENOENT) {
+ pr_err("Failed to get PHY regulator\n");
+ return ret;
+ }
+
+ if (priv->vbus_supply) {
+ ret = regulator_set_enable(priv->vbus_supply, true);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ priv->otg_mode = usb_get_dr_mode(dev_of_offset(dev));
+
+ ret = dwc3_meson_g12a_usb_init(priv);
+ if (ret)
+ return ret;
+
+ for (i = 0 ; i < PHY_COUNT ; ++i) {
+ if (!priv->phys[i].dev)
+ continue;
+
+ ret = generic_phy_init(&priv->phys[i]);
+ if (ret)
+ goto err_phy_init;
+ }
+
+ return 0;
+
+err_phy_init:
+ for (i = 0 ; i < PHY_COUNT ; ++i) {
+ if (!priv->phys[i].dev)
+ continue;
+
+ generic_phy_exit(&priv->phys[i]);
+ }
+
+ return ret;
+}
+
+static int dwc3_meson_g12a_remove(struct udevice *dev)
+{
+ struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
+ int i;
+
+ reset_release_all(&priv->reset, 1);
+
+ clk_release_all(&priv->clk, 1);
+
+ for (i = 0 ; i < PHY_COUNT ; ++i) {
+ if (!priv->phys[i].dev)
+ continue;
+
+ generic_phy_exit(&priv->phys[i]);
+ }
+
+ return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id dwc3_meson_g12a_ids[] = {
+ { .compatible = "amlogic,meson-g12a-usb-ctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(dwc3_generic_wrapper) = {
+ .name = "dwc3-meson-g12a",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = dwc3_meson_g12a_ids,
+ .probe = dwc3_meson_g12a_probe,
+ .remove = dwc3_meson_g12a_remove,
+ .platdata_auto_alloc_size = sizeof(struct dwc3_meson_g12a),
+
+};
diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c
index e81eb164b0..f3d24772cd 100644
--- a/drivers/usb/gadget/f_rockusb.c
+++ b/drivers/usb/gadget/f_rockusb.c
@@ -15,7 +15,7 @@
#include <linux/compiler.h>
#include <version.h>
#include <g_dnl.h>
-#include <asm/arch/f_rockusb.h>
+#include <asm/arch-rockchip/f_rockusb.h>
static inline struct f_rockusb *func_to_rockusb(struct usb_function *f)
{
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 0fbc115801..b1188bcbf5 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -132,6 +132,13 @@ config USB_EHCI_MARVELL
---help---
Enables support for the on-chip EHCI controller on MVEBU SoCs.
+config USB_EHCI_MX5
+ bool "Support for i.MX5 on-chip EHCI USB controller"
+ depends on ARCH_MX5
+ default n
+ help
+ Enables support for the on-chip EHCI controller on i.MX5 SoCs.
+
config USB_EHCI_MX6
bool "Support for i.MX6 on-chip EHCI USB controller"
depends on ARCH_MX6
@@ -239,6 +246,11 @@ config USB_OHCI_GENERIC
---help---
Enables support for generic OHCI controller.
+config USB_OHCI_DA8XX
+ bool "Support for da850 OHCI USB controller"
+ help
+ Enable support for the da850 USB controller.
+
endif # USB_OHCI_HCD
config USB_UHCI_HCD
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 23e7e7125f..b8f8e7a794 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -75,8 +75,12 @@ static int ehci_fsl_init_after_reset(struct ehci_ctrl *ctrl)
struct usb_ehci *ehci = NULL;
struct ehci_fsl_priv *priv = container_of(ctrl, struct ehci_fsl_priv,
ehci);
-
+#ifdef CONFIG_PPC
+ ehci = (struct usb_ehci *)lower_32_bits(priv->hcd_base);
+#else
ehci = (struct usb_ehci *)priv->hcd_base;
+#endif
+
if (ehci_fsl_init(priv, ehci, priv->ehci.hccr, priv->ehci.hcor) < 0)
return -ENXIO;
@@ -103,7 +107,11 @@ static int ehci_fsl_probe(struct udevice *dev)
debug("Can't get the EHCI register base address\n");
return -ENXIO;
}
+#ifdef CONFIG_PPC
+ ehci = (struct usb_ehci *)lower_32_bits(priv->hcd_base);
+#else
ehci = (struct usb_ehci *)priv->hcd_base;
+#endif
hccr = (struct ehci_hccr *)(&ehci->caplength);
hcor = (struct ehci_hcor *)
((void *)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c
index 60f1470860..0b32728c57 100644
--- a/drivers/usb/host/ehci-mx5.c
+++ b/drivers/usb/host/ehci-mx5.c
@@ -12,6 +12,8 @@
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
+#include <dm.h>
+#include <power/regulator.h>
#include "ehci.h"
@@ -223,6 +225,7 @@ __weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
mdelay(50);
}
+#if !CONFIG_IS_ENABLED(DM_USB)
static const struct ehci_ops mx5_ehci_ops = {
.powerup_fixup = mx5_ehci_powerup_fixup,
};
@@ -267,3 +270,103 @@ int ehci_hcd_stop(int index)
{
return 0;
}
+#else /* CONFIG_IS_ENABLED(DM_USB) */
+struct ehci_mx5_priv_data {
+ struct ehci_ctrl ctrl;
+ struct usb_ehci *ehci;
+ struct udevice *vbus_supply;
+ enum usb_init_type init_type;
+ int portnr;
+};
+
+static const struct ehci_ops mx5_ehci_ops = {
+ .powerup_fixup = mx5_ehci_powerup_fixup,
+};
+
+static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+ struct usb_platdata *plat = dev_get_platdata(dev);
+ const char *mode;
+
+ mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL);
+ if (mode) {
+ if (strcmp(mode, "peripheral") == 0)
+ plat->init_type = USB_INIT_DEVICE;
+ else if (strcmp(mode, "host") == 0)
+ plat->init_type = USB_INIT_HOST;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+ struct usb_platdata *plat = dev_get_platdata(dev);
+ struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev);
+ struct ehci_mx5_priv_data *priv = dev_get_priv(dev);
+ enum usb_init_type type = plat->init_type;
+ struct ehci_hccr *hccr;
+ struct ehci_hcor *hcor;
+ int ret;
+
+ set_usboh3_clk();
+ enable_usboh3_clk(true);
+ set_usb_phy_clk();
+ enable_usb_phy1_clk(true);
+ enable_usb_phy2_clk(true);
+ mdelay(1);
+
+ priv->ehci = ehci;
+ priv->portnr = dev->seq;
+ priv->init_type = type;
+
+ ret = device_get_supply_regulator(dev, "vbus-supply",
+ &priv->vbus_supply);
+ if (ret)
+ debug("%s: No vbus supply\n", dev->name);
+
+ if (!ret && priv->vbus_supply) {
+ ret = regulator_set_enable(priv->vbus_supply,
+ (type == USB_INIT_DEVICE) ?
+ false : true);
+ if (ret) {
+ puts("Error enabling VBUS supply\n");
+ return ret;
+ }
+ }
+
+ hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+ hcor = (struct ehci_hcor *)((uint32_t)hccr +
+ HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
+ setbits_le32(&ehci->usbmode, CM_HOST);
+
+ __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+ setbits_le32(&ehci->portsc, USB_EN);
+
+ mxc_set_usbcontrol(priv->portnr, CONFIG_MXC_USB_FLAGS);
+ mdelay(10);
+
+ return ehci_register(dev, hccr, hcor, &mx5_ehci_ops, 0,
+ priv->init_type);
+}
+
+static const struct udevice_id mx5_usb_ids[] = {
+ { .compatible = "fsl,imx53-usb" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_mx5) = {
+ .name = "ehci_mx5",
+ .id = UCLASS_USB,
+ .of_match = mx5_usb_ids,
+ .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+ .probe = ehci_usb_probe,
+ .remove = ehci_deregister,
+ .ops = &ehci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct ehci_mx5_priv_data),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* !CONFIG_IS_ENABLED(DM_USB) */
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 47ad3f34d5..233df57b4d 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -4,9 +4,54 @@
*/
#include <common.h>
-
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include "ohci.h"
#include <asm/arch/da8xx-usb.h>
+struct da8xx_ohci {
+ ohci_t ohci;
+ struct clk *clocks; /* clock list */
+ struct phy phy;
+ int clock_count; /* number of clock in clock list */
+};
+
+static int usb_phy_on(void)
+{
+ unsigned long timeout;
+
+ clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
+ (CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN |
+ CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE |
+ CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX),
+ (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN |
+ CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ |
+ CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM));
+
+ /* wait until the usb phy pll locks */
+ timeout = get_timer(0);
+ while (get_timer(timeout) < 10) {
+ if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
+ return 1;
+ }
+
+ /* USB phy was not turned on */
+ return 0;
+}
+
+static void usb_phy_off(void)
+{
+ /* Power down the on-chip PHY. */
+ clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
+ CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM,
+ CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
+ CFGCHIP2_RESET);
+}
+
int usb_cpu_init(void)
{
/* enable psc for usb2.0 */
@@ -37,3 +82,95 @@ int usb_cpu_init_fail(void)
{
return usb_cpu_stop();
}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ohci_da8xx_probe(struct udevice *dev)
+{
+ struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
+ struct da8xx_ohci *priv = dev_get_priv(dev);
+ int i, err, ret, clock_nb;
+
+ err = 0;
+ priv->clock_count = 0;
+ clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
+
+ if (clock_nb < 0)
+ return clock_nb;
+
+ if (clock_nb > 0) {
+ priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
+ GFP_KERNEL);
+ if (!priv->clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < clock_nb; i++) {
+ err = clk_get_by_index(dev, i, &priv->clocks[i]);
+ if (err < 0)
+ break;
+
+ err = clk_enable(&priv->clocks[i]);
+ if (err) {
+ dev_err(dev, "failed to enable clock %d\n", i);
+ clk_free(&priv->clocks[i]);
+ goto clk_err;
+ }
+ priv->clock_count++;
+ }
+ }
+
+ err = usb_cpu_init();
+
+ if (err)
+ goto clk_err;
+
+ err = ohci_register(dev, regs);
+ if (err)
+ goto phy_err;
+
+ return 0;
+
+phy_err:
+ ret = usb_cpu_stop();
+ if (ret)
+ dev_err(dev, "failed to shutdown usb phy\n");
+
+clk_err:
+ ret = clk_release_all(priv->clocks, priv->clock_count);
+ if (ret)
+ dev_err(dev, "failed to disable all clocks\n");
+
+ return err;
+}
+
+static int ohci_da8xx_remove(struct udevice *dev)
+{
+ struct da8xx_ohci *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = ohci_deregister(dev);
+ if (ret)
+ return ret;
+
+ ret = usb_cpu_stop();
+ if (ret)
+ return ret;
+
+ return clk_release_all(priv->clocks, priv->clock_count);
+}
+
+static const struct udevice_id da8xx_ohci_ids[] = {
+ { .compatible = "ti,da830-ohci" },
+ { }
+};
+
+U_BOOT_DRIVER(ohci_generic) = {
+ .name = "ohci-da8xx",
+ .id = UCLASS_USB,
+ .of_match = da8xx_ohci_ids,
+ .probe = ohci_da8xx_probe,
+ .remove = ohci_da8xx_remove,
+ .ops = &ohci_usb_ops,
+ .priv_auto_alloc_size = sizeof(struct da8xx_ohci),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
+};
+#endif
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 3b6f889f7b..2b0df88f49 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1545,10 +1545,8 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
return -1;
}
-#if 0
mdelay(10);
/* ohci_dump_status(ohci); */
-#endif
timeout = USB_TIMEOUT_MS(pipe);
diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c
index 2ee0f23b7e..1f2805270a 100644
--- a/drivers/usb/musb/musb_hcd.c
+++ b/drivers/usb/musb/musb_hcd.c
@@ -327,9 +327,7 @@ static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
csr = readw(&musbr->txcsr);
csr |= MUSB_CSR0_TXPKTRDY;
-#if !defined(CONFIG_SOC_DM365)
csr |= MUSB_CSR0_H_DIS_PING;
-#endif
writew(csr, &musbr->txcsr);
result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
if (result < 0)
@@ -352,9 +350,7 @@ static int ctrlreq_out_status_phase(struct usb_device *dev)
/* Set the StatusPkt bit */
csr = readw(&musbr->txcsr);
csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT);
-#if !defined(CONFIG_SOC_DM365)
csr |= MUSB_CSR0_H_DIS_PING;
-#endif
writew(csr, &musbr->txcsr);
/* Wait until TXPKTRDY bit is cleared */
@@ -372,9 +368,7 @@ static int ctrlreq_in_status_phase(struct usb_device *dev)
/* Set the StatusPkt bit and ReqPkt bit */
csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
-#if !defined(CONFIG_SOC_DM365)
csr |= MUSB_CSR0_H_DIS_PING;
-#endif
writew(csr, &musbr->txcsr);
result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
diff --git a/drivers/video/imx/mxc_ipuv3_fb.c b/drivers/video/imx/mxc_ipuv3_fb.c
index 3e38d4bdcc..29ecac40a2 100644
--- a/drivers/video/imx/mxc_ipuv3_fb.c
+++ b/drivers/video/imx/mxc_ipuv3_fb.c
@@ -678,13 +678,14 @@ static int ipuv3_video_bind(struct udevice *dev)
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
- (1 << LCD_MAX_LOG2_BPP) / 8;
+ (1 << VIDEO_BPP32) / 8;
return 0;
}
static const struct udevice_id ipuv3_video_ids[] = {
{ .compatible = "fsl,imx6q-ipu" },
+ { .compatible = "fsl,imx53-ipu" },
{ }
};
diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c
index eb3692c387..315d3adf27 100644
--- a/drivers/video/rockchip/rk3288_hdmi.c
+++ b/drivers/video/rockchip/rk3288_hdmi.c
@@ -13,9 +13,9 @@
#include <syscon.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/grf_rk3288.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
#include <power/regulator.h>
#include "rk_hdmi.h"
diff --git a/drivers/video/rockchip/rk3288_mipi.c b/drivers/video/rockchip/rk3288_mipi.c
index d268b46514..7c4a4cc53b 100644
--- a/drivers/video/rockchip/rk3288_mipi.c
+++ b/drivers/video/rockchip/rk3288_mipi.c
@@ -14,14 +14,14 @@
#include "rk_mipi.h"
#include <syscon.h>
#include <asm/gpio.h>
-#include <asm/hardware.h>
#include <asm/io.h>
#include <dm/uclass-internal.h>
#include <linux/kernel.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3288.h>
-#include <asm/arch/grf_rk3288.h>
-#include <asm/arch/rockchip_mipi_dsi.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3288.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/rockchip_mipi_dsi.h>
#define MHz 1000000
diff --git a/drivers/video/rockchip/rk3288_vop.c b/drivers/video/rockchip/rk3288_vop.c
index 7e953a628c..0f91dab1f2 100644
--- a/drivers/video/rockchip/rk3288_vop.c
+++ b/drivers/video/rockchip/rk3288_vop.c
@@ -11,10 +11,10 @@
#include <regmap.h>
#include <syscon.h>
#include <video.h>
-#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/grf_rk3288.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rockchip/hardware.h>
#include "rk_vop.h"
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/video/rockchip/rk3399_hdmi.c b/drivers/video/rockchip/rk3399_hdmi.c
index b75efe6fc3..a62be98327 100644
--- a/drivers/video/rockchip/rk3399_hdmi.c
+++ b/drivers/video/rockchip/rk3399_hdmi.c
@@ -13,9 +13,9 @@
#include <syscon.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/grf_rk3399.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
#include <power/regulator.h>
#include "rk_hdmi.h"
diff --git a/drivers/video/rockchip/rk3399_mipi.c b/drivers/video/rockchip/rk3399_mipi.c
index bb9007bf36..a93b73400b 100644
--- a/drivers/video/rockchip/rk3399_mipi.c
+++ b/drivers/video/rockchip/rk3399_mipi.c
@@ -14,14 +14,14 @@
#include "rk_mipi.h"
#include <syscon.h>
#include <asm/gpio.h>
-#include <asm/hardware.h>
#include <asm/io.h>
#include <dm/uclass-internal.h>
#include <linux/kernel.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3399.h>
-#include <asm/arch/grf_rk3399.h>
-#include <asm/arch/rockchip_mipi_dsi.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3399.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/rockchip_mipi_dsi.h>
/* Select mipi dsi source, big or little vop */
static int rk_mipi_dsi_source_select(struct udevice *dev)
diff --git a/drivers/video/rockchip/rk3399_vop.c b/drivers/video/rockchip/rk3399_vop.c
index 7a02221ae0..81c122d7a9 100644
--- a/drivers/video/rockchip/rk3399_vop.c
+++ b/drivers/video/rockchip/rk3399_vop.c
@@ -10,7 +10,7 @@
#include <dm.h>
#include <regmap.h>
#include <video.h>
-#include <asm/hardware.h>
+#include <asm/arch-rockchip/hardware.h>
#include <asm/io.h>
#include "rk_vop.h"
diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c
index e074107632..4330725a25 100644
--- a/drivers/video/rockchip/rk_edp.c
+++ b/drivers/video/rockchip/rk_edp.c
@@ -14,9 +14,9 @@
#include <syscon.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/edp_rk3288.h>
-#include <asm/arch/grf_rk3288.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/edp_rk3288.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
#include <dt-bindings/clock/rk3288-cru.h>
#define MAX_CR_LOOP 5
diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c
index 13d07ee304..51931ceefa 100644
--- a/drivers/video/rockchip/rk_hdmi.c
+++ b/drivers/video/rockchip/rk_hdmi.c
@@ -14,10 +14,9 @@
#include <regmap.h>
#include <syscon.h>
#include <asm/gpio.h>
-#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
#include "rk_hdmi.h"
#include "rk_vop.h" /* for rk_vop_probe_regulators */
diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c
index f0a528c0d6..cf5c0439b1 100644
--- a/drivers/video/rockchip/rk_lvds.c
+++ b/drivers/video/rockchip/rk_lvds.c
@@ -12,9 +12,9 @@
#include <syscon.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/lvds_rk3288.h>
-#include <asm/arch/grf_rk3288.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/lvds_rk3288.h>
+#include <asm/arch-rockchip/grf_rk3288.h>
#include <dt-bindings/clock/rk3288-cru.h>
#include <dt-bindings/video/rk3288.h>
diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c
index 4f1a0f3a5f..bcd039b7bc 100644
--- a/drivers/video/rockchip/rk_mipi.c
+++ b/drivers/video/rockchip/rk_mipi.c
@@ -14,14 +14,13 @@
#include "rk_mipi.h"
#include <syscon.h>
#include <asm/gpio.h>
-#include <asm/hardware.h>
#include <asm/io.h>
#include <dm/uclass-internal.h>
#include <linux/kernel.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3399.h>
-#include <asm/arch/grf_rk3399.h>
-#include <asm/arch/rockchip_mipi_dsi.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3399.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/rockchip_mipi_dsi.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index faf4f24db0..b56c3f336c 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -13,11 +13,10 @@
#include <syscon.h>
#include <video.h>
#include <asm/gpio.h>
-#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/edp_rk3288.h>
-#include <asm/arch/vop_rk3288.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/edp_rk3288.h>
+#include <asm/arch-rockchip/vop_rk3288.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
#include <power/regulator.h>
diff --git a/drivers/video/rockchip/rk_vop.h b/drivers/video/rockchip/rk_vop.h
index 828974d394..8fa2f38939 100644
--- a/drivers/video/rockchip/rk_vop.h
+++ b/drivers/video/rockchip/rk_vop.h
@@ -6,7 +6,7 @@
#ifndef __RK_VOP_H__
#define __RK_VOP_H__
-#include <asm/arch/vop_rk3288.h>
+#include <asm/arch-rockchip/vop_rk3288.h>
struct rk_vop_priv {
void *grf;
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index c31303b56e..af88588904 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -529,6 +529,20 @@ int vidconsole_put_char(struct udevice *dev, char ch)
return 0;
}
+int vidconsole_put_string(struct udevice *dev, const char *str)
+{
+ const char *s;
+ int ret;
+
+ for (s = str; *s; s++) {
+ ret = vidconsole_put_char(dev, *s);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
{
struct udevice *dev = sdev->priv;
@@ -541,8 +555,7 @@ static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
{
struct udevice *dev = sdev->priv;
- while (*s)
- vidconsole_put_char(dev, *s++);
+ vidconsole_put_string(dev, s);
video_sync(dev->parent, false);
}
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index 14aac88d6d..b19bfb4f2f 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -149,7 +149,7 @@ void video_sync(struct udevice *vid, bool force)
* architectures do not actually implement it. Is there a way to find
* out whether it exists? For now, ARM is safe.
*/
-#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
+#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
struct video_priv *priv = dev_get_uclass_priv(vid);
if (priv->flush_dcache) {
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3bce0aa0b8..b01dbc446d 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -55,7 +55,7 @@ config WDT
help
Enable driver model for watchdog timer. At the moment the API
is very simple and only supports four operations:
- start, restart, stop and reset (expire immediately).
+ start, stop, reset and expire_now (expire immediately).
What exactly happens when the timer expires is up to a particular
device/driver.
@@ -103,6 +103,13 @@ config WDT_ORION
Select this to enable Orion watchdog timer, which can be found on some
Marvell Armada chips.
+config WDT_SP805
+ bool "SP805 watchdog timer support"
+ depends on WDT
+ help
+ Select this to enable SP805 watchdog timer, which can be found on some
+ nxp layerscape chips.
+
config WDT_CDNS
bool "Cadence watchdog timer support"
depends on WDT
@@ -143,7 +150,7 @@ config WDT_AT91
config WDT_MT7621
bool "MediaTek MT7621 watchdog timer support"
- depends on WDT && ARCH_MT7620
+ depends on WDT && SOC_MT7628
help
Select this to enable Ralink / Mediatek watchdog timer,
which can be found on some MediaTek chips.
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 40b2f4bc66..6f20e73810 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
obj-$(CONFIG_WDT_MTK) += mtk_wdt.o
+obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
diff --git a/drivers/watchdog/bcm6345_wdt.c b/drivers/watchdog/bcm6345_wdt.c
index 44f5662038..9f14e7d777 100644
--- a/drivers/watchdog/bcm6345_wdt.c
+++ b/drivers/watchdog/bcm6345_wdt.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <dm.h>
#include <wdt.h>
+#include <clk.h>
#include <asm/io.h>
/* WDT Value register */
@@ -26,6 +27,7 @@
struct bcm6345_wdt_priv {
void __iomem *regs;
+ unsigned long clk_rate;
};
static int bcm6345_wdt_reset(struct udevice *dev)
@@ -41,16 +43,17 @@ static int bcm6345_wdt_reset(struct udevice *dev)
static int bcm6345_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
{
struct bcm6345_wdt_priv *priv = dev_get_priv(dev);
+ u32 val = priv->clk_rate / 1000 * timeout;
- if (timeout < WDT_VAL_MIN) {
+ if (val < WDT_VAL_MIN) {
debug("watchdog won't fire with less than 2 ticks\n");
- timeout = WDT_VAL_MIN;
- } else if (timeout > WDT_VAL_MAX) {
+ val = WDT_VAL_MIN;
+ } else if (val > WDT_VAL_MAX) {
debug("maximum watchdog timeout exceeded\n");
- timeout = WDT_VAL_MAX;
+ val = WDT_VAL_MAX;
}
- writel(timeout, priv->regs + WDT_VAL_REG);
+ writel(val, priv->regs + WDT_VAL_REG);
return bcm6345_wdt_reset(dev);
}
@@ -85,11 +88,19 @@ static const struct udevice_id bcm6345_wdt_ids[] = {
static int bcm6345_wdt_probe(struct udevice *dev)
{
struct bcm6345_wdt_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ int ret;
priv->regs = dev_remap_addr(dev);
if (!priv->regs)
return -EINVAL;
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (!ret)
+ priv->clk_rate = clk_get_rate(&clk);
+ else
+ return -EINVAL;
+
bcm6345_wdt_stop(dev);
return 0;
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
new file mode 100644
index 0000000000..966128216f
--- /dev/null
+++ b/drivers/watchdog/sp805_wdt.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Watchdog driver for SP805 on some Layerscape SoC
+ *
+ * Copyright 2019 NXP
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm/device.h>
+#include <dm/fdtaddr.h>
+#include <dm/read.h>
+#include <linux/bitops.h>
+#include <watchdog.h>
+#include <wdt.h>
+
+#define WDTLOAD 0x000
+#define WDTCONTROL 0x008
+#define WDTINTCLR 0x00C
+#define WDTLOCK 0xC00
+
+#define TIME_OUT_MIN_MSECS 1
+#define TIME_OUT_MAX_MSECS 120000
+#define SYS_FSL_WDT_CLK_DIV 16
+#define INT_ENABLE BIT(0)
+#define RESET_ENABLE BIT(1)
+#define DISABLE 0
+#define UNLOCK 0x1ACCE551
+#define LOCK 0x00000001
+#define INT_MASK BIT(0)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sp805_wdt_priv {
+ void __iomem *reg;
+};
+
+static int sp805_wdt_reset(struct udevice *dev)
+{
+ struct sp805_wdt_priv *priv = dev_get_priv(dev);
+
+ writel(UNLOCK, priv->reg + WDTLOCK);
+ writel(INT_MASK, priv->reg + WDTINTCLR);
+ writel(LOCK, priv->reg + WDTLOCK);
+ readl(priv->reg + WDTLOCK);
+
+ return 0;
+}
+
+static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ u32 load_value;
+ u32 load_time;
+ struct sp805_wdt_priv *priv = dev_get_priv(dev);
+
+ load_time = (u32)timeout;
+ if (timeout < TIME_OUT_MIN_MSECS)
+ load_time = TIME_OUT_MIN_MSECS;
+ else if (timeout > TIME_OUT_MAX_MSECS)
+ load_time = TIME_OUT_MAX_MSECS;
+ /* sp805 runs counter with given value twice, so when the max timeout is
+ * set 120s, the gd->bus_clk is less than 1145MHz, the load_value will
+ * not overflow.
+ */
+ load_value = (gd->bus_clk) /
+ (2 * 1000 * SYS_FSL_WDT_CLK_DIV) * load_time;
+
+ writel(UNLOCK, priv->reg + WDTLOCK);
+ writel(load_value, priv->reg + WDTLOAD);
+ writel(INT_MASK, priv->reg + WDTINTCLR);
+ writel(INT_ENABLE | RESET_ENABLE, priv->reg + WDTCONTROL);
+ writel(LOCK, priv->reg + WDTLOCK);
+ readl(priv->reg + WDTLOCK);
+
+ return 0;
+}
+
+static int sp805_wdt_stop(struct udevice *dev)
+{
+ struct sp805_wdt_priv *priv = dev_get_priv(dev);
+
+ writel(UNLOCK, priv->reg + WDTLOCK);
+ writel(DISABLE, priv->reg + WDTCONTROL);
+ writel(LOCK, priv->reg + WDTLOCK);
+ readl(priv->reg + WDTLOCK);
+
+ return 0;
+}
+
+static int sp805_wdt_probe(struct udevice *dev)
+{
+ debug("%s: Probing wdt%u\n", __func__, dev->seq);
+
+ return 0;
+}
+
+static int sp805_wdt_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sp805_wdt_priv *priv = dev_get_priv(dev);
+
+ priv->reg = (void __iomem *)dev_read_addr(dev);
+ if (IS_ERR(priv->reg))
+ return PTR_ERR(priv->reg);
+
+ return 0;
+}
+
+static const struct wdt_ops sp805_wdt_ops = {
+ .start = sp805_wdt_start,
+ .reset = sp805_wdt_reset,
+ .stop = sp805_wdt_stop,
+};
+
+static const struct udevice_id sp805_wdt_ids[] = {
+ { .compatible = "arm,sp805-wdt" },
+ {}
+};
+
+U_BOOT_DRIVER(sp805_wdt) = {
+ .name = "sp805_wdt",
+ .id = UCLASS_WDT,
+ .of_match = sp805_wdt_ids,
+ .probe = sp805_wdt_probe,
+ .priv_auto_alloc_size = sizeof(struct sp805_wdt_priv),
+ .ofdata_to_platdata = sp805_wdt_ofdata_to_platdata,
+ .ops = &sp805_wdt_ops,
+};