summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/ata/Kconfig7
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/mvsata_ide.c199
-rw-r--r--drivers/block/sandbox.c8
-rw-r--r--drivers/clk/aspeed/clk_ast2600.c2
-rw-r--r--drivers/clk/clk-composite.c8
-rw-r--r--drivers/clk/clk-hsdk-cgu.c4
-rw-r--r--drivers/clk/clk-uclass.c2
-rw-r--r--drivers/clk/clk_fixed_rate.c14
-rw-r--r--drivers/clk/clk_sandbox.c40
-rw-r--r--drivers/clk/clk_sandbox_test.c6
-rw-r--r--drivers/clk/clk_zynqmp.c251
-rw-r--r--drivers/clk/imx/clk-imx8.c4
-rw-r--r--drivers/clk/imx/clk-imx8qm.c6
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c6
-rw-r--r--drivers/clk/imx/clk-pllv3.c2
-rw-r--r--drivers/clk/kendryte/bypass.c2
-rw-r--r--drivers/clk/kendryte/clk.c2
-rw-r--r--drivers/clk/microchip/mpfs_clk.c1
-rw-r--r--drivers/clk/mvebu/armada-37xx-periph.c6
-rw-r--r--drivers/clk/sunxi/Makefile2
-rw-r--r--drivers/clk/sunxi/clk_h6.c2
-rw-r--r--drivers/clk/sunxi/clk_sun6i_rtc.c35
-rw-r--r--drivers/core/Kconfig14
-rw-r--r--drivers/core/acpi.c2
-rw-r--r--drivers/core/device.c111
-rw-r--r--drivers/core/of_addr.c4
-rw-r--r--drivers/core/of_extra.c23
-rw-r--r--drivers/core/root.c85
-rw-r--r--drivers/core/simple-bus.c32
-rw-r--r--drivers/core/simple-pm-bus.c4
-rw-r--r--drivers/core/uclass.c7
-rw-r--r--drivers/crypto/fsl/Kconfig6
-rw-r--r--drivers/crypto/fsl/Makefile4
-rw-r--r--drivers/crypto/fsl/desc.h49
-rw-r--r--drivers/crypto/fsl/desc_constr.h28
-rw-r--r--drivers/crypto/fsl/fsl_blob.c6
-rw-r--r--drivers/crypto/fsl/fsl_hash.c6
-rw-r--r--drivers/crypto/fsl/fsl_mfgprot.c160
-rw-r--r--drivers/crypto/fsl/jobdesc.c16
-rw-r--r--drivers/crypto/fsl/jr.c53
-rw-r--r--drivers/crypto/fsl/jr.h11
-rw-r--r--drivers/crypto/fsl/type.h16
-rw-r--r--drivers/ddr/fsl/Kconfig1
-rw-r--r--drivers/ddr/imx/imx8m/Kconfig8
-rw-r--r--drivers/dfu/dfu_sf.c18
-rw-r--r--drivers/fastboot/fb_mmc.c6
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c207
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_devices.c25
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c10
-rw-r--r--drivers/firmware/scmi/smt.c15
-rw-r--r--drivers/gpio/gpio-uclass.c243
-rw-r--r--drivers/gpio/intel_gpio.c86
-rw-r--r--drivers/gpio/sandbox.c138
-rw-r--r--drivers/gpio/stm32_gpio.c17
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/Makefile2
-rw-r--r--drivers/i2c/i2c-emul-uclass.c34
-rw-r--r--drivers/i2c/i2c-gpio.c19
-rw-r--r--drivers/misc/Kconfig18
-rw-r--r--drivers/misc/Makefile7
-rw-r--r--drivers/misc/cbmem_console.c2
-rw-r--r--drivers/misc/cros_ec.c17
-rw-r--r--drivers/misc/cros_ec_sandbox.c4
-rw-r--r--drivers/misc/irq-uclass.c2
-rw-r--r--drivers/misc/mxc_ocotp.c2
-rw-r--r--drivers/misc/p2sb_emul.c1
-rw-r--r--drivers/misc/qfw.c243
-rw-r--r--drivers/misc/qfw_mmio.c119
-rw-r--r--drivers/misc/qfw_pio.c69
-rw-r--r--drivers/misc/qfw_sandbox.c127
-rw-r--r--drivers/misc/test_drv.c11
-rw-r--r--drivers/mmc/Kconfig18
-rw-r--r--drivers/mmc/fsl_esdhc.c31
-rw-r--r--drivers/mmc/fsl_esdhc_imx.c53
-rw-r--r--drivers/mmc/mmc-uclass.c12
-rw-r--r--drivers/mmc/mmc.c8
-rw-r--r--drivers/mmc/mvebu_mmc.c307
-rw-r--r--drivers/mmc/pci_mmc.c6
-rw-r--r--drivers/mtd/cfi_flash.c37
-rw-r--r--drivers/mtd/nand/raw/mxs_nand_spl.c5
-rw-r--r--drivers/mtd/nand/raw/nand_base.c2
-rw-r--r--drivers/mtd/spi/sf-uclass.c14
-rw-r--r--drivers/mtd/spi/sf_internal.h4
-rw-r--r--drivers/mtd/spi/sf_probe.c8
-rw-r--r--drivers/mtd/spi/spi-nor-core.c11
-rw-r--r--drivers/mtd/spi/spi-nor-tiny.c6
-rw-r--r--drivers/net/Kconfig33
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/designware.c96
-rw-r--r--drivers/net/dsa_sandbox.c179
-rw-r--r--drivers/net/dwmac_meson8b.c150
-rw-r--r--drivers/net/fm/Makefile2
-rw-r--r--drivers/net/mdio_mux_meson_g12a.c149
-rw-r--r--drivers/net/mdio_mux_mmioreg.c129
-rw-r--r--drivers/net/phy/Kconfig1
-rw-r--r--drivers/net/phy/fixed.c54
-rw-r--r--drivers/net/phy/phy.c63
-rw-r--r--drivers/net/phy/xilinx_gmii2rgmii.c61
-rw-r--r--drivers/net/tsec.c36
-rw-r--r--drivers/net/zynq_gem.c25
-rw-r--r--drivers/pci/Kconfig16
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/pci_auto.c3
-rw-r--r--drivers/pci/pci_rom.c7
-rw-r--r--drivers/pci/pcie_dw_common.c365
-rw-r--r--drivers/pci/pcie_dw_common.h155
-rw-r--r--drivers/pci/pcie_dw_meson.c459
-rw-r--r--drivers/pci/pcie_dw_rockchip.c472
-rw-r--r--drivers/pci/pcie_dw_ti.c444
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7629.c7
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c28
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c26
-rw-r--r--drivers/pinctrl/pinctrl-stmfx.c19
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c10
-rw-r--r--drivers/pinctrl/renesas/Kconfig10
-rw-r--r--drivers/pinctrl/renesas/Makefile1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77990.c87
-rw-r--r--drivers/pinctrl/renesas/pfc.c11
-rw-r--r--drivers/pinctrl/renesas/sh_pfc.h1
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/pmic_max77696.c31
-rw-r--r--drivers/power/pmic/pmic_pca9450.c4
-rw-r--r--drivers/power/regulator/Kconfig8
-rw-r--r--drivers/power/regulator/Makefile1
-rw-r--r--drivers/power/regulator/scmi_regulator.c195
-rw-r--r--drivers/pwm/Kconfig9
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/cros_ec_pwm.c84
-rw-r--r--drivers/pwm/rk_pwm.c2
-rw-r--r--drivers/pwm/sandbox_pwm.c11
-rw-r--r--drivers/qe/Kconfig1
-rw-r--r--drivers/ram/sifive/Kconfig2
-rw-r--r--drivers/ram/stm32_sdram.c3
-rw-r--r--drivers/reset/Kconfig2
-rw-r--r--drivers/rtc/Kconfig13
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/armada38x.c184
-rw-r--r--drivers/rtc/i2c_rtc_emul.c21
-rw-r--r--drivers/rtc/rv3028.c208
-rw-r--r--drivers/rtc/sandbox_rtc.c13
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/serial_coreboot.c2
-rw-r--r--drivers/serial/serial_mtk.c74
-rw-r--r--drivers/sound/tegra_i2s.c1
-rw-r--r--drivers/spi/spi-uclass.c11
-rw-r--r--drivers/spi/xilinx_spi.c8
-rw-r--r--drivers/sysreset/sysreset-uclass.c2
-rw-r--r--drivers/tee/optee/Kconfig6
-rw-r--r--drivers/tee/optee/core.c6
-rw-r--r--drivers/tee/sandbox.c54
-rw-r--r--drivers/timer/sandbox_timer.c3
-rw-r--r--drivers/timer/sifive_clint_timer.c1
-rw-r--r--drivers/timer/timer-uclass.c6
-rw-r--r--drivers/tpm/Makefile2
-rw-r--r--drivers/tpm/cr50_i2c.c4
-rw-r--r--drivers/tpm/tpm-uclass.c8
-rw-r--r--drivers/tpm/tpm2_tis_sandbox.c2
-rw-r--r--drivers/usb/dwc3/linux-compat.h6
-rw-r--r--drivers/usb/gadget/udc/udc-uclass.c2
-rw-r--r--drivers/usb/host/xhci-mem.c8
-rw-r--r--drivers/usb/host/xhci-ring.c9
-rw-r--r--drivers/video/Kconfig4
-rw-r--r--drivers/video/cfb_console.c14
-rw-r--r--drivers/video/coreboot.c18
-rw-r--r--drivers/video/pwm_backlight.c20
-rw-r--r--drivers/video/rockchip/rk_edp.c103
-rw-r--r--drivers/video/rockchip/rk_vop.c84
-rw-r--r--drivers/video/sunxi/Makefile2
-rw-r--r--drivers/video/sunxi/sunxi_display.c268
-rw-r--r--drivers/video/tegra124/sor.c4
-rw-r--r--drivers/video/video_bmp.c4
-rw-r--r--drivers/watchdog/Kconfig20
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/booke_wdt.c106
-rw-r--r--drivers/watchdog/designware_wdt.c37
-rw-r--r--drivers/watchdog/imx_watchdog.c2
-rw-r--r--drivers/watchdog/ulp_wdog.c2
-rw-r--r--drivers/watchdog/wdt-uclass.c28
180 files changed, 5726 insertions, 2333 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index c562a719f74..3510daba29f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -38,7 +38,7 @@ ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_BOOTCOUNT_LIMIT) += bootcount/
obj-$(CONFIG_SPL_CACHE_SUPPORT) += cache/
-obj-$(CONFIG_SPL_CPU_SUPPORT) += cpu/
+obj-$(CONFIG_SPL_CPU) += cpu/
obj-$(CONFIG_SPL_CRYPTO_SUPPORT) += crypto/
obj-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/
obj-$(CONFIG_ARMADA_38X) += ddr/marvell/a38x/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index f2f8275aeca..9ff4b8736c1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -62,6 +62,7 @@ config DWC_AHCI
config DWC_AHSATA
bool "Enable DWC AHSATA driver support"
select LIBATA
+ depends on BLK
help
Enable this driver to support the DWC AHSATA SATA controller found
in i.MX5 and i.MX6 SoCs.
@@ -82,12 +83,6 @@ config FSL_SATA
Enable this driver to support the SATA controller found in
some Freescale PowerPC SoCs.
-config MVSATA_IDE
- bool "Enable Marvell SATA controller driver support via IDE interface"
- help
- Enable this driver to support the SATA controller found in
- some Marvell SoCs, running in IDE compatibility mode using PIO.
-
config SATA_MV
bool "Enable Marvell SATA controller driver support"
select AHCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 98fb4807008..4811b2f82c4 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_SCSI_AHCI) += ahci.o
obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
obj-$(CONFIG_FSL_SATA) += fsl_sata.o
obj-$(CONFIG_LIBATA) += libata.o
-obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o
obj-$(CONFIG_SATA) += sata.o
obj-$(CONFIG_SATA_CEVA) += sata_ceva.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
diff --git a/drivers/ata/mvsata_ide.c b/drivers/ata/mvsata_ide.c
deleted file mode 100644
index 41f9a91617d..00000000000
--- a/drivers/ata/mvsata_ide.c
+++ /dev/null
@@ -1,199 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net>
- *
- * Written-by: Albert ARIBAUD <albert.u.boot@aribaud.net>
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-
-#if defined(CONFIG_ARCH_ORION5X)
-#include <asm/arch/orion5x.h>
-#elif defined(CONFIG_ARCH_KIRKWOOD)
-#include <asm/arch/soc.h>
-#elif defined(CONFIG_ARCH_MVEBU)
-#include <linux/mbus.h>
-#endif
-
-/* SATA port registers */
-struct mvsata_port_registers {
- u32 reserved0[10];
- u32 edma_cmd;
- u32 reserved1[181];
- /* offset 0x300 : ATA Interface registers */
- u32 sstatus;
- u32 serror;
- u32 scontrol;
- u32 ltmode;
- u32 phymode3;
- u32 phymode4;
- u32 reserved2[5];
- u32 phymode1;
- u32 phymode2;
- u32 bist_cr;
- u32 bist_dw1;
- u32 bist_dw2;
- u32 serrorintrmask;
-};
-
-/*
- * Sanity checks:
- * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR.
- * - for ide_preinit to make sense, we need at least one of
- * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET;
- * - for ide_preinit to be called, we need CONFIG_IDE_PREINIT.
- * Fail with an explanation message if these conditions are not met.
- * This is particularly important for CONFIG_IDE_PREINIT, because
- * its lack would not cause a build error.
- */
-
-#if !defined(CONFIG_SYS_ATA_BASE_ADDR)
-#error CONFIG_SYS_ATA_BASE_ADDR must be defined
-#elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \
- && !defined(CONFIG_SYS_ATA_IDE1_OFFSET)
-#error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \
- must be defined
-#elif !defined(CONFIG_IDE_PREINIT)
-#error CONFIG_IDE_PREINIT must be defined
-#endif
-
-/*
- * Masks and values for SControl DETection and Interface Power Management,
- * and for SStatus DETection.
- */
-
-#define MVSATA_EDMA_CMD_ATA_RST 0x00000004
-#define MVSATA_SCONTROL_DET_MASK 0x0000000F
-#define MVSATA_SCONTROL_DET_NONE 0x00000000
-#define MVSATA_SCONTROL_DET_INIT 0x00000001
-#define MVSATA_SCONTROL_IPM_MASK 0x00000F00
-#define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300
-#define MVSATA_SCONTROL_MASK \
- (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK)
-#define MVSATA_PORT_INIT \
- (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED)
-#define MVSATA_PORT_USE \
- (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED)
-#define MVSATA_SSTATUS_DET_MASK 0x0000000F
-#define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003
-
-/*
- * Status codes to return to client callers. Currently, callers ignore
- * exact value and only care for zero or nonzero, so no need to make this
- * public, it is only #define'd for clarity.
- * If/when standard negative codes are implemented in U-Boot, then these
- * #defines should be moved to, or replaced by ones from, the common list
- * of status codes.
- */
-
-#define MVSATA_STATUS_OK 0
-#define MVSATA_STATUS_TIMEOUT -1
-
-/*
- * Registers for SATA MBUS memory windows
- */
-
-#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4))
-#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4))
-
-/*
- * Initialize SATA memory windows for Armada XP
- */
-
-#ifdef CONFIG_ARCH_MVEBU
-static void mvsata_ide_conf_mbus_windows(void)
-{
- const struct mbus_dram_target_info *dram;
- int i;
-
- dram = mvebu_mbus_dram_info();
-
- /* Disable windows, Set Size/Base to 0 */
- for (i = 0; i < 4; i++) {
- writel(0, MVSATA_WIN_CONTROL(i));
- writel(0, MVSATA_WIN_BASE(i));
- }
-
- for (i = 0; i < dram->num_cs; i++) {
- const struct mbus_dram_window *cs = dram->cs + i;
- writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
- (dram->mbus_dram_target_id << 4) | 1,
- MVSATA_WIN_CONTROL(i));
- writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i));
- }
-}
-#endif
-
-/*
- * Initialize one MVSATAHC port: set SControl's IPM to "always active"
- * and DET to "reset", then wait for SStatus's DET to become "device and
- * comm ok" (or time out after 50 us if no device), then set SControl's
- * DET back to "no action".
- */
-
-static int mvsata_ide_initialize_port(struct mvsata_port_registers *port)
-{
- u32 control;
- u32 status;
- u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */
-
- /* Hard reset */
- writel(MVSATA_EDMA_CMD_ATA_RST, &port->edma_cmd);
- udelay(25); /* taken from original marvell port */
- writel(0, &port->edma_cmd);
-
- /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */
- control = readl(&port->scontrol);
- control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT;
- writel(control, &port->scontrol);
- /* Toggle control DET back to 0 (normal operation) */
- control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE;
- writel(control, &port->scontrol);
- /* wait for status DET to become 3 (device and communication OK) */
- while (--timeleft) {
- status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK;
- if (status == MVSATA_SSTATUS_DET_DEVCOMM)
- break;
- udelay(1);
- }
- /* return success or time-out error depending on time left */
- if (!timeleft)
- return MVSATA_STATUS_TIMEOUT;
- return MVSATA_STATUS_OK;
-}
-
-/*
- * ide_preinit() will be called by ide_init in cmd_ide.c and will
- * reset the MVSTATHC ports needed by the board.
- */
-
-int ide_preinit(void)
-{
- int ret = MVSATA_STATUS_TIMEOUT;
- int status;
-
-#ifdef CONFIG_ARCH_MVEBU
- mvsata_ide_conf_mbus_windows();
-#endif
-
- /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */
-#if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
- status = mvsata_ide_initialize_port(
- (struct mvsata_port_registers *)
- (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET));
- if (status == MVSATA_STATUS_OK)
- ret = MVSATA_STATUS_OK;
-#endif
- /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */
-#if defined(CONFIG_SYS_ATA_IDE1_OFFSET)
- status = mvsata_ide_initialize_port(
- (struct mvsata_port_registers *)
- (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET));
- if (status == MVSATA_STATUS_OK)
- ret = MVSATA_STATUS_OK;
-#endif
- /* Return success if at least one port initialization succeeded */
- return ret;
-}
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index e2f229b15db..1c2c3b4f886 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -89,7 +89,7 @@ static unsigned long host_block_write(struct blk_desc *block_dev,
}
#ifdef CONFIG_BLK
-int host_dev_bind(int devnum, char *filename)
+int host_dev_bind(int devnum, char *filename, bool removable)
{
struct host_block_dev *host_dev;
struct udevice *dev;
@@ -146,7 +146,7 @@ int host_dev_bind(int devnum, char *filename)
}
desc = blk_get_devnum_by_type(IF_TYPE_HOST, devnum);
- desc->removable = 1;
+ desc->removable = removable;
snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
snprintf(desc->revision, BLK_REV_SIZE, "1.0");
@@ -160,7 +160,7 @@ err:
return ret;
}
#else
-int host_dev_bind(int dev, char *filename)
+int host_dev_bind(int dev, char *filename, bool removable)
{
struct host_block_dev *host_dev = find_host_device(dev);
@@ -195,7 +195,7 @@ int host_dev_bind(int dev, char *filename)
blk_dev->block_write = host_block_write;
blk_dev->devnum = dev;
blk_dev->part_type = PART_TYPE_UNKNOWN;
- blk_dev->removable = 1;
+ blk_dev->removable = removable;
snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot");
snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile");
snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0");
diff --git a/drivers/clk/aspeed/clk_ast2600.c b/drivers/clk/aspeed/clk_ast2600.c
index acb7eca7414..3a92739f5cf 100644
--- a/drivers/clk/aspeed/clk_ast2600.c
+++ b/drivers/clk/aspeed/clk_ast2600.c
@@ -1140,7 +1140,7 @@ int soc_clk_dump(void)
clk_free(&clk);
- if (ret == -ENOTSUPP) {
+ if (ret == -EINVAL) {
printf("clk ID %lu not supported yet\n",
aspeed_clk_names[i].id);
continue;
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 7e99c5b910d..bb5351ebc0b 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -37,10 +37,10 @@ static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk *mux = composite->mux;
- if (mux && mux_ops)
- return mux_ops->set_parent(mux, parent);
- else
- return -ENOTSUPP;
+ if (!mux || !mux_ops)
+ return -ENOSYS;
+
+ return mux_ops->set_parent(mux, parent);
}
static unsigned long clk_composite_recalc_rate(struct clk *clk)
diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c
index 449b430e230..26b0aa9a26f 100644
--- a/drivers/clk/clk-hsdk-cgu.c
+++ b/drivers/clk/clk-hsdk-cgu.c
@@ -718,7 +718,7 @@ static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate)
if (clk->map[sclk->id].set_rate)
return clk->map[sclk->id].set_rate(sclk, rate);
- return -ENOTSUPP;
+ return -EINVAL;
}
static int hsdk_cgu_disable(struct clk *sclk)
@@ -731,7 +731,7 @@ static int hsdk_cgu_disable(struct clk *sclk)
if (clk->map[sclk->id].disable)
return clk->map[sclk->id].disable(sclk);
- return -ENOTSUPP;
+ return -EINVAL;
}
static const struct clk_ops hsdk_cgu_ops = {
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index b87288da7a2..4ab3c402ed8 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -39,7 +39,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells,
{
int ret;
- ret = device_get_by_driver_info_idx(cells->idx, &clk->dev);
+ ret = device_get_by_ofplat_idx(cells->idx, &clk->dev);
if (ret)
return ret;
clk->id = cells->arg[0];
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index 3c5a83c523c..09f9ef26a42 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -25,18 +25,24 @@ const struct clk_ops clk_fixed_rate_ops = {
.enable = dummy_enable,
};
-static int clk_fixed_rate_of_to_plat(struct udevice *dev)
+void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev,
+ struct clk_fixed_rate *plat)
{
- struct clk *clk = &to_clk_fixed_rate(dev)->clk;
+ struct clk *clk = &plat->clk;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
- to_clk_fixed_rate(dev)->fixed_rate =
- dev_read_u32_default(dev, "clock-frequency", 0);
+ plat->fixed_rate = dev_read_u32_default(dev, "clock-frequency", 0);
#endif
/* Make fixed rate clock accessible from higher level struct clk */
/* FIXME: This is not allowed */
dev_set_uclass_priv(dev, clk);
+
clk->dev = dev;
clk->enable_count = 0;
+}
+
+static int clk_fixed_rate_of_to_plat(struct udevice *dev)
+{
+ clk_fixed_rate_ofdata_to_plat_(dev, to_clk_fixed_rate(dev));
return 0;
}
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
index b28b67b4486..57acf7d8553 100644
--- a/drivers/clk/clk_sandbox.c
+++ b/drivers/clk/clk_sandbox.c
@@ -9,13 +9,7 @@
#include <errno.h>
#include <malloc.h>
#include <asm/clk.h>
-
-struct sandbox_clk_priv {
- bool probed;
- ulong rate[SANDBOX_CLK_ID_COUNT];
- bool enabled[SANDBOX_CLK_ID_COUNT];
- bool requested[SANDBOX_CLK_ID_COUNT];
-};
+#include <linux/clk-provider.h>
static ulong sandbox_clk_get_rate(struct clk *clk)
{
@@ -178,3 +172,35 @@ int sandbox_clk_query_requested(struct udevice *dev, int id)
return -EINVAL;
return priv->requested[id];
}
+
+int clk_fixed_rate_of_to_plat(struct udevice *dev)
+{
+ struct clk_fixed_rate *cplat;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct sandbox_clk_fixed_rate_plat *plat = dev_get_plat(dev);
+
+ cplat = &plat->fixed;
+ cplat->fixed_rate = plat->dtplat.clock_frequency;
+#else
+ cplat = to_clk_fixed_rate(dev);
+#endif
+ clk_fixed_rate_ofdata_to_plat_(dev, cplat);
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_clk_fixed_rate_match[] = {
+ { .compatible = "sandbox,fixed-clock" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_fixed_clock) = {
+ .name = "sandbox_fixed_clock",
+ .id = UCLASS_CLK,
+ .of_match = sandbox_clk_fixed_rate_match,
+ .of_to_plat = clk_fixed_rate_of_to_plat,
+ .plat_auto = sizeof(struct sandbox_clk_fixed_rate_plat),
+ .ops = &clk_fixed_rate_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c
index c4e44815084..f665fd3cc45 100644
--- a/drivers/clk/clk_sandbox_test.c
+++ b/drivers/clk/clk_sandbox_test.c
@@ -11,12 +11,6 @@
#include <dm/device_compat.h>
#include <linux/err.h>
-struct sandbox_clk_test {
- struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
- struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
- struct clk_bulk bulk;
-};
-
static const char * const sandbox_clk_test_names[] = {
[SANDBOX_CLK_TEST_ID_FIXED] = "fixed",
[SANDBOX_CLK_TEST_ID_SPI] = "spi",
diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c
index 609d8e3b2ff..13a623fdb96 100644
--- a/drivers/clk/clk_zynqmp.c
+++ b/drivers/clk/clk_zynqmp.c
@@ -97,8 +97,7 @@ static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020;
#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT)
#define CLK_CTRL_DIV0_SHIFT 8
#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT)
-#define CLK_CTRL_SRCSEL_SHIFT 0
-#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
+#define CLK_CTRL_SRCSEL_MASK 0x7
#define PLLCTRL_FBDIV_MASK 0x7f00
#define PLLCTRL_FBDIV_SHIFT 8
#define PLLCTRL_RESET_MASK 1
@@ -132,7 +131,7 @@ enum zynqmp_clk {
iou_switch,
gem_tsu_ref, gem_tsu,
gem0_ref, gem1_ref, gem2_ref, gem3_ref,
- gem0_rx, gem1_rx, gem2_rx, gem3_rx,
+ gem0_tx, gem1_tx, gem2_tx, gem3_tx,
qspi_ref,
sdio0_ref, sdio1_ref,
uart0_ref, uart1_ref,
@@ -152,7 +151,7 @@ static const char * const clk_names[clk_max] = {
"iopll", "rpll", "apll", "dpll",
"vpll", "iopll_to_fpd", "rpll_to_fpd",
"apll_to_lpd", "dpll_to_lpd", "vpll_to_lpd",
- "acpu", "acpu_half", "dbf_fpd", "dbf_lpd",
+ "acpu", "acpu_half", "dbg_fpd", "dbg_lpd",
"dbg_trace", "dbg_tstmp", "dp_video_ref",
"dp_audio_ref", "dp_stc_ref", "gdma_ref",
"dpdma_ref", "ddr_ref", "sata_ref", "pcie_ref",
@@ -172,6 +171,38 @@ static const char * const clk_names[clk_max] = {
"ams_ref", "pl0", "pl1", "pl2", "pl3", "wdt"
};
+static const u32 pll_src[][4] = {
+ {apll, 0xff, dpll, vpll}, /* acpu */
+ {dpll, vpll, 0xff, 0xff}, /* ddr_ref */
+ {rpll, iopll, 0xff, 0xff}, /* dll_ref */
+ {iopll, 0xff, rpll, dpll_to_lpd}, /* gem_tsu_ref */
+ {iopll, 0xff, rpll, dpll}, /* peripheral */
+ {apll, 0xff, iopll_to_fpd, dpll}, /* wdt */
+ {iopll_to_fpd, 0xff, dpll, apll}, /* dbg_fpd */
+ {iopll, 0xff, rpll, dpll_to_lpd}, /* timestamp_ref */
+ {iopll_to_fpd, 0xff, apll, dpll}, /* sata_ref */
+ {iopll_to_fpd, 0xff, rpll_to_fpd, dpll},/* pcie_ref */
+ {iopll_to_fpd, 0xff, vpll, dpll}, /* gpu_ref */
+ {apll, 0xff, vpll, dpll}, /* topsw_main_ref */
+ {rpll, 0xff, iopll, dpll_to_lpd}, /* cpu_r5_ref */
+};
+
+enum zynqmp_clk_pll_src {
+ ACPU_CLK_SRC = 0,
+ DDR_CLK_SRC,
+ DLL_CLK_SRC,
+ GEM_TSU_CLK_SRC,
+ PERI_CLK_SRC,
+ WDT_CLK_SRC,
+ DBG_FPD_CLK_SRC,
+ TIMESTAMP_CLK_SRC,
+ SATA_CLK_SRC,
+ PCIE_CLK_SRC,
+ GPU_CLK_SRC,
+ TOPSW_MAIN_CLK_SRC,
+ CPU_R5_CLK_SRC
+};
+
struct zynqmp_clk_priv {
unsigned long ps_clk_freq;
unsigned long video_clk;
@@ -195,12 +226,38 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRF_APB_VPLL_CTRL;
case acpu:
return CRF_APB_ACPU_CTRL;
+ case dbg_fpd:
+ return CRF_APB_DBG_FPD_CTRL;
+ case dbg_trace:
+ return CRF_APB_DBG_TRACE_CTRL;
+ case dbg_tstmp:
+ return CRF_APB_DBG_TSTMP_CTRL;
+ case gpu_ref ... gpu_pp1_ref:
+ return CRF_APB_GPU_REF_CTRL;
case ddr_ref:
return CRF_APB_DDR_CTRL;
+ case sata_ref:
+ return CRF_APB_SATA_REF_CTRL;
+ case pcie_ref:
+ return CRF_APB_PCIE_REF_CTRL;
+ case gdma_ref:
+ return CRF_APB_GDMA_REF_CTRL;
+ case dpdma_ref:
+ return CRF_APB_DPDMA_REF_CTRL;
+ case topsw_main:
+ return CRF_APB_TOPSW_MAIN_CTRL;
+ case topsw_lsbus:
+ return CRF_APB_TOPSW_LSBUS_CTRL;
+ case lpd_switch:
+ return CRL_APB_LPD_SWITCH_CTRL;
+ case lpd_lsbus:
+ return CRL_APB_LPD_LSBUS_CTRL;
case qspi_ref:
return CRL_APB_QSPI_REF_CTRL;
case usb3_dual_ref:
return CRL_APB_USB3_DUAL_REF_CTRL;
+ case gem_tsu_ref:
+ return CRL_APB_GEM_TSU_REF_CTRL;
case gem0_ref:
return CRL_APB_GEM0_REF_CTRL;
case gem1_ref:
@@ -213,6 +270,8 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRL_APB_USB0_BUS_REF_CTRL;
case usb1_bus_ref:
return CRL_APB_USB1_BUS_REF_CTRL;
+ case cpu_r5:
+ return CRL_APB_CPU_R5_CTRL;
case uart0_ref:
return CRL_APB_UART0_REF_CTRL;
case uart1_ref:
@@ -235,6 +294,14 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRL_APB_CAN0_REF_CTRL;
case can1_ref:
return CRL_APB_CAN1_REF_CTRL;
+ case dll_ref:
+ return CRL_APB_DLL_REF_CTRL;
+ case adma_ref:
+ return CRL_APB_ADMA_REF_CTRL;
+ case timestamp_ref:
+ return CRL_APB_TIMESTAMP_REF_CTRL;
+ case ams_ref:
+ return CRL_APB_AMS_REF_CTRL;
case pl0:
return CRL_APB_PL0_REF_CTRL;
case pl1:
@@ -253,68 +320,6 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return 0;
}
-static enum zynqmp_clk zynqmp_clk_get_cpu_pll(u32 clk_ctrl)
-{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
- CLK_CTRL_SRCSEL_SHIFT;
-
- switch (srcsel) {
- case 2:
- return dpll;
- case 3:
- return vpll;
- case 0 ... 1:
- default:
- return apll;
- }
-}
-
-static enum zynqmp_clk zynqmp_clk_get_ddr_pll(u32 clk_ctrl)
-{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
- CLK_CTRL_SRCSEL_SHIFT;
-
- switch (srcsel) {
- case 1:
- return vpll;
- case 0:
- default:
- return dpll;
- }
-}
-
-static enum zynqmp_clk zynqmp_clk_get_peripheral_pll(u32 clk_ctrl)
-{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
- CLK_CTRL_SRCSEL_SHIFT;
-
- switch (srcsel) {
- case 2:
- return rpll;
- case 3:
- return dpll;
- case 0 ... 1:
- default:
- return iopll;
- }
-}
-
-static enum zynqmp_clk zynqmp_clk_get_wdt_pll(u32 clk_ctrl)
-{
- u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
- CLK_CTRL_SRCSEL_SHIFT;
-
- switch (srcsel) {
- case 2:
- return iopll_to_fpd;
- case 3:
- return dpll;
- case 0 ... 1:
- default:
- return apll;
- }
-}
-
static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
struct zynqmp_clk_priv *priv,
bool is_pre_src)
@@ -378,7 +383,7 @@ static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
enum zynqmp_clk id)
{
- u32 clk_ctrl, div;
+ u32 clk_ctrl, div, srcsel;
enum zynqmp_clk pll;
int ret;
unsigned long pllrate;
@@ -391,7 +396,8 @@ static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- pll = zynqmp_clk_get_cpu_pll(clk_ctrl);
+ srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
+ pll = pll_src[ACPU_CLK_SRC][srcsel];
pllrate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pllrate))
return pllrate;
@@ -401,7 +407,7 @@ static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
{
- u32 clk_ctrl, div;
+ u32 clk_ctrl, div, srcsel;
enum zynqmp_clk pll;
int ret;
ulong pllrate;
@@ -414,7 +420,8 @@ static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
- pll = zynqmp_clk_get_ddr_pll(clk_ctrl);
+ srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
+ pll = pll_src[DDR_CLK_SRC][srcsel];
pllrate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pllrate))
return pllrate;
@@ -422,11 +429,33 @@ static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
return DIV_ROUND_CLOSEST(pllrate, div);
}
+static ulong zynqmp_clk_get_dll_rate(struct zynqmp_clk_priv *priv)
+{
+ u32 clk_ctrl, srcsel;
+ enum zynqmp_clk pll;
+ ulong pllrate;
+ int ret;
+
+ ret = zynqmp_mmio_read(CRL_APB_DLL_REF_CTRL, &clk_ctrl);
+ if (ret) {
+ printf("%s mio read fail\n", __func__);
+ return -EIO;
+ }
+
+ srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
+ pll = pll_src[DLL_CLK_SRC][srcsel];
+ pllrate = zynqmp_clk_get_pll_rate(priv, pll);
+ if (IS_ERR_VALUE(pllrate))
+ return pllrate;
+
+ return pllrate;
+}
+
static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
- enum zynqmp_clk id, bool two_divs)
+ enum zynqmp_clk id, bool two_divs)
{
enum zynqmp_clk pll;
- u32 clk_ctrl, div0;
+ u32 clk_ctrl, div0, srcsel;
u32 div1 = 1;
int ret;
ulong pllrate;
@@ -446,8 +475,13 @@ static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
if (!div1)
div1 = 1;
}
+ srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
+
+ if (id == gem_tsu_ref)
+ pll = pll_src[GEM_TSU_CLK_SRC][srcsel];
+ else
+ pll = pll_src[PERI_CLK_SRC][srcsel];
- pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
pllrate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pllrate))
return pllrate;
@@ -457,11 +491,11 @@ static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
DIV_ROUND_CLOSEST(pllrate, div0), div1);
}
-static ulong zynqmp_clk_get_wdt_rate(struct zynqmp_clk_priv *priv,
- enum zynqmp_clk id, bool two_divs)
+static ulong zynqmp_clk_get_crf_crl_rate(struct zynqmp_clk_priv *priv,
+ enum zynqmp_clk id, bool two_divs)
{
enum zynqmp_clk pll;
- u32 clk_ctrl, div0;
+ u32 clk_ctrl, div0, srcsel;
u32 div1 = 1;
int ret;
ulong pllrate;
@@ -475,8 +509,45 @@ static ulong zynqmp_clk_get_wdt_rate(struct zynqmp_clk_priv *priv,
div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
if (!div0)
div0 = 1;
+ srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
- pll = zynqmp_clk_get_wdt_pll(clk_ctrl);
+ switch (id) {
+ case wdt:
+ case dbg_trace:
+ case topsw_lsbus:
+ pll = pll_src[WDT_CLK_SRC][srcsel];
+ break;
+ case dbg_fpd:
+ case dbg_tstmp:
+ pll = pll_src[DBG_FPD_CLK_SRC][srcsel];
+ break;
+ case timestamp_ref:
+ pll = pll_src[TIMESTAMP_CLK_SRC][srcsel];
+ break;
+ case sata_ref:
+ pll = pll_src[SATA_CLK_SRC][srcsel];
+ break;
+ case pcie_ref:
+ pll = pll_src[PCIE_CLK_SRC][srcsel];
+ break;
+ case gpu_ref ... gpu_pp1_ref:
+ pll = pll_src[GPU_CLK_SRC][srcsel];
+ break;
+ case gdma_ref:
+ case dpdma_ref:
+ case topsw_main:
+ pll = pll_src[TOPSW_MAIN_CLK_SRC][srcsel];
+ break;
+ case cpu_r5:
+ case ams_ref:
+ case adma_ref:
+ case lpd_lsbus:
+ case lpd_switch:
+ pll = pll_src[CPU_R5_CLK_SRC][srcsel];
+ break;
+ default:
+ return -ENXIO;
+ }
if (two_divs) {
ret = zynqmp_mmio_read(zynqmp_clk_get_register(pll), &clk_ctrl);
if (ret) {
@@ -533,7 +604,7 @@ static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
enum zynqmp_clk pll;
u32 clk_ctrl, div0 = 0, div1 = 0;
ulong pll_rate, new_rate;
- u32 reg;
+ u32 reg, srcsel;
int ret;
u32 mask;
@@ -544,7 +615,8 @@ static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
return -EIO;
}
- pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
+ srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
+ pll = pll_src[PERI_CLK_SRC][srcsel];
pll_rate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pll_rate))
return pll_rate;
@@ -588,14 +660,31 @@ static ulong zynqmp_clk_get_rate(struct clk *clk)
return zynqmp_clk_get_cpu_rate(priv, id);
case ddr_ref:
return zynqmp_clk_get_ddr_rate(priv);
+ case dll_ref:
+ return zynqmp_clk_get_dll_rate(priv);
+ case gem_tsu_ref:
+ case pl0 ... pl3:
case gem0_ref ... gem3_ref:
case qspi_ref ... can1_ref:
- case pl0 ... pl3:
+ case usb0_bus_ref ... usb3_dual_ref:
two_divs = true;
return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
case wdt:
+ case topsw_lsbus:
+ case sata_ref ... gpu_pp1_ref:
two_divs = true;
- return zynqmp_clk_get_wdt_rate(priv, id, two_divs);
+ case cpu_r5:
+ case dbg_fpd:
+ case ams_ref:
+ case adma_ref:
+ case lpd_lsbus:
+ case dbg_trace:
+ case dbg_tstmp:
+ case lpd_switch:
+ case topsw_main:
+ case timestamp_ref:
+ case gdma_ref ... dpdma_ref:
+ return zynqmp_clk_get_crf_crl_rate(priv, id, two_divs);
default:
return -ENXIO;
}
diff --git a/drivers/clk/imx/clk-imx8.c b/drivers/clk/imx/clk-imx8.c
index 8484613eed5..b3dc138c4bb 100644
--- a/drivers/clk/imx/clk-imx8.c
+++ b/drivers/clk/imx/clk-imx8.c
@@ -29,7 +29,7 @@ __weak ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
__weak int __imx8_clk_enable(struct clk *clk, bool enable)
{
- return -ENOTSUPP;
+ return -EINVAL;
}
static int imx8_clk_disable(struct clk *clk)
@@ -70,7 +70,7 @@ int soc_clk_dump(void)
clk_free(&clk);
- if (ret == -ENOTSUPP) {
+ if (ret == -EINVAL) {
printf("clk ID %lu not supported yet\n",
imx8_clk_names[i].id);
continue;
diff --git a/drivers/clk/imx/clk-imx8qm.c b/drivers/clk/imx/clk-imx8qm.c
index 7e466d630a0..7759dc63ee1 100644
--- a/drivers/clk/imx/clk-imx8qm.c
+++ b/drivers/clk/imx/clk-imx8qm.c
@@ -133,7 +133,7 @@ ulong imx8_clk_get_rate(struct clk *clk)
__func__, clk->id);
return -EINVAL;
}
- return -ENOTSUPP;
+ return -EINVAL;
};
ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
@@ -237,7 +237,7 @@ ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
__func__, clk->id);
return -EINVAL;
}
- return -ENOTSUPP;
+ return -EINVAL;
};
ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
@@ -337,7 +337,7 @@ int __imx8_clk_enable(struct clk *clk, bool enable)
__func__, clk->id);
return -EINVAL;
}
- return -ENOTSUPP;
+ return -EINVAL;
}
ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
index e6b2fb40da2..ffa2fcee0b2 100644
--- a/drivers/clk/imx/clk-imx8qxp.c
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -126,7 +126,7 @@ ulong imx8_clk_get_rate(struct clk *clk)
__func__, clk->id);
return -EINVAL;
}
- return -ENOTSUPP;
+ return -EINVAL;
};
ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
@@ -221,7 +221,7 @@ ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
__func__, clk->id);
return -EINVAL;
}
- return -ENOTSUPP;
+ return -EINVAL;
};
ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
@@ -311,7 +311,7 @@ int __imx8_clk_enable(struct clk *clk, bool enable)
__func__, clk->id);
return -EINVAL;
}
- return -ENOTSUPP;
+ return -EINVAL;
}
ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index feacaee1c42..b5cbf800543 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -290,7 +290,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
break;
default:
kfree(pll);
- return ERR_PTR(-ENOTSUPP);
+ return ERR_PTR(-EINVAL);
}
pll->base = base;
diff --git a/drivers/clk/kendryte/bypass.c b/drivers/clk/kendryte/bypass.c
index 5f1986f2cb8..bbdbd9a10de 100644
--- a/drivers/clk/kendryte/bypass.c
+++ b/drivers/clk/kendryte/bypass.c
@@ -157,7 +157,7 @@ static int k210_bypass_set_parent(struct clk *clk, struct clk *parent)
if (ops->set_parent)
return ops->set_parent(bypass->bypassee, parent);
else
- return -ENOTSUPP;
+ return -EINVAL;
}
/*
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index 4b959401a63..3b674a998e3 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -495,7 +495,7 @@ static int k210_clk_probe(struct udevice *dev)
* could fix this, but it's Probably Not Worth It (TM).
*/
if (probed)
- return -ENOTSUPP;
+ return -EINVAL;
base = dev_read_addr_ptr(dev_get_parent(dev));
if (!base)
diff --git a/drivers/clk/microchip/mpfs_clk.c b/drivers/clk/microchip/mpfs_clk.c
index 722c79b7c0e..05d7647206c 100644
--- a/drivers/clk/microchip/mpfs_clk.c
+++ b/drivers/clk/microchip/mpfs_clk.c
@@ -120,4 +120,5 @@ U_BOOT_DRIVER(mpfs_clk) = {
.ops = &mpfs_clk_ops,
.probe = mpfs_clk_probe,
.priv_auto = sizeof(struct clk),
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index 0132fcb7e61..b0f47c33b3f 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -340,7 +340,7 @@ static int periph_clk_enable(struct clk *clk, int enable)
return -EINVAL;
if (!periph_clk->can_gate)
- return -ENOTSUPP;
+ return -EINVAL;
if (enable)
clrbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
@@ -408,7 +408,7 @@ static ulong armada_37xx_periph_clk_set_rate(struct clk *clk, ulong req_rate)
return old_rate;
if (!periph_clk->can_gate || !periph_clk->dividers)
- return -ENOTSUPP;
+ return -EINVAL;
parent_rate = get_parent_rate(priv, clk->id);
if (parent_rate == -EINVAL)
@@ -445,7 +445,7 @@ static int armada_37xx_periph_clk_set_parent(struct clk *clk,
return -EINVAL;
if (!periph_clk->can_mux || !periph_clk->can_gate)
- return -ENOTSUPP;
+ return -EINVAL;
ret = clk_get_by_index(clk->dev, 0, &check_parent);
if (ret < 0)
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 0dfc0593fb1..4f9282a8b9b 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -6,6 +6,8 @@
obj-$(CONFIG_CLK_SUNXI) += clk_sunxi.o
+obj-$(CONFIG_CLK_SUNXI) += clk_sun6i_rtc.o
+
obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o
obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o
diff --git a/drivers/clk/sunxi/clk_h6.c b/drivers/clk/sunxi/clk_h6.c
index ac8656fe895..df93d96b3b0 100644
--- a/drivers/clk/sunxi/clk_h6.c
+++ b/drivers/clk/sunxi/clk_h6.c
@@ -43,6 +43,7 @@ static struct ccu_clk_gate h6_gates[] = {
[CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
[CLK_BUS_OHCI3] = GATE(0xa8c, BIT(3)),
[CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
+ [CLK_BUS_XHCI] = GATE(0xa8c, BIT(5)),
[CLK_BUS_EHCI3] = GATE(0xa8c, BIT(7)),
[CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
};
@@ -71,6 +72,7 @@ static struct ccu_reset h6_resets[] = {
[RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
[RST_BUS_OHCI3] = RESET(0xa8c, BIT(19)),
[RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
+ [RST_BUS_XHCI] = RESET(0xa8c, BIT(21)),
[RST_BUS_EHCI3] = RESET(0xa8c, BIT(23)),
[RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
};
diff --git a/drivers/clk/sunxi/clk_sun6i_rtc.c b/drivers/clk/sunxi/clk_sun6i_rtc.c
new file mode 100644
index 00000000000..0c280d221ba
--- /dev/null
+++ b/drivers/clk/sunxi/clk_sun6i_rtc.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 Amarula Solutions.
+ * Copyright (C) 2020 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+
+static int clk_sun6i_rtc_enable(struct clk *clk)
+{
+ return 0;
+}
+
+static const struct clk_ops clk_sun6i_rtc_ops = {
+ .enable = clk_sun6i_rtc_enable,
+};
+
+static const struct udevice_id sun6i_rtc_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-rtc" },
+ { .compatible = "allwinner,sun8i-a23-rtc" },
+ { .compatible = "allwinner,sun8i-h3-rtc" },
+ { .compatible = "allwinner,sun8i-r40-rtc" },
+ { .compatible = "allwinner,sun8i-v3-rtc" },
+ { .compatible = "allwinner,sun50i-h5-rtc" },
+ { .compatible = "allwinner,sun50i-h6-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun6i_rtc) = {
+ .name = "clk_sun6i_rtc",
+ .id = UCLASS_CLK,
+ .of_match = sun6i_rtc_ids,
+ .ops = &clk_sun6i_rtc_ops,
+};
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 1eccac28c62..a7c31208604 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -235,6 +235,20 @@ config SPL_SIMPLE_BUS
Supports the 'simple-bus' driver, which is used on some systems
in SPL.
+config SIMPLE_BUS_CORRECT_RANGE
+ bool "Decode the 'simple-bus' <range> by honoring the #address-cells and #size-cells"
+ depends on SIMPLE_BUS
+ default y if SANDBOX
+ help
+ Decoding the 'simple-bus' <range> by honoring the #address-cells
+ and #size-cells of parent/child bus. If unset, #address-cells of
+ parent bus is assumed to be 1, #address-cells and #size-cells of
+ child bus is also assumed to be 1, to save some spaces of using
+ an advanced API to decode the <range>, which benefits SPL image
+ builds that have size limits.
+
+ If you are unsure about this, Say N here.
+
config SIMPLE_PM_BUS
bool "Support simple-pm-bus driver"
depends on DM && OF_CONTROL && CLK && POWER_DOMAIN
diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
index 0901b9260a1..2176d8b8365 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -91,7 +91,7 @@ int acpi_get_path(const struct udevice *dev, char *out_path, int maxlen)
path = dev_read_string(dev, "acpi,path");
if (path) {
if (strlen(path) >= maxlen)
- return -E2BIG;
+ return -ENOSPC;
strcpy(out_path, path);
return 0;
}
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 81f6880eac4..cb960f8ec44 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -45,6 +45,9 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
bool auto_seq = true;
void *ptr;
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND))
+ return -ENOSYS;
+
if (devp)
*devp = NULL;
if (!name)
@@ -395,26 +398,31 @@ int device_of_to_plat(struct udevice *dev)
if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
return 0;
- /* Ensure all parents have ofdata */
- if (dev->parent) {
- ret = device_of_to_plat(dev->parent);
+ /*
+ * This is not needed if binding is disabled, since data is allocated
+ * at build time.
+ */
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND)) {
+ /* Ensure all parents have ofdata */
+ if (dev->parent) {
+ ret = device_of_to_plat(dev->parent);
+ if (ret)
+ goto fail;
+
+ /*
+ * The device might have already been probed during
+ * the call to device_probe() on its parent device
+ * (e.g. PCI bridge devices). Test the flags again
+ * so that we don't mess up the device.
+ */
+ if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
+ return 0;
+ }
+
+ ret = device_alloc_priv(dev);
if (ret)
goto fail;
-
- /*
- * The device might have already been probed during
- * the call to device_probe() on its parent device
- * (e.g. PCI bridge devices). Test the flags again
- * so that we don't mess up the device.
- */
- if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
- return 0;
}
-
- ret = device_alloc_priv(dev);
- if (ret)
- goto fail;
-
drv = dev->driver;
assert(drv);
@@ -592,7 +600,7 @@ void *dev_get_plat(const struct udevice *dev)
return NULL;
}
- return dev->plat_;
+ return dm_priv_to_rw(dev->plat_);
}
void *dev_get_parent_plat(const struct udevice *dev)
@@ -602,7 +610,7 @@ void *dev_get_parent_plat(const struct udevice *dev)
return NULL;
}
- return dev->parent_plat_;
+ return dm_priv_to_rw(dev->parent_plat_);
}
void *dev_get_uclass_plat(const struct udevice *dev)
@@ -612,7 +620,7 @@ void *dev_get_uclass_plat(const struct udevice *dev)
return NULL;
}
- return dev->uclass_plat_;
+ return dm_priv_to_rw(dev->uclass_plat_);
}
void *dev_get_priv(const struct udevice *dev)
@@ -622,7 +630,7 @@ void *dev_get_priv(const struct udevice *dev)
return NULL;
}
- return dev->priv_;
+ return dm_priv_to_rw(dev->priv_);
}
void *dev_get_uclass_priv(const struct udevice *dev)
@@ -632,7 +640,7 @@ void *dev_get_uclass_priv(const struct udevice *dev)
return NULL;
}
- return dev->uclass_priv_;
+ return dm_priv_to_rw(dev->uclass_priv_);
}
void *dev_get_parent_priv(const struct udevice *dev)
@@ -642,7 +650,7 @@ void *dev_get_parent_priv(const struct udevice *dev)
return NULL;
}
- return dev->parent_priv_;
+ return dm_priv_to_rw(dev->parent_priv_);
}
static int device_get_device_tail(struct udevice *dev, int ret,
@@ -803,27 +811,19 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
}
#if CONFIG_IS_ENABLED(OF_PLATDATA)
-int device_get_by_driver_info(const struct driver_info *info,
- struct udevice **devp)
+int device_get_by_ofplat_idx(uint idx, struct udevice **devp)
{
- struct driver_info *info_base =
- ll_entry_start(struct driver_info, driver_info);
- int idx = info - info_base;
- struct driver_rt *drt = gd_dm_driver_rt() + idx;
struct udevice *dev;
- dev = drt->dev;
- *devp = NULL;
-
- return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
-}
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ struct udevice *base = ll_entry_start(struct udevice, udevice);
-int device_get_by_driver_info_idx(uint idx, struct udevice **devp)
-{
- struct driver_rt *drt = gd_dm_driver_rt() + idx;
- struct udevice *dev;
+ dev = base + idx;
+ } else {
+ struct driver_rt *drt = gd_dm_driver_rt() + idx;
- dev = drt->dev;
+ dev = drt->dev;
+ }
*devp = NULL;
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
@@ -1136,3 +1136,36 @@ int dev_enable_by_path(const char *path)
return lists_bind_fdt(parent, node, NULL, false);
}
#endif
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
+static struct udevice_rt *dev_get_rt(const struct udevice *dev)
+{
+ struct udevice *base = ll_entry_start(struct udevice, udevice);
+ int idx = dev - base;
+
+ struct udevice_rt *urt = gd_dm_udevice_rt() + idx;
+
+ return urt;
+}
+
+u32 dev_get_flags(const struct udevice *dev)
+{
+ const struct udevice_rt *urt = dev_get_rt(dev);
+
+ return urt->flags_;
+}
+
+void dev_or_flags(const struct udevice *dev, u32 or)
+{
+ struct udevice_rt *urt = dev_get_rt(dev);
+
+ urt->flags_ |= or;
+}
+
+void dev_bic_flags(const struct udevice *dev, u32 bic)
+{
+ struct udevice_rt *urt = dev_get_rt(dev);
+
+ urt->flags_ &= ~bic;
+}
+#endif /* OF_PLATDATA_RT */
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index 5bc6ca1de01..b3e384d2ee1 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -372,7 +372,7 @@ int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
bus_node->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
printf("Bad cell count for %s\n", of_node_full_name(dev));
- return -EINVAL;
+ ret = -EINVAL;
goto out_parent;
}
@@ -380,7 +380,7 @@ int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
bus_node->count_cells(parent, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
printf("Bad cell count for %s\n", of_node_full_name(parent));
- return -EINVAL;
+ ret = -EINVAL;
goto out_parent;
}
diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c
index 653344529e6..7702beff97b 100644
--- a/drivers/core/of_extra.c
+++ b/drivers/core/of_extra.c
@@ -130,3 +130,26 @@ int ofnode_decode_memory_region(ofnode config_node, const char *mem_type,
return 0;
}
+
+bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node)
+{
+ ofnode node, subnode;
+ int len;
+
+ subnode = ofnode_find_subnode(eth_node, "fixed-link");
+ if (ofnode_valid(subnode)) {
+ /* new binding */
+ node = subnode;
+ } else if (ofnode_get_property(eth_node, "fixed-link", &len) &&
+ len == (5 * sizeof(__be32))) {
+ /* old binding */
+ node = eth_node;
+ } else {
+ return false;
+ }
+
+ if (phy_node)
+ *phy_node = node;
+
+ return true;
+}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 9bc682cffea..d9a19c5e6b6 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -11,6 +11,7 @@
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
+#include <asm-generic/sections.h>
#include <asm/global_data.h>
#include <linux/libfdt.h>
#include <dm/acpi.h>
@@ -129,6 +130,36 @@ void fix_devices(void)
}
}
+static int dm_setup_inst(void)
+{
+ DM_ROOT_NON_CONST = DM_DEVICE_GET(root);
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) {
+ struct udevice_rt *urt;
+ void *base;
+ int n_ents;
+ uint size;
+
+ /* Allocate the udevice_rt table */
+ n_ents = ll_entry_count(struct udevice, udevice);
+ urt = calloc(n_ents, sizeof(struct udevice_rt));
+ if (!urt)
+ return log_msg_ret("urt", -ENOMEM);
+ gd_set_dm_udevice_rt(urt);
+
+ /* Now allocate space for the priv/plat data, and copy it in */
+ size = __priv_data_end - __priv_data_start;
+
+ base = calloc(1, size);
+ if (!base)
+ return log_msg_ret("priv", -ENOMEM);
+ memcpy(base, __priv_data_start, size);
+ gd_set_dm_priv_base(base);
+ }
+
+ return 0;
+}
+
int dm_init(bool of_live)
{
int ret;
@@ -140,8 +171,12 @@ int dm_init(bool of_live)
dm_warn("Virtual root driver already exists!\n");
return -EINVAL;
}
- gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
- INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ gd->uclass_root = &uclass_head;
+ } else {
+ gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
+ INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
+ }
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
fix_drivers();
@@ -149,14 +184,23 @@ int dm_init(bool of_live)
fix_devices();
}
- ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
- if (ret)
- return ret;
- if (CONFIG_IS_ENABLED(OF_CONTROL))
- dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
- ret = device_probe(DM_ROOT_NON_CONST);
- if (ret)
- return ret;
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ ret = dm_setup_inst();
+ if (ret) {
+ log_debug("dm_setup_inst() failed: %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = device_bind_by_name(NULL, false, &root_info,
+ &DM_ROOT_NON_CONST);
+ if (ret)
+ return ret;
+ if (CONFIG_IS_ENABLED(OF_CONTROL))
+ dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
+ ret = device_probe(DM_ROOT_NON_CONST);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -185,7 +229,7 @@ int dm_scan_plat(bool pre_reloc_only)
{
int ret;
- if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) {
struct driver_rt *dyn;
int n_ents;
@@ -303,6 +347,15 @@ __weak int dm_scan_other(bool pre_reloc_only)
return 0;
}
+#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
+void *dm_priv_to_rw(void *priv)
+{
+ long offset = priv - (void *)__priv_data_start;
+
+ return gd_dm_priv_base() + offset;
+}
+#endif
+
/**
* dm_scan() - Scan tables to bind devices
*
@@ -347,10 +400,12 @@ int dm_init_and_scan(bool pre_reloc_only)
debug("dm_init() failed: %d\n", ret);
return ret;
}
- ret = dm_scan(pre_reloc_only);
- if (ret) {
- log_debug("dm_scan() failed: %d\n", ret);
- return ret;
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+ ret = dm_scan(pre_reloc_only);
+ if (ret) {
+ log_debug("dm_scan() failed: %d\n", ret);
+ return ret;
+ }
}
return 0;
diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c
index b0c2c209587..18f52d26df2 100644
--- a/drivers/core/simple-bus.c
+++ b/drivers/core/simple-bus.c
@@ -4,8 +4,12 @@
*/
#include <common.h>
+#include <asm/global_data.h>
#include <dm.h>
#include <dm/simple_bus.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr)
{
@@ -22,16 +26,30 @@ static int simple_bus_post_bind(struct udevice *dev)
#if CONFIG_IS_ENABLED(OF_PLATDATA)
return 0;
#else
- u32 cell[3];
+ struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
int ret;
- ret = dev_read_u32_array(dev, "ranges", cell, ARRAY_SIZE(cell));
- if (!ret) {
- struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
+ if (CONFIG_IS_ENABLED(SIMPLE_BUS_CORRECT_RANGE)) {
+ uint64_t caddr, paddr, len;
+
+ /* only read range index 0 */
+ ret = fdt_read_range((void *)gd->fdt_blob, dev_of_offset(dev),
+ 0, &caddr, &paddr, &len);
+ if (!ret) {
+ plat->base = caddr;
+ plat->target = paddr;
+ plat->size = len;
+ }
+ } else {
+ u32 cell[3];
- plat->base = cell[0];
- plat->target = cell[1];
- plat->size = cell[2];
+ ret = dev_read_u32_array(dev, "ranges", cell,
+ ARRAY_SIZE(cell));
+ if (!ret) {
+ plat->base = cell[0];
+ plat->target = cell[1];
+ plat->size = cell[2];
+ }
}
return dm_scan_fdt_dev(dev);
diff --git a/drivers/core/simple-pm-bus.c b/drivers/core/simple-pm-bus.c
index 7a18953cba1..1bb0d86e289 100644
--- a/drivers/core/simple-pm-bus.c
+++ b/drivers/core/simple-pm-bus.c
@@ -21,7 +21,7 @@ static int simple_pm_bus_probe(struct udevice *dev)
return ret;
ret = clk_enable_bulk(bulk);
- if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ if (ret && ret != -ENOSYS) {
clk_release_bulk(bulk);
return ret;
}
@@ -34,7 +34,7 @@ static int simple_pm_bus_remove(struct udevice *dev)
struct clk_bulk *bulk = dev_get_priv(dev);
ret = clk_release_bulk(bulk);
- if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
+ if (ret && ret != -ENOSYS)
return ret;
else
return 0;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 1a4ea7a57a6..117d35ac49c 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -148,8 +148,11 @@ int uclass_get(enum uclass_id id, struct uclass **ucp)
*ucp = NULL;
uc = uclass_find(id);
- if (!uc)
+ if (!uc) {
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_INST))
+ return -ENOENT;
return uclass_add(id, ucp);
+ }
*ucp = uc;
return 0;
@@ -391,7 +394,7 @@ done:
return ret;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
const char *name, struct udevice **devp)
{
diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
index 5ed6140da35..1f5dfb94bb8 100644
--- a/drivers/crypto/fsl/Kconfig
+++ b/drivers/crypto/fsl/Kconfig
@@ -7,6 +7,12 @@ config FSL_CAAM
Module (CAAM), also known as the SEC version 4 (SEC4). The driver uses
Job Ring as interface to communicate with CAAM.
+config CAAM_64BIT
+ bool
+ default y if PHYS_64BIT && !ARCH_IMX8M
+ help
+ Select Crypto driver for 64 bits CAAM version
+
config SYS_FSL_HAS_SEC
bool
help
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
index a5e8d38e381..f9c3ccecfc2 100644
--- a/drivers/crypto/fsl/Makefile
+++ b/drivers/crypto/fsl/Makefile
@@ -4,7 +4,7 @@
obj-y += sec.o
obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
-obj-$(CONFIG_CMD_BLOB) += fsl_blob.o
-obj-$(CONFIG_CMD_DEKBLOB) += fsl_blob.o
+obj-$(CONFIG_CMD_BLOB)$(CONFIG_IMX_CAAM_DEK_ENCAP) += fsl_blob.o
obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
obj-$(CONFIG_FSL_CAAM_RNG) += rng.o
+obj-$(CONFIG_FSL_MFGPROT) += fsl_mfgprot.o
diff --git a/drivers/crypto/fsl/desc.h b/drivers/crypto/fsl/desc.h
index 3589e6ea024..5705c4f9447 100644
--- a/drivers/crypto/fsl/desc.h
+++ b/drivers/crypto/fsl/desc.h
@@ -11,6 +11,8 @@
#ifndef DESC_H
#define DESC_H
+#include "type.h"
+
#define KEY_BLOB_SIZE 32
#define MAC_SIZE 16
@@ -693,29 +695,29 @@
/* Structures for Protocol Data Blocks */
struct __packed pdb_ecdsa_verify {
uint32_t pdb_hdr;
- dma_addr_t dma_q; /* Pointer to q (elliptic curve) */
- dma_addr_t dma_r; /* Pointer to r (elliptic curve) */
- dma_addr_t dma_g_xy; /* Pointer to Gx,y (elliptic curve) */
- dma_addr_t dma_pkey; /* Pointer to Wx,y (public key) */
- dma_addr_t dma_hash; /* Pointer to hash input */
- dma_addr_t dma_c; /* Pointer to C_signature */
- dma_addr_t dma_d; /* Pointer to D_signature */
- dma_addr_t dma_buf; /* Pointer to 64-byte temp buffer */
- dma_addr_t dma_ab; /* Pointer to a,b (elliptic curve ) */
+ caam_dma_addr_t dma_q; /* Pointer to q (elliptic curve) */
+ caam_dma_addr_t dma_r; /* Pointer to r (elliptic curve) */
+ caam_dma_addr_t dma_g_xy; /* Pointer to Gx,y (elliptic curve) */
+ caam_dma_addr_t dma_pkey; /* Pointer to Wx,y (public key) */
+ caam_dma_addr_t dma_hash; /* Pointer to hash input */
+ caam_dma_addr_t dma_c; /* Pointer to C_signature */
+ caam_dma_addr_t dma_d; /* Pointer to D_signature */
+ caam_dma_addr_t dma_buf; /* Pointer to 64-byte temp buffer */
+ caam_dma_addr_t dma_ab; /* Pointer to a,b (elliptic curve ) */
uint32_t img_size; /* Length of Message */
};
struct __packed pdb_ecdsa_sign {
uint32_t pdb_hdr;
- dma_addr_t dma_q; /* Pointer to q (elliptic curve) */
- dma_addr_t dma_r; /* Pointer to r (elliptic curve) */
- dma_addr_t dma_g_xy; /* Pointer to Gx,y (elliptic curve) */
- dma_addr_t dma_pri_key; /* Pointer to S (Private key) */
- dma_addr_t dma_hash; /* Pointer to hash input */
- dma_addr_t dma_c; /* Pointer to C_signature */
- dma_addr_t dma_d; /* Pointer to D_signature */
- dma_addr_t dma_ab; /* Pointer to a,b (elliptic curve ) */
- dma_addr_t dma_u; /* Pointer to Per Message Random */
+ caam_dma_addr_t dma_q; /* Pointer to q (elliptic curve) */
+ caam_dma_addr_t dma_r; /* Pointer to r (elliptic curve) */
+ caam_dma_addr_t dma_g_xy; /* Pointer to Gx,y (elliptic curve) */
+ caam_dma_addr_t dma_pri_key; /* Pointer to S (Private key) */
+ caam_dma_addr_t dma_hash; /* Pointer to hash input */
+ caam_dma_addr_t dma_c; /* Pointer to C_signature */
+ caam_dma_addr_t dma_d; /* Pointer to D_signature */
+ caam_dma_addr_t dma_ab; /* Pointer to a,b (elliptic curve ) */
+ caam_dma_addr_t dma_u; /* Pointer to Per Message Random */
uint32_t img_size; /* Length of Message */
};
@@ -726,20 +728,21 @@ struct __packed pdb_ecdsa_sign {
struct __packed pdb_mp_pub_k {
uint32_t pdb_hdr;
#define PDB_MP_PUB_K_SGF_SHIFT 31
- dma_addr_t dma_pkey; /* Pointer to Wx,y (public key) */
+ caam_dma_addr_t dma_pkey; /* Pointer to Wx,y (public key) */
};
struct __packed pdb_mp_sign {
uint32_t pdb_hdr;
#define PDB_MP_SIGN_SGF_SHIFT 28
- dma_addr_t dma_addr_msg; /* Pointer to Message */
- dma_addr_t dma_addr_hash; /* Pointer to hash output */
- dma_addr_t dma_addr_c_sig; /* Pointer to C_signature */
- dma_addr_t dma_addr_d_sig; /* Pointer to D_signature */
+ caam_dma_addr_t dma_addr_msg; /* Pointer to Message */
+ caam_dma_addr_t dma_addr_hash; /* Pointer to hash output */
+ caam_dma_addr_t dma_addr_c_sig; /* Pointer to C_signature */
+ caam_dma_addr_t dma_addr_d_sig; /* Pointer to D_signature */
uint32_t img_size; /* Length of Message */
};
#define PDB_MP_CSEL_SHIFT 17
+#define PDB_MP_CSEL_WIDTH 4
#define PDB_MP_CSEL_P256 0x3 << PDB_MP_CSEL_SHIFT /* P-256 */
#define PDB_MP_CSEL_P384 0x4 << PDB_MP_CSEL_SHIFT /* P-384 */
#define PDB_MP_CSEL_P521 0x5 << PDB_MP_CSEL_SHIFT /* P-521 */
diff --git a/drivers/crypto/fsl/desc_constr.h b/drivers/crypto/fsl/desc_constr.h
index b82ba83e73a..209557c4ffa 100644
--- a/drivers/crypto/fsl/desc_constr.h
+++ b/drivers/crypto/fsl/desc_constr.h
@@ -12,7 +12,7 @@
#define IMMEDIATE (1 << 23)
#define CAAM_CMD_SZ sizeof(u32)
-#define CAAM_PTR_SZ sizeof(dma_addr_t)
+#define CAAM_PTR_SZ sizeof(caam_dma_addr_t)
#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE)
#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
@@ -35,7 +35,7 @@
LDST_SRCDST_WORD_DECOCTRL | \
(LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
struct ptr_addr_t {
#ifdef CONFIG_SYS_FSL_SEC_LE
u32 low;
@@ -49,9 +49,9 @@ struct ptr_addr_t {
};
#endif
-static inline void pdb_add_ptr(dma_addr_t *offset, dma_addr_t ptr)
+static inline void pdb_add_ptr(caam_dma_addr_t *offset, caam_dma_addr_t ptr)
{
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
/* The Position of low and high part of 64 bit address
* will depend on the endianness of CAAM Block */
struct ptr_addr_t *ptr_addr = (struct ptr_addr_t *)offset;
@@ -102,11 +102,11 @@ static inline void init_job_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes)
options);
}
-static inline void append_ptr(u32 *desc, dma_addr_t ptr)
+static inline void append_ptr(u32 *desc, caam_dma_addr_t ptr)
{
- dma_addr_t *offset = (dma_addr_t *)desc_end(desc);
+ caam_dma_addr_t *offset = (caam_dma_addr_t *)desc_end(desc);
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
/* The Position of low and high part of 64 bit address
* will depend on the endianness of CAAM Block */
struct ptr_addr_t *ptr_addr = (struct ptr_addr_t *)offset;
@@ -159,7 +159,7 @@ static inline u32 *write_cmd(u32 *desc, u32 command)
return desc + 1;
}
-static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
+static inline void append_cmd_ptr(u32 *desc, caam_dma_addr_t ptr, int len,
u32 command)
{
append_cmd(desc, command | len);
@@ -167,7 +167,7 @@ static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
}
/* Write length after pointer, rather than inside command */
-static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr,
+static inline void append_cmd_ptr_extlen(u32 *desc, caam_dma_addr_t ptr,
unsigned int len, u32 command)
{
append_cmd(desc, command);
@@ -225,7 +225,7 @@ APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD)
APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE)
#define APPEND_CMD_PTR(cmd, op) \
-static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \
+static inline void append_##cmd(u32 *desc, caam_dma_addr_t ptr, unsigned int len, \
u32 options) \
{ \
PRINT_POS; \
@@ -236,7 +236,7 @@ APPEND_CMD_PTR(load, LOAD)
APPEND_CMD_PTR(fifo_load, FIFO_LOAD)
APPEND_CMD_PTR(fifo_store, FIFO_STORE)
-static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len,
+static inline void append_store(u32 *desc, caam_dma_addr_t ptr, unsigned int len,
u32 options)
{
u32 cmd_src;
@@ -254,7 +254,7 @@ static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len,
}
#define APPEND_SEQ_PTR_INTLEN(cmd, op) \
-static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \
+static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, caam_dma_addr_t ptr, \
unsigned int len, \
u32 options) \
{ \
@@ -278,7 +278,7 @@ APPEND_CMD_PTR_TO_IMM(load, LOAD);
APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD);
#define APPEND_CMD_PTR_EXTLEN(cmd, op) \
-static inline void append_##cmd##_extlen(u32 *desc, dma_addr_t ptr, \
+static inline void append_##cmd##_extlen(u32 *desc, caam_dma_addr_t ptr, \
unsigned int len, u32 options) \
{ \
PRINT_POS; \
@@ -292,7 +292,7 @@ APPEND_CMD_PTR_EXTLEN(seq_out_ptr, SEQ_OUT_PTR)
* the size of its type
*/
#define APPEND_CMD_PTR_LEN(cmd, op, type) \
-static inline void append_##cmd(u32 *desc, dma_addr_t ptr, \
+static inline void append_##cmd(u32 *desc, caam_dma_addr_t ptr, \
type len, u32 options) \
{ \
PRINT_POS; \
diff --git a/drivers/crypto/fsl/fsl_blob.c b/drivers/crypto/fsl/fsl_blob.c
index d6bd861251e..e8202cc5697 100644
--- a/drivers/crypto/fsl/fsl_blob.c
+++ b/drivers/crypto/fsl/fsl_blob.c
@@ -65,6 +65,9 @@ int blob_decap(u8 *key_mod, u8 *src, u8 *dst, u32 len)
flush_dcache_range((unsigned long)desc,
(unsigned long)desc + size);
+ flush_dcache_range((unsigned long)dst,
+ (unsigned long)dst + size);
+
ret = run_descriptor_jr(desc);
if (ret) {
@@ -130,6 +133,9 @@ int blob_encap(u8 *key_mod, u8 *src, u8 *dst, u32 len)
flush_dcache_range((unsigned long)desc,
(unsigned long)desc + size);
+ flush_dcache_range((unsigned long)dst,
+ (unsigned long)dst + size);
+
ret = run_descriptor_jr(desc);
if (ret) {
diff --git a/drivers/crypto/fsl/fsl_hash.c b/drivers/crypto/fsl/fsl_hash.c
index 61f953e8a6d..8b5c26db070 100644
--- a/drivers/crypto/fsl/fsl_hash.c
+++ b/drivers/crypto/fsl/fsl_hash.c
@@ -87,7 +87,7 @@ static int caam_hash_update(void *hash_ctx, const void *buf,
enum caam_hash_algos caam_algo)
{
uint32_t final;
- phys_addr_t addr = virt_to_phys((void *)buf);
+ caam_dma_addr_t addr = virt_to_phys((void *)buf);
struct sha_ctx *ctx = hash_ctx;
if (ctx->sg_num >= MAX_SG_32) {
@@ -95,12 +95,12 @@ static int caam_hash_update(void *hash_ctx, const void *buf,
return -EINVAL;
}
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi, (uint32_t)(addr >> 32));
#else
sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi, 0x0);
#endif
- sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_lo, (uint32_t)addr);
+ sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_lo, (caam_dma_addr_t)addr);
sec_out32(&ctx->sg_tbl[ctx->sg_num].len_flag,
(size & SG_ENTRY_LENGTH_MASK));
diff --git a/drivers/crypto/fsl/fsl_mfgprot.c b/drivers/crypto/fsl/fsl_mfgprot.c
new file mode 100644
index 00000000000..29af79f577d
--- /dev/null
+++ b/drivers/crypto/fsl/fsl_mfgprot.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fsl_sec.h>
+#include <memalign.h>
+#include "desc.h"
+#include "desc_constr.h"
+#include "jobdesc.h"
+#include "jr.h"
+
+/* Size of MFG descriptor */
+#define MFG_PUBK_DSC_WORDS 4
+#define MFG_SIGN_DSC_WORDS 8
+
+static void mfg_build_sign_dsc(u32 *dsc_ptr, const u8 *m, int size,
+ u8 *dgst, u8 *c, u8 *d)
+{
+ u32 *dsc = dsc_ptr;
+ struct pdb_mp_sign *pdb;
+
+ init_job_desc_pdb(dsc, 0, sizeof(struct pdb_mp_sign));
+
+ pdb = (struct pdb_mp_sign *)desc_pdb(dsc);
+
+ /* Curve */
+ pdb->pdb_hdr = (PDB_MP_CSEL_P256);
+
+ /* Message Pointer */
+ pdb_add_ptr(&pdb->dma_addr_msg, virt_to_phys((void *)m));
+
+ /* mes-resp Pointer */
+ pdb_add_ptr(&pdb->dma_addr_hash, virt_to_phys((void *)dgst));
+
+ /* C Pointer */
+ pdb_add_ptr(&pdb->dma_addr_c_sig, virt_to_phys((void *)c));
+
+ /* d Pointer */
+ pdb_add_ptr(&pdb->dma_addr_d_sig, virt_to_phys((void *)d));
+
+ /* Message Size */
+ pdb->img_size = size;
+
+ /* MP PubK generate key command */
+ append_cmd(dsc, (CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL |
+ OP_PCLID_MP_SIGN));
+}
+
+static void mfg_build_pubk_dsc(u32 *dsc_ptr, u8 *dst)
+{
+ u32 *dsc = dsc_ptr;
+ struct pdb_mp_pub_k *pdb;
+
+ init_job_desc_pdb(dsc, 0, sizeof(struct pdb_mp_pub_k));
+
+ pdb = (struct pdb_mp_pub_k *)desc_pdb(dsc);
+
+ /* Curve */
+ pdb->pdb_hdr = (PDB_MP_CSEL_P256);
+
+ /* Message Pointer */
+ pdb_add_ptr(&pdb->dma_pkey, virt_to_phys((void *)dst));
+
+ /* MP Sign key command */
+ append_cmd(dsc, (CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL |
+ OP_PCLID_MP_PUB_KEY));
+}
+
+int gen_mppubk(u8 *dst)
+{
+ int size, ret;
+ u32 *dsc;
+
+ /* Job Descriptor initialization */
+ dsc = memalign(ARCH_DMA_MINALIGN,
+ sizeof(uint32_t) * MFG_PUBK_DSC_WORDS);
+ if (!dsc) {
+ debug("Not enough memory for descriptor allocation\n");
+ return -ENOMEM;
+ }
+
+ mfg_build_pubk_dsc(dsc, dst);
+
+ size = roundup(sizeof(uint32_t) * MFG_PUBK_DSC_WORDS,
+ ARCH_DMA_MINALIGN);
+ flush_dcache_range((unsigned long)dsc, (unsigned long)dsc + size);
+
+ size = roundup(FSL_CAAM_MP_PUBK_BYTES, ARCH_DMA_MINALIGN);
+ flush_dcache_range((unsigned long)dst, (unsigned long)dst + size);
+
+ /* Execute Job Descriptor */
+ puts("\nGenerating Manufacturing Protection Public Key\n");
+
+ ret = run_descriptor_jr(dsc);
+ if (ret) {
+ debug("Error in public key generation %d\n", ret);
+ goto err;
+ }
+
+ size = roundup(FSL_CAAM_MP_PUBK_BYTES, ARCH_DMA_MINALIGN);
+ invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + size);
+err:
+ free(dsc);
+ return ret;
+}
+
+int sign_mppubk(const u8 *m, int data_size, u8 *dgst, u8 *c, u8 *d)
+{
+ int size, ret;
+ u32 *dsc;
+
+ /* Job Descriptor initialization */
+ dsc = memalign(ARCH_DMA_MINALIGN,
+ sizeof(uint32_t) * MFG_SIGN_DSC_WORDS);
+ if (!dsc) {
+ debug("Not enough memory for descriptor allocation\n");
+ return -ENOMEM;
+ }
+
+ mfg_build_sign_dsc(dsc, m, data_size, dgst, c, d);
+
+ size = roundup(sizeof(uint32_t) * MFG_SIGN_DSC_WORDS,
+ ARCH_DMA_MINALIGN);
+ flush_dcache_range((unsigned long)dsc, (unsigned long)dsc + size);
+
+ size = roundup(data_size, ARCH_DMA_MINALIGN);
+ flush_dcache_range((unsigned long)m, (unsigned long)m + size);
+
+ size = roundup(FSL_CAAM_MP_MES_DGST_BYTES, ARCH_DMA_MINALIGN);
+ flush_dcache_range((unsigned long)dgst, (unsigned long)dgst + size);
+
+ size = roundup(FSL_CAAM_MP_PRVK_BYTES, ARCH_DMA_MINALIGN);
+ flush_dcache_range((unsigned long)c, (unsigned long)c + size);
+ flush_dcache_range((unsigned long)d, (unsigned long)d + size);
+
+ /* Execute Job Descriptor */
+ puts("\nSigning message with Manufacturing Protection Private Key\n");
+
+ ret = run_descriptor_jr(dsc);
+ if (ret) {
+ debug("Error in public key generation %d\n", ret);
+ goto err;
+ }
+
+ size = roundup(FSL_CAAM_MP_MES_DGST_BYTES, ARCH_DMA_MINALIGN);
+ invalidate_dcache_range((unsigned long)dgst,
+ (unsigned long)dgst + size);
+
+ size = roundup(FSL_CAAM_MP_PRVK_BYTES, ARCH_DMA_MINALIGN);
+ invalidate_dcache_range((unsigned long)c, (unsigned long)c + size);
+ invalidate_dcache_range((unsigned long)d, (unsigned long)d + size);
+
+err:
+ free(dsc);
+ return ret;
+}
diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c
index fbc1aeddeeb..d2354155318 100644
--- a/drivers/crypto/fsl/jobdesc.c
+++ b/drivers/crypto/fsl/jobdesc.c
@@ -4,6 +4,7 @@
* Basic job descriptor construction
*
* Copyright 2014 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
*
*/
@@ -15,7 +16,8 @@
#include "rsa_caam.h"
#include <asm/cache.h>
-#if defined(CONFIG_MX6) || defined(CONFIG_MX7)
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7) || defined(CONFIG_MX7ULP) || \
+ defined(CONFIG_IMX8M)
/*!
* Secure memory run command
*
@@ -163,9 +165,9 @@ int inline_cnstr_jobdesc_blob_dek(uint32_t *desc, const uint8_t *plain_txt,
append_u32(desc, aad_w2);
- append_cmd_ptr(desc, (dma_addr_t)SEC_MEM_PAGE1, in_sz, CMD_SEQ_IN_PTR);
+ append_cmd_ptr(desc, (caam_dma_addr_t)SEC_MEM_PAGE1, in_sz, CMD_SEQ_IN_PTR);
- append_cmd_ptr(desc, (dma_addr_t)dek_blob + 8, out_sz, CMD_SEQ_OUT_PTR);
+ append_cmd_ptr(desc, (caam_dma_addr_t)(ulong)(dek_blob + 8), out_sz, CMD_SEQ_OUT_PTR);
append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB |
OP_PCLID_SECMEM);
@@ -181,7 +183,7 @@ void inline_cnstr_jobdesc_hash(uint32_t *desc,
/* SHA 256 , output is of length 32 words */
uint32_t storelen = alg_size;
u32 options;
- dma_addr_t dma_addr_in, dma_addr_out;
+ caam_dma_addr_t dma_addr_in, dma_addr_out;
dma_addr_in = virt_to_phys((void *)msg);
dma_addr_out = virt_to_phys((void *)digest);
@@ -210,7 +212,7 @@ void inline_cnstr_jobdesc_blob_encap(uint32_t *desc, uint8_t *key_idnfr,
uint8_t *plain_txt, uint8_t *enc_blob,
uint32_t in_sz)
{
- dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
+ caam_dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
/* output blob will have 32 bytes key blob in beginning and
* 16 byte HMAC identifier at end of data blob */
@@ -235,7 +237,7 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
uint8_t *enc_blob, uint8_t *plain_txt,
uint32_t out_sz)
{
- dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
+ caam_dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
uint32_t in_sz = out_sz + KEY_BLOB_SIZE + MAC_SIZE;
@@ -311,7 +313,7 @@ void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
struct pk_in_params *pkin, uint8_t *out,
uint32_t out_siz)
{
- dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out;
+ caam_dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out;
dma_addr_e = virt_to_phys((void *)pkin->e);
dma_addr_a = virt_to_phys((void *)pkin->a);
diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c
index 44273c345f9..22b649219e8 100644
--- a/drivers/crypto/fsl/jr.c
+++ b/drivers/crypto/fsl/jr.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2008-2014 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
*
* Based on CAAM driver in drivers/crypto/caam in Linux
*/
@@ -21,6 +22,7 @@
#include <asm/fsl_pamu.h>
#endif
#include <dm/lists.h>
+#include <linux/delay.h>
#define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1))
#define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size))
@@ -34,10 +36,10 @@ uint32_t sec_offset[CONFIG_SYS_FSL_MAX_NUM_OF_SEC] = {
};
#define SEC_ADDR(idx) \
- ((CONFIG_SYS_FSL_SEC_ADDR + sec_offset[idx]))
+ (ulong)((CONFIG_SYS_FSL_SEC_ADDR + sec_offset[idx]))
#define SEC_JR0_ADDR(idx) \
- (SEC_ADDR(idx) + \
+ (ulong)(SEC_ADDR(idx) + \
(CONFIG_SYS_FSL_JR0_OFFSET - CONFIG_SYS_FSL_SEC_OFFSET))
struct jobring jr0[CONFIG_SYS_FSL_MAX_NUM_OF_SEC];
@@ -82,16 +84,16 @@ static void jr_initregs(uint8_t sec_idx)
{
struct jr_regs *regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx);
struct jobring *jr = &jr0[sec_idx];
- phys_addr_t ip_base = virt_to_phys((void *)jr->input_ring);
- phys_addr_t op_base = virt_to_phys((void *)jr->output_ring);
+ caam_dma_addr_t ip_base = virt_to_phys((void *)jr->input_ring);
+ caam_dma_addr_t op_base = virt_to_phys((void *)jr->output_ring);
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
sec_out32(&regs->irba_h, ip_base >> 32);
#else
sec_out32(&regs->irba_h, 0x0);
#endif
sec_out32(&regs->irba_l, (uint32_t)ip_base);
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
sec_out32(&regs->orba_h, op_base >> 32);
#else
sec_out32(&regs->orba_h, 0x0);
@@ -117,8 +119,8 @@ static int jr_init(uint8_t sec_idx)
jr->liodn = DEFAULT_JR_LIODN;
#endif
jr->size = JR_SIZE;
- jr->input_ring = (dma_addr_t *)memalign(ARCH_DMA_MINALIGN,
- JR_SIZE * sizeof(dma_addr_t));
+ jr->input_ring = (caam_dma_addr_t *)memalign(ARCH_DMA_MINALIGN,
+ JR_SIZE * sizeof(caam_dma_addr_t));
if (!jr->input_ring)
return -1;
@@ -129,7 +131,7 @@ static int jr_init(uint8_t sec_idx)
if (!jr->output_ring)
return -1;
- memset(jr->input_ring, 0, JR_SIZE * sizeof(dma_addr_t));
+ memset(jr->input_ring, 0, JR_SIZE * sizeof(caam_dma_addr_t));
memset(jr->output_ring, 0, jr->op_size);
start_jr0(sec_idx);
@@ -148,7 +150,7 @@ static int jr_sw_cleanup(uint8_t sec_idx)
jr->read_idx = 0;
jr->write_idx = 0;
memset(jr->info, 0, sizeof(jr->info));
- memset(jr->input_ring, 0, jr->size * sizeof(dma_addr_t));
+ memset(jr->input_ring, 0, jr->size * sizeof(caam_dma_addr_t));
memset(jr->output_ring, 0, jr->size * sizeof(struct op_ring));
return 0;
@@ -194,7 +196,7 @@ static int jr_enqueue(uint32_t *desc_addr,
uint32_t desc_word;
int length = desc_len(desc_addr);
int i;
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
uint32_t *addr_hi, *addr_lo;
#endif
@@ -208,7 +210,7 @@ static int jr_enqueue(uint32_t *desc_addr,
sec_out32((uint32_t *)&desc_addr[i], desc_word);
}
- phys_addr_t desc_phys_addr = virt_to_phys(desc_addr);
+ caam_dma_addr_t desc_phys_addr = virt_to_phys(desc_addr);
jr->info[head].desc_phys_addr = desc_phys_addr;
jr->info[head].callback = (void *)callback;
@@ -221,7 +223,7 @@ static int jr_enqueue(uint32_t *desc_addr,
sizeof(struct jr_info), ARCH_DMA_MINALIGN);
flush_dcache_range(start, end);
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
/* Write the 64 bit Descriptor address on Input Ring.
* The 32 bit hign and low part of the address will
* depend on endianness of SEC block.
@@ -240,11 +242,11 @@ static int jr_enqueue(uint32_t *desc_addr,
#else
/* Write the 32 bit Descriptor address on Input Ring. */
sec_out32(&jr->input_ring[head], desc_phys_addr);
-#endif /* ifdef CONFIG_PHYS_64BIT */
+#endif /* ifdef CONFIG_CAAM_64BIT */
start = (unsigned long)&jr->input_ring[head] & ~(ARCH_DMA_MINALIGN - 1);
end = ALIGN((unsigned long)&jr->input_ring[head] +
- sizeof(dma_addr_t), ARCH_DMA_MINALIGN);
+ sizeof(caam_dma_addr_t), ARCH_DMA_MINALIGN);
flush_dcache_range(start, end);
jr->head = (head + 1) & (jr->size - 1);
@@ -270,7 +272,7 @@ static int jr_dequeue(int sec_idx)
int idx, i, found;
void (*callback)(uint32_t status, void *arg);
void *arg = NULL;
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
uint32_t *addr_hi, *addr_lo;
#else
uint32_t *addr;
@@ -281,8 +283,8 @@ static int jr_dequeue(int sec_idx)
found = 0;
- phys_addr_t op_desc;
- #ifdef CONFIG_PHYS_64BIT
+ caam_dma_addr_t op_desc;
+ #ifdef CONFIG_CAAM_64BIT
/* Read the 64 bit Descriptor address from Output Ring.
* The 32 bit hign and low part of the address will
* depend on endianness of SEC block.
@@ -302,7 +304,7 @@ static int jr_dequeue(int sec_idx)
/* Read the 32 bit Descriptor address from Output Ring. */
addr = (uint32_t *)&jr->output_ring[jr->tail].desc;
op_desc = sec_in32(addr);
- #endif /* ifdef CONFIG_PHYS_64BIT */
+ #endif /* ifdef CONFIG_CAAM_64BIT */
uint32_t status = sec_in32(&jr->output_ring[jr->tail].status);
@@ -355,8 +357,8 @@ static void desc_done(uint32_t status, void *arg)
static inline int run_descriptor_jr_idx(uint32_t *desc, uint8_t sec_idx)
{
- unsigned long long timeval = get_ticks();
- unsigned long long timeout = usec2ticks(CONFIG_SEC_DEQ_TIMEOUT);
+ unsigned long long timeval = 0;
+ unsigned long long timeout = CONFIG_USEC_DEQ_TIMEOUT;
struct result op;
int ret = 0;
@@ -369,9 +371,10 @@ static inline int run_descriptor_jr_idx(uint32_t *desc, uint8_t sec_idx)
goto out;
}
- timeval = get_ticks();
- timeout = usec2ticks(CONFIG_SEC_DEQ_TIMEOUT);
while (op.done != 1) {
+ udelay(1);
+ timeval += 1;
+
ret = jr_dequeue(sec_idx);
if (ret) {
debug("Error in SEC deq\n");
@@ -379,7 +382,7 @@ static inline int run_descriptor_jr_idx(uint32_t *desc, uint8_t sec_idx)
goto out;
}
- if ((get_ticks() - timeval) > timeout) {
+ if (timeval > timeout) {
debug("SEC Dequeue timed out\n");
ret = JQ_DEQ_TO_ERR;
goto out;
@@ -675,7 +678,7 @@ int sec_init_idx(uint8_t sec_idx)
mcr = (mcr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT);
#endif
-#ifdef CONFIG_PHYS_64BIT
+#ifdef CONFIG_CAAM_64BIT
mcr |= (1 << MCFGR_PS_SHIFT);
#endif
sec_out32(&sec->mcfgr, mcr);
diff --git a/drivers/crypto/fsl/jr.h b/drivers/crypto/fsl/jr.h
index ffd3a192738..1047aa772c4 100644
--- a/drivers/crypto/fsl/jr.h
+++ b/drivers/crypto/fsl/jr.h
@@ -8,10 +8,11 @@
#define __JR_H
#include <linux/compiler.h>
+#include "type.h"
#define JR_SIZE 4
-/* Timeout currently defined as 90 sec */
-#define CONFIG_SEC_DEQ_TIMEOUT 90000000U
+/* Timeout currently defined as 10 sec */
+#define CONFIG_USEC_DEQ_TIMEOUT 10000000U
#define DEFAULT_JR_ID 0
#define DEFAULT_JR_LIODN 0
@@ -41,13 +42,13 @@
#define RNG4_MAX_HANDLES 2
struct op_ring {
- phys_addr_t desc;
+ caam_dma_addr_t desc;
uint32_t status;
} __packed;
struct jr_info {
void (*callback)(uint32_t status, void *arg);
- phys_addr_t desc_phys_addr;
+ caam_dma_addr_t desc_phys_addr;
uint32_t desc_len;
uint32_t op_done;
void *arg;
@@ -83,7 +84,7 @@ struct jobring {
* by SEC
*/
/*Circular Ring of i/p descriptors */
- dma_addr_t *input_ring;
+ caam_dma_addr_t *input_ring;
/* Circular Ring of o/p descriptors */
/* Circula Ring containing info regarding descriptors in i/p
* and o/p ring
diff --git a/drivers/crypto/fsl/type.h b/drivers/crypto/fsl/type.h
new file mode 100644
index 00000000000..b7031a60fdd
--- /dev/null
+++ b/drivers/crypto/fsl/type.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ *
+ */
+
+#ifndef CRYPTO_FSL_TYPE_H
+#define CRYPTO_FSL_TYPE_H
+
+#ifdef CONFIG_CAAM_64BIT
+typedef unsigned long long caam_dma_addr_t;
+#else
+typedef u32 caam_dma_addr_t;
+#endif
+
+#endif
diff --git a/drivers/ddr/fsl/Kconfig b/drivers/ddr/fsl/Kconfig
index 5f62489a90f..8b480dfd690 100644
--- a/drivers/ddr/fsl/Kconfig
+++ b/drivers/ddr/fsl/Kconfig
@@ -44,7 +44,6 @@ config SYS_NUM_DDR_CTLRS
ARCH_MPC8572 || \
ARCH_MPC8641 || \
ARCH_P4080 || \
- ARCH_P5020 || \
ARCH_P5040 || \
ARCH_LX2160A || \
ARCH_LX2162A || \
diff --git a/drivers/ddr/imx/imx8m/Kconfig b/drivers/ddr/imx/imx8m/Kconfig
index a5f5524fbec..a90b7db4940 100644
--- a/drivers/ddr/imx/imx8m/Kconfig
+++ b/drivers/ddr/imx/imx8m/Kconfig
@@ -36,4 +36,12 @@ config IMX8M_DRAM_INLINE_ECC
help
Select this config if you want to use inline ecc feature for
imx8mp-evk board.
+
+config IMX8M_VDD_SOC_850MV
+ bool "imx8mp change the vdd_soc voltage to 850mv"
+ depends on IMX8MP
+
+config IMX8M_LPDDR4_FREQ0_2400MTS
+ bool "imx8m PDDR4 freq0 change from 4000MTS to 2400MTS"
+
endmenu
diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c
index 76b629a334f..8f8c4259772 100644
--- a/drivers/dfu/dfu_sf.c
+++ b/drivers/dfu/dfu_sf.c
@@ -87,7 +87,23 @@ static unsigned int dfu_polltimeout_sf(struct dfu_entity *dfu)
static void dfu_free_entity_sf(struct dfu_entity *dfu)
{
- spi_flash_free(dfu->data.sf.dev);
+ /*
+ * In the DM case it is not necessary to free the SPI device.
+ * For the non-DM case we must ensure that the the SPI device is only
+ * freed once.
+ */
+ if (!CONFIG_IS_ENABLED(DM_SPI_FLASH)) {
+ struct spi_flash *dev = dfu->data.sf.dev;
+
+ if (!dev)
+ return;
+ dfu->data.sf.dev = NULL;
+ list_for_each_entry(dfu, &dfu_list, list) {
+ if (dfu->data.sf.dev == dev)
+ dfu->data.sf.dev = NULL;
+ }
+ spi_flash_free(dev);
+ }
}
static struct spi_flash *parse_dev(char *devstr)
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index 8e74e50e918..2f3837e5591 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -40,7 +40,7 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
/* check for raw partition descriptor */
strcpy(env_desc_name, "fastboot_raw_partition_");
- strncat(env_desc_name, name, PART_NAME_LEN);
+ strlcat(env_desc_name, name, PART_NAME_LEN);
raw_part_desc = strdup(env_get(env_desc_name));
if (raw_part_desc == NULL)
return -ENODEV;
@@ -61,7 +61,7 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
info->start = simple_strtoul(argv[0], NULL, 0);
info->size = simple_strtoul(argv[1], NULL, 0);
info->blksz = dev_desc->blksz;
- strncpy((char *)info->name, name, PART_NAME_LEN);
+ strlcpy((char *)info->name, name, PART_NAME_LEN);
if (raw_part_desc) {
if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0) {
@@ -114,7 +114,7 @@ static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc,
/* check for alias */
strcpy(env_alias_name, "fastboot_partition_alias_");
- strncat(env_alias_name, name, PART_NAME_LEN);
+ strlcat(env_alias_name, name, PART_NAME_LEN);
aliased_part_name = env_get(env_alias_name);
if (aliased_part_name != NULL)
ret = do_get_part_info(dev_desc, aliased_part_name,
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
index 97a5dace15f..4b968205c2f 100644
--- a/drivers/firmware/scmi/sandbox-scmi_agent.c
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -20,17 +20,18 @@
* processing. It simulates few of the SCMI services for some of the
* SCMI protocols embedded in U-Boot. Currently:
* - SCMI clock protocol: emulate 2 agents each exposing few clocks
- * - SCMI reset protocol: emulate 1 agents each exposing a reset
+ * - SCMI reset protocol: emulate 1 agent exposing a reset controller
+ * - SCMI voltage domain protocol: emulate 1 agent exposing 2 regulators
*
- * Agent #0 simulates 2 clocks and 1 reset domain.
+ * Agent #0 simulates 2 clocks, 1 reset domain and 1 voltage domain.
* See IDs in scmi0_clk[]/scmi0_reset[] and "sandbox-scmi-agent@0" in test.dts.
*
* Agent #1 simulates 1 clock.
* See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts.
*
- * All clocks are default disabled and reset levels down.
+ * All clocks and regulators are default disabled and reset controller down.
*
- * This Driver exports sandbox_scmi_service_ct() for the test sequence to
+ * This Driver exports sandbox_scmi_service_ctx() for the test sequence to
* get the state of the simulated services (clock state, rate, ...) and
* check back-end device state reflects the request send through the
* various uclass devices, as clocks and reset controllers.
@@ -47,6 +48,11 @@ static struct sandbox_scmi_reset scmi0_reset[] = {
{ .id = 3 },
};
+static struct sandbox_scmi_voltd scmi0_voltd[] = {
+ { .id = 0, .voltage_uv = 3300000 },
+ { .id = 1, .voltage_uv = 1800000 },
+};
+
static struct sandbox_scmi_clk scmi1_clk[] = {
{ .id = 1, .rate = 44 },
};
@@ -83,6 +89,13 @@ static void debug_print_agent_state(struct udevice *dev, char *str)
agent->reset_count,
agent->reset_count ? agent->reset[0].asserted : -1,
agent->reset_count > 1 ? agent->reset[1].asserted : -1);
+ dev_dbg(dev, " scmi%u_voltd (%zu): %u/%d, %u/%d, ...\n",
+ agent->idx,
+ agent->voltd_count,
+ agent->voltd_count ? agent->voltd[0].enabled : -1,
+ agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
+ agent->voltd_count ? agent->voltd[1].enabled : -1,
+ agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
};
static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id)
@@ -125,6 +138,20 @@ static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id,
return NULL;
}
+static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint agent_id,
+ uint domain_id)
+{
+ size_t n;
+
+ if (agent_id == 0) {
+ for (n = 0; n < ARRAY_SIZE(scmi0_voltd); n++)
+ if (scmi0_voltd[n].id == domain_id)
+ return scmi0_voltd + n;
+ }
+
+ return NULL;
+}
+
/*
* Sandbox SCMI agent ops
*/
@@ -292,6 +319,160 @@ static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
return 0;
}
+static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_attr_in *in = NULL;
+ struct scmi_voltd_attr_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_attr_in *)msg->in_msg;
+ out = (struct scmi_voltd_attr_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ memset(out, 0, sizeof(*out));
+ snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_config_set(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_config_set_in *in = NULL;
+ struct scmi_voltd_config_set_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_config_set_in *)msg->in_msg;
+ out = (struct scmi_voltd_config_set_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
+ dev_err(dev, "Invalid config value 0x%x\n", in->config);
+
+ out->status = SCMI_INVALID_PARAMETERS;
+ } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
+ in->config != SCMI_VOLTD_CONFIG_OFF) {
+ dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
+
+ out->status = SCMI_INVALID_PARAMETERS;
+ } else {
+ voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_config_get(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_config_get_in *in = NULL;
+ struct scmi_voltd_config_get_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_config_get_in *)msg->in_msg;
+ out = (struct scmi_voltd_config_get_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ if (voltd_state->enabled)
+ out->config = SCMI_VOLTD_CONFIG_ON;
+ else
+ out->config = SCMI_VOLTD_CONFIG_OFF;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_level_set(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_level_set_in *in = NULL;
+ struct scmi_voltd_level_set_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_level_set_in *)msg->in_msg;
+ out = (struct scmi_voltd_level_set_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ voltd_state->voltage_uv = in->voltage_level;
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_level_get(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_level_get_in *in = NULL;
+ struct scmi_voltd_level_get_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_level_get_in *)msg->in_msg;
+ out = (struct scmi_voltd_level_get_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ out->voltage_level = voltd_state->voltage_uv;
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
static int sandbox_scmi_test_process_msg(struct udevice *dev,
struct scmi_msg *msg)
{
@@ -318,6 +499,22 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
break;
}
break;
+ case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ switch (msg->message_id) {
+ case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
+ return sandbox_scmi_voltd_attribs(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
+ return sandbox_scmi_voltd_config_set(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
+ return sandbox_scmi_voltd_config_get(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
+ return sandbox_scmi_voltd_level_set(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
+ return sandbox_scmi_voltd_level_get(dev, msg);
+ default:
+ break;
+ }
+ break;
case SCMI_PROTOCOL_ID_BASE:
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
case SCMI_PROTOCOL_ID_SYSTEM:
@@ -369,6 +566,8 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
.clk_count = ARRAY_SIZE(scmi0_clk),
.reset = scmi0_reset,
.reset_count = ARRAY_SIZE(scmi0_reset),
+ .voltd = scmi0_voltd,
+ .voltd_count = ARRAY_SIZE(scmi0_voltd),
};
break;
case '1':
diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c
index 69239a198f0..66a67928817 100644
--- a/drivers/firmware/scmi/sandbox-scmi_devices.c
+++ b/drivers/firmware/scmi/sandbox-scmi_devices.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2020, Linaro Limited
+ * Copyright (C) 2020-2021, Linaro Limited
*/
#define LOG_CATEGORY UCLASS_MISC
@@ -8,11 +8,13 @@
#include <common.h>
#include <clk.h>
#include <dm.h>
+#include <log.h>
#include <malloc.h>
#include <reset.h>
#include <asm/io.h>
#include <asm/scmi_test.h>
#include <dm/device_compat.h>
+#include <power/regulator.h>
/*
* Simulate to some extent a SCMI exchange.
@@ -23,16 +25,19 @@
#define SCMI_TEST_DEVICES_CLK_COUNT 3
#define SCMI_TEST_DEVICES_RD_COUNT 1
+#define SCMI_TEST_DEVICES_VOLTD_COUNT 2
/*
* struct sandbox_scmi_device_priv - Storage for device handles used by test
* @clk: Array of clock instances used by tests
* @reset_clt: Array of the reset controller instances used by tests
+ * @regulators: Array of regulator device references used by the tests
* @devices: Resources exposed by sandbox_scmi_devices_ctx()
*/
struct sandbox_scmi_device_priv {
struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
+ struct udevice *regulators[SCMI_TEST_DEVICES_VOLTD_COUNT];
struct sandbox_scmi_devices devices;
};
@@ -76,6 +81,8 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
.clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
.reset = priv->reset_ctl,
.reset_count = SCMI_TEST_DEVICES_RD_COUNT,
+ .regul = priv->regulators,
+ .regul_count = SCMI_TEST_DEVICES_VOLTD_COUNT,
};
for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
@@ -94,8 +101,24 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
}
}
+ for (n = 0; n < SCMI_TEST_DEVICES_VOLTD_COUNT; n++) {
+ char name[32];
+
+ ret = snprintf(name, sizeof(name), "regul%zu-supply", n);
+ assert(ret >= 0 && ret < sizeof(name));
+
+ ret = device_get_supply_regulator(dev, name,
+ priv->devices.regul + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on voltd %zu\n", __func__, n);
+ goto err_regul;
+ }
+ }
+
return 0;
+err_regul:
+ n = SCMI_TEST_DEVICES_RD_COUNT;
err_reset:
for (; n > 0; n--)
reset_free(priv->devices.reset + n - 1);
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 527163b5ce3..4f5870b4838 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -80,6 +80,16 @@ static int scmi_bind_protocols(struct udevice *dev)
if (IS_ENABLED(CONFIG_RESET_SCMI))
drv = DM_DRIVER_GET(scmi_reset_domain);
break;
+ case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
+ node = ofnode_find_subnode(node, "regulators");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "no regulators node\n");
+ return -ENXIO;
+ }
+ drv = DM_DRIVER_GET(scmi_voltage_domain);
+ }
+ break;
default:
break;
}
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
index 60b9d499b79..f1915c00741 100644
--- a/drivers/firmware/scmi/smt.c
+++ b/drivers/firmware/scmi/smt.c
@@ -41,8 +41,13 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
if (ret)
return ret;
- faddr = cpu_to_fdt32(resource.start);
- paddr = ofnode_translate_address(args.node, &faddr);
+ /* TEMP workaround for ofnode_read_resource translation issue */
+ if (of_live_active()) {
+ paddr = resource.start;
+ } else {
+ faddr = cpu_to_fdt32(resource.start);
+ paddr = ofnode_translate_address(args.node, &faddr);
+ }
smt->size = resource_size(&resource);
if (smt->size < sizeof(struct scmi_smt_header)) {
@@ -56,8 +61,10 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
#ifdef CONFIG_ARM
if (dcache_status())
- mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,
- smt->size, DCACHE_OFF);
+ mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, MMU_SECTION_SIZE),
+ ALIGN(smt->size, MMU_SECTION_SIZE),
+ DCACHE_OFF);
+
#endif
return 0;
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 4a9b74e1ca1..e4e7f58c39a 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -3,6 +3,8 @@
* Copyright (c) 2013 Google, Inc
*/
+#define LOG_CATEGORY UCLASS_GPIO
+
#include <common.h>
#include <dm.h>
#include <log.h>
@@ -21,6 +23,7 @@
#include <dm/device_compat.h>
#include <linux/bug.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -220,7 +223,7 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
static int gpio_find_and_xlate(struct gpio_desc *desc,
struct ofnode_phandle_args *args)
{
- struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+ const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
if (ops->xlate)
return ops->xlate(desc->dev, desc, args);
@@ -353,6 +356,7 @@ int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
int dm_gpio_request(struct gpio_desc *desc, const char *label)
{
+ const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
struct udevice *dev = desc->dev;
struct gpio_dev_priv *uc_priv;
char *str;
@@ -364,8 +368,8 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
str = strdup(label);
if (!str)
return -ENOMEM;
- if (gpio_get_ops(dev)->request) {
- ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
+ if (ops->request) {
+ ret = ops->request(dev, desc->offset, label);
if (ret) {
free(str);
return ret;
@@ -442,14 +446,15 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...)
int _dm_gpio_free(struct udevice *dev, uint offset)
{
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
struct gpio_dev_priv *uc_priv;
int ret;
uc_priv = dev_get_uclass_priv(dev);
if (!uc_priv->name[offset])
return -ENXIO;
- if (gpio_get_ops(dev)->rfree) {
- ret = gpio_get_ops(dev)->rfree(dev, offset);
+ if (ops->rfree) {
+ ret = ops->rfree(dev, offset);
if (ret)
return ret;
}
@@ -515,11 +520,8 @@ int gpio_direction_input(unsigned gpio)
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
- ret = check_reserved(&desc, "dir_input");
- if (ret)
- return ret;
- return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
+ return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN);
}
/**
@@ -534,24 +536,25 @@ int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio, int value)
{
struct gpio_desc desc;
+ ulong flags;
int ret;
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
- ret = check_reserved(&desc, "dir_output");
- if (ret)
- return ret;
- return gpio_get_ops(desc.dev)->direction_output(desc.dev,
- desc.offset, value);
+ flags = GPIOD_IS_OUT;
+ if (value)
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, flags);
}
static int _gpio_get_value(const struct gpio_desc *desc)
{
+ const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
int value;
- value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
+ value = ops->get_value(desc->dev, desc->offset);
return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
}
@@ -569,6 +572,7 @@ int dm_gpio_get_value(const struct gpio_desc *desc)
int dm_gpio_set_value(const struct gpio_desc *desc, int value)
{
+ const struct dm_gpio_ops *ops;
int ret;
ret = check_reserved(desc, "set_value");
@@ -578,21 +582,33 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
if (desc->flags & GPIOD_ACTIVE_LOW)
value = !value;
+ /* GPIOD_ are directly managed by driver in set_flags */
+ ops = gpio_get_ops(desc->dev);
+ if (ops->set_flags) {
+ ulong flags = desc->flags;
+
+ if (value)
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ else
+ flags &= ~GPIOD_IS_OUT_ACTIVE;
+ return ops->set_flags(desc->dev, desc->offset, flags);
+ }
+
/*
* Emulate open drain by not actively driving the line high or
* Emulate open source by not actively driving the line low
*/
if ((desc->flags & GPIOD_OPEN_DRAIN && value) ||
(desc->flags & GPIOD_OPEN_SOURCE && !value))
- return gpio_get_ops(desc->dev)->direction_input(desc->dev,
- desc->offset);
+ return ops->direction_input(desc->dev, desc->offset);
else if (desc->flags & GPIOD_OPEN_DRAIN ||
desc->flags & GPIOD_OPEN_SOURCE)
- return gpio_get_ops(desc->dev)->direction_output(desc->dev,
- desc->offset,
- value);
+ return ops->direction_output(desc->dev, desc->offset, value);
+
+ ret = ops->set_value(desc->dev, desc->offset, value);
+ if (ret)
+ return ret;
- gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
return 0;
}
@@ -620,10 +636,21 @@ static int check_dir_flags(ulong flags)
return 0;
}
-static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+/**
+ * _dm_gpio_set_flags() - Send flags to the driver
+ *
+ * This uses the best available method to send the given flags to the driver.
+ * Note that if flags & GPIOD_ACTIVE_LOW, the driver sees the opposite value
+ * of GPIOD_IS_OUT_ACTIVE.
+ *
+ * @desc: GPIO description
+ * @flags: flags value to set
+ * @return 0 if OK, -ve on error
+ */
+static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags)
{
struct udevice *dev = desc->dev;
- struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
int ret = 0;
@@ -638,84 +665,102 @@ static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
return ret;
}
- /* GPIOD_ are directly managed by driver in set_dir_flags*/
- if (ops->set_dir_flags) {
- ret = ops->set_dir_flags(dev, desc->offset, flags);
+ /* If active low, invert the output state */
+ if ((flags & (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) ==
+ (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW))
+ flags ^= GPIOD_IS_OUT_ACTIVE;
+
+ /* GPIOD_ are directly managed by driver in set_flags */
+ if (ops->set_flags) {
+ ret = ops->set_flags(dev, desc->offset, flags);
} else {
if (flags & GPIOD_IS_OUT) {
- ret = ops->direction_output(dev, desc->offset,
- GPIOD_FLAGS_OUTPUT(flags));
+ bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
+ ret = ops->direction_output(dev, desc->offset, value);
} else if (flags & GPIOD_IS_IN) {
ret = ops->direction_input(dev, desc->offset);
}
}
- /* save the flags also in descriptor */
- if (!ret)
- desc->flags = flags;
-
return ret;
}
-int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set)
{
+ ulong flags;
int ret;
ret = check_reserved(desc, "set_dir_flags");
if (ret)
return ret;
- /* combine the requested flags (for IN/OUT) and the descriptor flags */
- flags |= desc->flags;
- ret = _dm_gpio_set_dir_flags(desc, flags);
+ flags = (desc->flags & ~clr) | set;
- return ret;
+ ret = _dm_gpio_set_flags(desc, flags);
+ if (ret)
+ return ret;
+
+ /* save the flags also in descriptor */
+ desc->flags = flags;
+
+ return 0;
+}
+
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+ /* combine the requested flags (for IN/OUT) and the descriptor flags */
+ return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags);
}
-int dm_gpio_set_dir(struct gpio_desc *desc)
+int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
+ ulong set)
{
int ret;
+ int i;
- ret = check_reserved(desc, "set_dir");
- if (ret)
- return ret;
+ for (i = 0; i < count; i++) {
+ ret = dm_gpio_clrset_flags(&desc[i], clr, set);
+ if (ret)
+ return log_ret(ret);
+ }
- return _dm_gpio_set_dir_flags(desc, desc->flags);
+ return 0;
}
-int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags)
+int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp)
{
struct udevice *dev = desc->dev;
int ret, value;
- struct dm_gpio_ops *ops = gpio_get_ops(dev);
- ulong dir_flags;
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ ulong flags;
- ret = check_reserved(desc, "get_dir_flags");
+ ret = check_reserved(desc, "get_flags");
if (ret)
return ret;
/* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */
- if (ops->get_dir_flags) {
- ret = ops->get_dir_flags(dev, desc->offset, &dir_flags);
+ if (ops->get_flags) {
+ ret = ops->get_flags(dev, desc->offset, &flags);
if (ret)
return ret;
/* GPIOD_ACTIVE_LOW is saved in desc->flags */
- value = dir_flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+ value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
if (desc->flags & GPIOD_ACTIVE_LOW)
value = !value;
- dir_flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
- dir_flags |= (desc->flags & GPIOD_ACTIVE_LOW);
+ flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
+ flags |= (desc->flags & GPIOD_ACTIVE_LOW);
if (value)
- dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ flags |= GPIOD_IS_OUT_ACTIVE;
} else {
- dir_flags = desc->flags;
+ flags = desc->flags;
/* only GPIOD_IS_OUT_ACTIVE is provided by uclass */
- dir_flags &= ~GPIOD_IS_OUT_ACTIVE;
+ flags &= ~GPIOD_IS_OUT_ACTIVE;
if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc))
- dir_flags |= GPIOD_IS_OUT_ACTIVE;
+ flags |= GPIOD_IS_OUT_ACTIVE;
}
- *flags = dir_flags;
+ *flagsp = flags;
return 0;
}
@@ -785,7 +830,7 @@ static int get_function(struct udevice *dev, int offset, bool skip_unused,
const char **namep)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
if (!device_active(dev))
@@ -822,7 +867,7 @@ int gpio_get_raw_function(struct udevice *dev, int offset, const char **namep)
int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
{
- struct dm_gpio_ops *ops = gpio_get_ops(dev);
+ const struct dm_gpio_ops *ops = gpio_get_ops(dev);
struct gpio_dev_priv *priv;
char *str = buf;
int func;
@@ -862,7 +907,7 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
#if CONFIG_IS_ENABLED(ACPIGEN)
int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio)
{
- struct dm_gpio_ops *ops;
+ const struct dm_gpio_ops *ops;
memset(gpio, '\0', sizeof(*gpio));
if (!dm_gpio_is_valid(desc)) {
@@ -949,6 +994,71 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count)
return vector;
}
+int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
+ int count)
+{
+ static const char tristate[] = "01z";
+ enum {
+ PULLUP,
+ PULLDOWN,
+
+ NUM_OPTIONS,
+ };
+ int vals[NUM_OPTIONS];
+ uint mask;
+ uint vector = 0;
+ int ret, i;
+
+ /*
+ * Limit to 19 digits which should be plenty. This avoids overflow of a
+ * 32-bit int
+ */
+ assert(count < 20);
+
+ for (i = 0; i < NUM_OPTIONS; i++) {
+ uint flags = GPIOD_IS_IN;
+
+ flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP;
+ ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL,
+ flags);
+ if (ret)
+ return log_msg_ret("pu", ret);
+
+ /* Give the lines time to settle */
+ udelay(10);
+
+ ret = dm_gpio_get_values_as_int(desc_list, count);
+ if (ret < 0)
+ return log_msg_ret("get1", ret);
+ vals[i] = ret;
+ }
+
+ log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count);
+ for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) {
+ uint pd = vals[PULLDOWN] & mask ? 1 : 0;
+ uint pu = vals[PULLUP] & mask ? 1 : 0;
+ uint digit;
+
+ /*
+ * Get value with internal pulldown active. If this is 1 then
+ * there is a stronger external pullup, which we call 1. If not
+ * then call it 0.
+ *
+ * If the values differ then the pin is floating so we call
+ * this a 2.
+ */
+ if (pu == pd)
+ digit = pd;
+ else
+ digit = 2;
+ log_debug("%c ", tristate[digit]);
+ vector = 3 * vector + digit;
+ }
+ log_debug("vector=%d\n", vector);
+
+ return vector;
+}
+
/**
* gpio_request_tail: common work for requesting a gpio.
*
@@ -1011,7 +1121,10 @@ static int gpio_request_tail(int ret, const char *nodename,
debug("%s: dm_gpio_requestf failed\n", __func__);
goto err;
}
- ret = dm_gpio_set_dir_flags(desc, flags);
+
+ /* Keep any direction flags provided by the devicetree */
+ ret = dm_gpio_set_dir_flags(desc,
+ flags | (desc->flags & GPIOD_MASK_DIR));
if (ret) {
debug("%s: dm_gpio_set_dir failed\n", __func__);
goto err;
@@ -1024,6 +1137,7 @@ err:
return ret;
}
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
static int _gpio_request_by_name_nodev(ofnode node, const char *list_name,
int index, struct gpio_desc *desc,
int flags, bool add_index)
@@ -1110,6 +1224,7 @@ int gpio_get_list_count(struct udevice *dev, const char *list_name)
return ret;
}
+#endif /* OF_PLATDATA */
int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
{
@@ -1306,10 +1421,10 @@ static int gpio_post_bind(struct udevice *dev)
ops->get_function += gd->reloc_off;
if (ops->xlate)
ops->xlate += gd->reloc_off;
- if (ops->set_dir_flags)
- ops->set_dir_flags += gd->reloc_off;
- if (ops->get_dir_flags)
- ops->get_dir_flags += gd->reloc_off;
+ if (ops->set_flags)
+ ops->set_flags += gd->reloc_off;
+ if (ops->get_flags)
+ ops->get_flags += gd->reloc_off;
reloc_done++;
}
diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c
index eda95485c93..f15ce7b59ee 100644
--- a/drivers/gpio/intel_gpio.c
+++ b/drivers/gpio/intel_gpio.c
@@ -3,6 +3,8 @@
* Copyright 2019 Google LLC
*/
+#define LOG_CATEGORY UCLASS_GPIO
+
#include <common.h>
#include <dm.h>
#include <errno.h>
@@ -21,40 +23,9 @@
#include <asm/pci.h>
#include <asm/arch/gpio.h>
#include <dm/acpi.h>
+#include <dm/device-internal.h>
#include <dt-bindings/gpio/x86-gpio.h>
-static int intel_gpio_direction_input(struct udevice *dev, uint offset)
-{
- struct udevice *pinctrl = dev_get_parent(dev);
- uint config_offset;
-
- config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
-
- pcr_clrsetbits32(pinctrl, config_offset,
- PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
- PAD_CFG0_RX_DISABLE,
- PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE);
-
- return 0;
-}
-
-static int intel_gpio_direction_output(struct udevice *dev, uint offset,
- int value)
-{
- struct udevice *pinctrl = dev_get_parent(dev);
- uint config_offset;
-
- config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
-
- pcr_clrsetbits32(pinctrl, config_offset,
- PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
- PAD_CFG0_TX_DISABLE | PAD_CFG0_TX_STATE,
- PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE |
- (value ? PAD_CFG0_TX_STATE : 0));
-
- return 0;
-}
-
static int intel_gpio_get_value(struct udevice *dev, uint offset)
{
struct udevice *pinctrl = dev_get_parent(dev);
@@ -115,7 +86,7 @@ static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
/*
* GPIO numbers are global in the device tree so it doesn't matter
- * which one is used
+ * which @orig_dev is used
*/
gpio = args->args[0];
ret = intel_pinctrl_get_pad(gpio, &pinctrl, &desc->offset);
@@ -127,6 +98,52 @@ static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
desc->dev = dev;
+ /*
+ * Handle the case where the wrong GPIO device was provided, since this
+ * will not have been probed by the GPIO uclass before calling here
+ * (see gpio_request_tail()).
+ */
+ if (orig_dev != dev) {
+ ret = device_probe(dev);
+ if (ret)
+ return log_msg_ret("probe", ret);
+ }
+
+ return 0;
+}
+
+static int intel_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ u32 bic0 = 0, bic1 = 0;
+ u32 or0, or1;
+ uint config_offset;
+
+ config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
+
+ if (flags & GPIOD_IS_OUT) {
+ bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
+ PAD_CFG0_TX_DISABLE;
+ or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE;
+ } else if (flags & GPIOD_IS_IN) {
+ bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
+ PAD_CFG0_RX_DISABLE;
+ or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE;
+ }
+ if (flags & GPIOD_PULL_UP) {
+ bic1 |= PAD_CFG1_PULL_MASK;
+ or1 |= PAD_CFG1_PULL_UP_20K;
+ } else if (flags & GPIOD_PULL_DOWN) {
+ bic1 |= PAD_CFG1_PULL_MASK;
+ or1 |= PAD_CFG1_PULL_DN_20K;
+ }
+
+ pcr_clrsetbits32(pinctrl, PAD_CFG0_OFFSET(config_offset), bic0, or0);
+ pcr_clrsetbits32(pinctrl, PAD_CFG1_OFFSET(config_offset), bic1, or1);
+ log_debug("%s: flags=%lx, offset=%x, config_offset=%x, %x/%x %x/%x\n",
+ dev->name, flags, offset, config_offset, bic0, or0, bic1, or1);
+
return 0;
}
@@ -177,12 +194,11 @@ static int intel_gpio_of_to_plat(struct udevice *dev)
}
static const struct dm_gpio_ops gpio_intel_ops = {
- .direction_input = intel_gpio_direction_input,
- .direction_output = intel_gpio_direction_output,
.get_value = intel_gpio_get_value,
.set_value = intel_gpio_set_value,
.get_function = intel_gpio_get_function,
.xlate = intel_gpio_xlate,
+ .set_flags = intel_gpio_set_flags,
#if CONFIG_IS_ENABLED(ACPIGEN)
.get_acpi = intel_gpio_get_acpi,
#endif
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index dc8d506e8d4..d008fdd2224 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -19,42 +19,51 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/sandbox-gpio.h>
-
struct gpio_state {
const char *label; /* label given by requester */
- ulong dir_flags; /* dir_flags (GPIOD_...) */
+ ulong flags; /* flags (GPIOD_...) */
};
-/* Access routines for GPIO dir flags */
-static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset)
+/* Access routines for GPIO info */
+static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct gpio_state *state = dev_get_priv(dev);
if (offset >= uc_priv->gpio_count) {
- static ulong invalid_dir_flags;
printf("sandbox_gpio: error: invalid gpio %u\n", offset);
- return &invalid_dir_flags;
+ return NULL;
}
- return &state[offset].dir_flags;
+ return &state[offset];
+}
+
+/* Access routines for GPIO flags */
+static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset)
+{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (!state)
+ return NULL;
+
+ return &state->flags;
}
static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
{
- return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
+ return (*get_gpio_flags(dev, offset) & flag) != 0;
}
static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
int value)
{
- ulong *gpio = get_gpio_dir_flags(dev, offset);
+ struct gpio_state *state = get_gpio_state(dev, offset);
if (value)
- *gpio |= flag;
+ state->flags |= flag;
else
- *gpio &= ~flag;
+ state->flags &= ~flag;
return 0;
}
@@ -65,14 +74,31 @@ static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+ bool val;
+
if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
debug("sandbox_gpio: get_value on output gpio %u\n", offset);
- return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE);
+
+ if (state->flags & GPIOD_EXT_DRIVEN) {
+ val = state->flags & GPIOD_EXT_HIGH;
+ } else {
+ if (state->flags & GPIOD_EXT_PULL_UP)
+ val = true;
+ else if (state->flags & GPIOD_EXT_PULL_DOWN)
+ val = false;
+ else
+ val = state->flags & GPIOD_PULL_UP;
+ }
+
+ return val;
}
int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
- return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
+ set_gpio_flag(dev, offset, GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+
+ return 0;
}
int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
@@ -83,20 +109,23 @@ int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
{
set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
- set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
+ set_gpio_flag(dev, offset, GPIOD_IS_IN, !output);
return 0;
}
-ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
+ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset)
{
- return *get_gpio_dir_flags(dev, offset);
+ ulong flags = *get_gpio_flags(dev, offset);
+
+ return flags & ~GPIOD_SANDBOX_MASK;
}
-int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
+int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags)
{
- *get_gpio_dir_flags(dev, offset) = flags;
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ state->flags = flags;
return 0;
}
@@ -117,10 +146,19 @@ static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
int value)
{
+ int ret;
+
debug("%s: offset:%u, value = %d\n", __func__, offset, value);
- return sandbox_gpio_set_direction(dev, offset, 1) |
- sandbox_gpio_set_value(dev, offset, value);
+ ret = sandbox_gpio_set_direction(dev, offset, 1);
+ if (ret)
+ return ret;
+ ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+ GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+ if (ret)
+ return ret;
+
+ return 0;
}
/* read GPIO IN value of port 'offset' */
@@ -134,6 +172,8 @@ static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
/* write GPIO OUT value to port 'offset' */
static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
+ int ret;
+
debug("%s: offset:%u, value = %d\n", __func__, offset, value);
if (!sandbox_gpio_get_direction(dev, offset)) {
@@ -142,7 +182,12 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
return -1;
}
- return sandbox_gpio_set_value(dev, offset, value);
+ ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+ GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+ if (ret)
+ return ret;
+
+ return 0;
}
static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
@@ -177,33 +222,30 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
return 0;
}
-static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
+static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
{
- ulong *dir_flags;
-
- debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags);
-
- dir_flags = get_gpio_dir_flags(dev, offset);
-
- /*
- * For testing purposes keep the output value when switching to input.
- * This allows us to manipulate the input value via the gpio command.
- */
- if (flags & GPIOD_IS_IN)
- *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) |
- (*dir_flags & GPIOD_IS_OUT_ACTIVE);
- else
- *dir_flags = flags;
+ debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (flags & GPIOD_IS_OUT) {
+ flags |= GPIOD_EXT_DRIVEN;
+ if (flags & GPIOD_IS_OUT_ACTIVE)
+ flags |= GPIOD_EXT_HIGH;
+ else
+ flags &= ~GPIOD_EXT_HIGH;
+ } else {
+ flags |= state->flags & GPIOD_SANDBOX_MASK;
+ }
+ state->flags = flags;
return 0;
}
-static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
- ulong *flags)
+static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
{
debug("%s: offset:%u\n", __func__, offset);
- *flags = *get_gpio_dir_flags(dev, offset);
+ *flagsp = *get_gpio_flags(dev, offset) & ~GPIOD_SANDBOX_MASK;
return 0;
}
@@ -272,8 +314,8 @@ static const struct dm_gpio_ops gpio_sandbox_ops = {
.set_value = sb_gpio_set_value,
.get_function = sb_gpio_get_function,
.xlate = sb_gpio_xlate,
- .set_dir_flags = sb_gpio_set_dir_flags,
- .get_dir_flags = sb_gpio_get_dir_flags,
+ .set_flags = sb_gpio_set_flags,
+ .get_flags = sb_gpio_get_flags,
#if CONFIG_IS_ENABLED(ACPIGEN)
.get_acpi = sb_gpio_get_acpi,
#endif
@@ -456,7 +498,7 @@ static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
return pin_name;
}
-static char *get_dir_flags_string(ulong flags)
+static char *get_flags_string(ulong flags)
{
if (flags & GPIOD_OPEN_DRAIN)
return "drive-open-drain";
@@ -475,7 +517,7 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
{
struct udevice *gpio_dev;
unsigned int gpio_idx;
- ulong dir_flags;
+ ulong flags;
int function;
/* look up for the bank which owns the requested pin */
@@ -484,11 +526,11 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
snprintf(buf, size, "Error");
} else {
function = sb_gpio_get_function(gpio_dev, gpio_idx);
- dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx);
+ flags = *get_gpio_flags(gpio_dev, gpio_idx);
snprintf(buf, size, "gpio %s %s",
function == GPIOF_OUTPUT ? "output" : "input",
- get_dir_flags_string(dir_flags));
+ get_flags_string(flags));
}
return 0;
diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c
index 7184db3c527..125c237551c 100644
--- a/drivers/gpio/stm32_gpio.c
+++ b/drivers/gpio/stm32_gpio.c
@@ -191,8 +191,8 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
return GPIOF_FUNC;
}
-static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
+static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
struct stm32_gpio_regs *regs = priv->regs;
@@ -203,12 +203,13 @@ static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
return idx;
if (flags & GPIOD_IS_OUT) {
- int value = GPIOD_FLAGS_OUTPUT(flags);
+ bool value = flags & GPIOD_IS_OUT_ACTIVE;
if (flags & GPIOD_OPEN_DRAIN)
stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD);
else
stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP);
+
stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
writel(BSRR_BIT(idx, value), &regs->bsrr);
@@ -223,8 +224,8 @@ static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
return 0;
}
-static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
- ulong *flags)
+static int stm32_gpio_get_flags(struct udevice *dev, unsigned int offset,
+ ulong *flagsp)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
struct stm32_gpio_regs *regs = priv->regs;
@@ -259,7 +260,7 @@ static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
default:
break;
}
- *flags = dir_flags;
+ *flagsp = dir_flags;
return 0;
}
@@ -270,8 +271,8 @@ static const struct dm_gpio_ops gpio_stm32_ops = {
.get_value = stm32_gpio_get_value,
.set_value = stm32_gpio_set_value,
.get_function = stm32_gpio_get_function,
- .set_dir_flags = stm32_gpio_set_dir_flags,
- .get_dir_flags = stm32_gpio_get_dir_flags,
+ .set_flags = stm32_gpio_set_flags,
+ .get_flags = stm32_gpio_get_flags,
};
static int gpio_stm32_probe(struct udevice *dev)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 1844941eb21..57a4efb88ed 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -479,7 +479,7 @@ config SYS_I2C_UNIPHIER_F
config SYS_I2C_VERSATILE
bool "Arm Ltd Versatile I2C bus driver"
- depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO)
+ depends on DM_I2C && TARGET_VEXPRESS64_JUNO
help
Add support for the Arm Ltd Versatile Express I2C driver. The I2C host
controller is present in the development boards manufactured by Arm Ltd.
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index acd27ac29d2..8c9f1fcd8b9 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -39,9 +39,7 @@ obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
-ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
-endif
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c
index 085b824e895..7917b63c55b 100644
--- a/drivers/i2c/i2c-emul-uclass.c
+++ b/drivers/i2c/i2c-emul-uclass.c
@@ -7,6 +7,7 @@
#include <dm.h>
#include <i2c.h>
#include <log.h>
+#include <asm/i2c.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
@@ -23,18 +24,6 @@
* uclass so avoid having strange devices on the I2C bus.
*/
-/**
- * struct i2c_emul_uc_plat - information about the emulator for this device
- *
- * This is used by devices in UCLASS_I2C_EMUL to record information about the
- * device being emulated. It is accessible with dev_get_uclass_plat()
- *
- * @dev: Device being emulated
- */
-struct i2c_emul_uc_plat {
- struct udevice *dev;
-};
-
struct udevice *i2c_emul_get_device(struct udevice *emul)
{
struct i2c_emul_uc_plat *uc_plat = dev_get_uclass_plat(emul);
@@ -42,14 +31,27 @@ struct udevice *i2c_emul_get_device(struct udevice *emul)
return uc_plat->dev;
}
+void i2c_emul_set_idx(struct udevice *dev, int emul_idx)
+{
+ struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+ plat->emul_idx = emul_idx;
+}
+
int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
{
struct i2c_emul_uc_plat *uc_plat;
struct udevice *emul;
int ret;
- ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
- "sandbox,emul", &emul);
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
+ "sandbox,emul", &emul);
+ } else {
+ struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+ ret = device_get_by_ofplat_idx(plat->emul_idx, &emul);
+ }
if (ret) {
log_err("No emulators for device '%s'\n", dev->name);
return ret;
@@ -85,8 +87,8 @@ static const struct udevice_id i2c_emul_parent_ids[] = {
{ }
};
-U_BOOT_DRIVER(i2c_emul_parent_drv) = {
- .name = "i2c_emul_parent_drv",
+U_BOOT_DRIVER(sandbox_i2c_emul_parent) = {
+ .name = "sandbox_i2c_emul_parent",
.id = UCLASS_I2C_EMUL_PARENT,
.of_match = i2c_emul_parent_ids,
};
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index a301a4460b3..cf8f8f40359 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -48,12 +48,13 @@ static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus)
static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
{
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+ ulong flags;
if (bit)
- sda->flags = (sda->flags & ~GPIOD_IS_OUT) | GPIOD_IS_IN;
+ flags = GPIOD_IS_IN;
else
- sda->flags = (sda->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
- dm_gpio_set_dir(sda);
+ flags = GPIOD_IS_OUT;
+ dm_gpio_clrset_flags(sda, GPIOD_MASK_DIR, flags);
}
static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
@@ -62,16 +63,14 @@ static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
int count = 0;
if (bit) {
- scl->flags = (scl->flags & ~GPIOD_IS_OUT) | GPIOD_IS_IN;
- dm_gpio_set_dir(scl);
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, GPIOD_IS_IN);
while (!dm_gpio_get_value(scl) && count++ < 100000)
udelay(1);
if (!dm_gpio_get_value(scl))
pr_err("timeout waiting on slave to release scl\n");
} else {
- scl->flags = (scl->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
- dm_gpio_set_dir(scl);
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, GPIOD_IS_OUT);
}
}
@@ -79,11 +78,11 @@ static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit)
{
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
- scl->flags = (scl->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
+ ulong flags = GPIOD_IS_OUT;
if (bit)
- scl->flags |= GPIOD_IS_OUT_ACTIVE;
- dm_gpio_set_dir(scl);
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, flags);
}
static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7d2a2997797..c650471ff7c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -368,8 +368,22 @@ config WINBOND_W83627
config QFW
bool
help
- Hidden option to enable QEMU fw_cfg interface. This will be selected by
- either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE.
+ Hidden option to enable QEMU fw_cfg interface and uclass. This will
+ be selected by either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE.
+
+config QFW_PIO
+ bool
+ depends on QFW
+ help
+ Hidden option to enable PIO QEMU fw_cfg interface. This will be
+ selected by the appropriate QEMU board.
+
+config QFW_MMIO
+ bool
+ depends on QFW
+ help
+ Hidden option to enable MMIO QEMU fw_cfg interface. This will be
+ selected by the appropriate QEMU board.
config I2C_EEPROM
bool "Enable driver for generic I2C-attached EEPROMs"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1a493960074..0c67d43a5d4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,7 +55,12 @@ obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
-obj-$(CONFIG_QFW) += qfw.o
+ifdef CONFIG_QFW
+obj-y += qfw.o
+obj-$(CONFIG_QFW_PIO) += qfw_pio.o
+obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o
+obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
+endif
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
diff --git a/drivers/misc/cbmem_console.c b/drivers/misc/cbmem_console.c
index 5ba0a542060..8bbe33d414d 100644
--- a/drivers/misc/cbmem_console.c
+++ b/drivers/misc/cbmem_console.c
@@ -9,7 +9,7 @@
#error This driver requires coreboot
#endif
-#include <asm/arch/sysinfo.h>
+#include <asm/cb_sysinfo.h>
struct cbmem_console {
u32 buffer_size;
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index ebfa7c41c25..7904d5cc72d 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -1170,6 +1170,23 @@ int cros_ec_battery_cutoff(struct udevice *dev, uint8_t flags)
return 0;
}
+int cros_ec_set_pwm_duty(struct udevice *dev, uint8_t index, uint16_t duty)
+{
+ struct ec_params_pwm_set_duty p;
+ int ret;
+
+ p.duty = duty;
+ p.pwm_type = EC_PWM_TYPE_GENERIC;
+ p.index = index;
+
+ ret = ec_command(dev, EC_CMD_PWM_SET_DUTY, 0, &p, sizeof(p),
+ NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state)
{
struct ec_params_ldo_set params;
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index cb8adc4495a..bc01df0904e 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -153,10 +153,14 @@ static int cros_ec_write_state(void *blob, int node)
{
struct ec_state *ec = g_state;
+ if (!g_state)
+ return 0;
+
/* We are guaranteed enough space to write basic properties */
fdt_setprop_u32(blob, node, "current-image", ec->current_image);
fdt_setprop(blob, node, "vbnv-context", ec->vbnv_context,
sizeof(ec->vbnv_context));
+
return state_setprop(node, "flash-data", ec->flash_data,
ec->ec_config.flash.length);
}
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index 24b27962a7d..3aa26f61d9e 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -69,7 +69,7 @@ int irq_get_by_driver_info(struct udevice *dev,
{
int ret;
- ret = device_get_by_driver_info_idx(cells->idx, &irq->dev);
+ ret = device_get_by_ofplat_idx(cells->idx, &irq->dev);
if (ret)
return ret;
irq->id = cells->arg[0];
diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c
index 926c62c8a14..b1893a5c7eb 100644
--- a/drivers/misc/mxc_ocotp.c
+++ b/drivers/misc/mxc_ocotp.c
@@ -335,7 +335,7 @@ 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)) {
+ if (is_imx8mq() && (soc_rev() >= CHIP_REV_2_1)) {
printf("mxc_ocotp %s(): fuse sense is disabled\n", __func__);
return -EPERM;
}
diff --git a/drivers/misc/p2sb_emul.c b/drivers/misc/p2sb_emul.c
index 973d02d6785..51f87161d5b 100644
--- a/drivers/misc/p2sb_emul.c
+++ b/drivers/misc/p2sb_emul.c
@@ -7,7 +7,6 @@
*/
#define LOG_CATEGORY UCLASS_MISC
-#define LOG_DEBUG
#include <common.h>
#include <axi.h>
diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c
index f6eb6583ed0..ea00be88a8d 100644
--- a/drivers/misc/qfw.c
+++ b/drivers/misc/qfw.c
@@ -1,25 +1,22 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
*/
+#define LOG_CATEGORY UCLASS_QFW
+
#include <common.h>
#include <command.h>
#include <errno.h>
#include <log.h>
#include <malloc.h>
#include <qfw.h>
-#include <asm/io.h>
+#include <dm.h>
+#include <misc.h>
#ifdef CONFIG_GENERATE_ACPI_TABLE
#include <asm/tables.h>
#endif
-#include <linux/list.h>
-
-static bool fwcfg_present;
-static bool fwcfg_dma_present;
-static struct fw_cfg_arch_ops *fwcfg_arch_ops;
-
-static LIST_HEAD(fw_list);
#ifdef CONFIG_GENERATE_ACPI_TABLE
/*
@@ -32,7 +29,8 @@ static LIST_HEAD(fw_list);
* be ignored.
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
+static int bios_linker_allocate(struct udevice *dev,
+ struct bios_linker_entry *entry, ulong *addr)
{
uint32_t size, align;
struct fw_file *file;
@@ -45,7 +43,7 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
return -EINVAL;
}
- file = qemu_fwcfg_find_file(entry->alloc.file);
+ file = qfw_find_file(dev, entry->alloc.file);
if (!file) {
printf("error: can't find file %s\n", entry->alloc.file);
return -ENOENT;
@@ -75,8 +73,8 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n",
file->cfg.name, size, entry->alloc.zone, align, aligned_addr);
- qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
- size, (void *)aligned_addr);
+ qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size,
+ (void *)aligned_addr);
file->addr = aligned_addr;
/* adjust address for low memory allocation */
@@ -94,16 +92,17 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
* ACPI tables
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_add_pointer(struct bios_linker_entry *entry)
+static int bios_linker_add_pointer(struct udevice *dev,
+ struct bios_linker_entry *entry)
{
struct fw_file *dest, *src;
uint32_t offset = le32_to_cpu(entry->pointer.offset);
uint64_t pointer = 0;
- dest = qemu_fwcfg_find_file(entry->pointer.dest_file);
+ dest = qfw_find_file(dev, entry->pointer.dest_file);
if (!dest || !dest->addr)
return -ENOENT;
- src = qemu_fwcfg_find_file(entry->pointer.src_file);
+ src = qfw_find_file(dev, entry->pointer.src_file);
if (!src || !src->addr)
return -ENOENT;
@@ -127,13 +126,14 @@ static int bios_linker_add_pointer(struct bios_linker_entry *entry)
* checksums
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_add_checksum(struct bios_linker_entry *entry)
+static int bios_linker_add_checksum(struct udevice *dev,
+ struct bios_linker_entry *entry)
{
struct fw_file *file;
uint8_t *data, cksum = 0;
uint8_t *cksum_start;
- file = qemu_fwcfg_find_file(entry->cksum.file);
+ file = qfw_find_file(dev, entry->cksum.file);
if (!file || !file->addr)
return -ENOENT;
@@ -149,20 +149,27 @@ static int bios_linker_add_checksum(struct bios_linker_entry *entry)
/* This function loads and patches ACPI tables provided by QEMU */
ulong write_acpi_tables(ulong addr)
{
- int i, ret = 0;
+ int i, ret;
struct fw_file *file;
struct bios_linker_entry *table_loader;
struct bios_linker_entry *entry;
uint32_t size;
+ struct udevice *dev;
+
+ ret = qfw_get_dev(&dev);
+ if (ret) {
+ printf("error: no qfw\n");
+ return addr;
+ }
/* make sure fw_list is loaded */
- ret = qemu_fwcfg_read_firmware_list();
+ ret = qfw_read_firmware_list(dev);
if (ret) {
printf("error: can't read firmware file list\n");
return addr;
}
- file = qemu_fwcfg_find_file("etc/table-loader");
+ file = qfw_find_file(dev, "etc/table-loader");
if (!file) {
printf("error: can't find etc/table-loader\n");
return addr;
@@ -180,24 +187,23 @@ ulong write_acpi_tables(ulong addr)
return addr;
}
- qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
- size, table_loader);
+ qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader);
for (i = 0; i < (size / sizeof(*entry)); i++) {
entry = table_loader + i;
switch (le32_to_cpu(entry->command)) {
case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
- ret = bios_linker_allocate(entry, &addr);
+ ret = bios_linker_allocate(dev, entry, &addr);
if (ret)
goto out;
break;
case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
- ret = bios_linker_add_pointer(entry);
+ ret = bios_linker_add_pointer(dev, entry);
if (ret)
goto out;
break;
case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
- ret = bios_linker_add_checksum(entry);
+ ret = bios_linker_add_checksum(dev, entry);
if (ret)
goto out;
break;
@@ -209,9 +215,9 @@ ulong write_acpi_tables(ulong addr)
out:
if (ret) {
struct fw_cfg_file_iter iter;
- for (file = qemu_fwcfg_file_iter_init(&iter);
- !qemu_fwcfg_file_iter_end(&iter);
- file = qemu_fwcfg_file_iter_next(&iter)) {
+ for (file = qfw_file_iter_init(dev, &iter);
+ !qfw_file_iter_end(&iter);
+ file = qfw_file_iter_next(&iter)) {
if (file->addr) {
free((void *)file->addr);
file->addr = 0;
@@ -225,170 +231,89 @@ out:
ulong acpi_get_rsdp_addr(void)
{
+ int ret;
struct fw_file *file;
+ struct udevice *dev;
- file = qemu_fwcfg_find_file("etc/acpi/rsdp");
+ ret = qfw_get_dev(&dev);
+ if (ret) {
+ printf("error: no qfw\n");
+ return 0;
+ }
+
+ file = qfw_find_file(dev, "etc/acpi/rsdp");
return file->addr;
}
#endif
-/* Read configuration item using fw_cfg PIO interface */
-static void qemu_fwcfg_read_entry_pio(uint16_t entry,
- uint32_t size, void *address)
+static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size,
+ void *address)
{
- debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n",
- entry, size, address);
+ struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev);
+
+ debug("%s: entry 0x%x, size %u address %p\n", __func__, entry, size,
+ address);
- return fwcfg_arch_ops->arch_read_pio(entry, size, address);
+ ops->read_entry_io(qdev->dev, entry, size, address);
}
-/* Read configuration item using fw_cfg DMA interface */
-static void qemu_fwcfg_read_entry_dma(uint16_t entry,
- uint32_t size, void *address)
+static void qfw_read_entry_dma(struct qfw_dev *qdev, u16 entry, u32 size,
+ void *address)
{
- struct fw_cfg_dma_access dma;
+ struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev);
- dma.length = cpu_to_be32(size);
- dma.address = cpu_to_be64((uintptr_t)address);
- dma.control = cpu_to_be32(FW_CFG_DMA_READ);
+ struct qfw_dma dma = {
+ .length = cpu_to_be32(size),
+ .address = cpu_to_be64((uintptr_t)address),
+ .control = cpu_to_be32(FW_CFG_DMA_READ),
+ };
/*
- * writting FW_CFG_INVALID will cause read operation to resume at
- * last offset, otherwise read will start at offset 0
+ * writing FW_CFG_INVALID will cause read operation to resume at last
+ * offset, otherwise read will start at offset 0
*/
if (entry != FW_CFG_INVALID)
dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16));
- barrier();
-
- debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n",
+ debug("%s: entry 0x%x, size %u address %p, control 0x%x\n", __func__,
entry, size, address, be32_to_cpu(dma.control));
- fwcfg_arch_ops->arch_read_dma(&dma);
-}
+ barrier();
-bool qemu_fwcfg_present(void)
-{
- return fwcfg_present;
+ ops->read_entry_dma(qdev->dev, &dma);
}
-bool qemu_fwcfg_dma_present(void)
+void qfw_read_entry(struct udevice *dev, u16 entry, u32 size, void *address)
{
- return fwcfg_dma_present;
-}
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
-void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address)
-{
- if (fwcfg_dma_present)
- qemu_fwcfg_read_entry_dma(entry, length, address);
+ if (qdev->dma_present)
+ qfw_read_entry_dma(qdev, entry, size, address);
else
- qemu_fwcfg_read_entry_pio(entry, length, address);
+ qfw_read_entry_io(qdev, entry, size, address);
}
-int qemu_fwcfg_online_cpus(void)
+int qfw_register(struct udevice *dev)
{
- uint16_t nb_cpus;
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
+ u32 qemu, dma_enabled;
- if (!fwcfg_present)
- return -ENODEV;
-
- qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
-
- return le16_to_cpu(nb_cpus);
-}
+ qdev->dev = dev;
+ INIT_LIST_HEAD(&qdev->fw_list);
-int qemu_fwcfg_read_firmware_list(void)
-{
- int i;
- uint32_t count;
- struct fw_file *file;
- struct list_head *entry;
-
- /* don't read it twice */
- if (!list_empty(&fw_list))
- return 0;
+ qfw_read_entry_io(qdev, FW_CFG_SIGNATURE, 4, &qemu);
+ if (be32_to_cpu(qemu) != QEMU_FW_CFG_SIGNATURE)
+ return -ENODEV;
- qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
- if (!count)
- return 0;
-
- count = be32_to_cpu(count);
- for (i = 0; i < count; i++) {
- file = malloc(sizeof(*file));
- if (!file) {
- printf("error: allocating resource\n");
- goto err;
- }
- qemu_fwcfg_read_entry(FW_CFG_INVALID,
- sizeof(struct fw_cfg_file), &file->cfg);
- file->addr = 0;
- list_add_tail(&file->list, &fw_list);
- }
+ qfw_read_entry_io(qdev, FW_CFG_ID, 1, &dma_enabled);
+ if (dma_enabled & FW_CFG_DMA_ENABLED)
+ qdev->dma_present = true;
return 0;
-
-err:
- list_for_each(entry, &fw_list) {
- file = list_entry(entry, struct fw_file, list);
- free(file);
- }
-
- return -ENOMEM;
}
-struct fw_file *qemu_fwcfg_find_file(const char *name)
-{
- struct list_head *entry;
- struct fw_file *file;
-
- list_for_each(entry, &fw_list) {
- file = list_entry(entry, struct fw_file, list);
- if (!strcmp(file->cfg.name, name))
- return file;
- }
-
- return NULL;
-}
-
-struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter)
-{
- iter->entry = fw_list.next;
- return list_entry((struct list_head *)iter->entry,
- struct fw_file, list);
-}
-
-struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter)
-{
- iter->entry = ((struct list_head *)iter->entry)->next;
- return list_entry((struct list_head *)iter->entry,
- struct fw_file, list);
-}
-
-bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter)
-{
- return iter->entry == &fw_list;
-}
-
-void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops)
-{
- uint32_t qemu;
- uint32_t dma_enabled;
-
- fwcfg_present = false;
- fwcfg_dma_present = false;
- fwcfg_arch_ops = NULL;
-
- if (!ops || !ops->arch_read_pio || !ops->arch_read_dma)
- return;
- fwcfg_arch_ops = ops;
-
- qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
- if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
- fwcfg_present = true;
-
- if (fwcfg_present) {
- qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
- if (dma_enabled & FW_CFG_DMA_ENABLED)
- fwcfg_dma_present = true;
- }
-}
+UCLASS_DRIVER(qfw) = {
+ .id = UCLASS_QFW,
+ .name = "qfw",
+ .per_device_auto = sizeof(struct qfw_dev),
+};
diff --git a/drivers/misc/qfw_mmio.c b/drivers/misc/qfw_mmio.c
new file mode 100644
index 00000000000..f397384054a
--- /dev/null
+++ b/drivers/misc/qfw_mmio.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MMIO interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+struct qfw_mmio {
+ /*
+ * Each access to the 64-bit data register can be 8/16/32/64 bits wide.
+ */
+ union {
+ u8 data8;
+ u16 data16;
+ u32 data32;
+ u64 data64;
+ };
+ u16 selector;
+ u8 padding[6];
+ u64 dma;
+};
+
+struct qfw_mmio_plat {
+ volatile struct qfw_mmio *mmio;
+};
+
+static void qfw_mmio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+ /*
+ * writing FW_CFG_INVALID will cause read operation to resume at last
+ * offset, otherwise read will start at offset 0
+ *
+ * Note: on platform where the control register is MMIO, the register
+ * is big endian.
+ */
+ if (entry != FW_CFG_INVALID)
+ plat->mmio->selector = cpu_to_be16(entry);
+
+ /* the endianness of data register is string-preserving */
+ while (size >= 8) {
+ *(u64 *)address = plat->mmio->data64;
+ address += 8;
+ size -= 8;
+ }
+ while (size >= 4) {
+ *(u32 *)address = plat->mmio->data32;
+ address += 4;
+ size -= 4;
+ }
+ while (size >= 2) {
+ *(u16 *)address = plat->mmio->data16;
+ address += 2;
+ size -= 2;
+ }
+ while (size >= 1) {
+ *(u8 *)address = plat->mmio->data8;
+ address += 1;
+ size -= 1;
+ }
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+static void qfw_mmio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+ /* the DMA address register is big-endian */
+ plat->mmio->dma = cpu_to_be64((uintptr_t)dma);
+
+ while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
+}
+
+static int qfw_mmio_of_to_plat(struct udevice *dev)
+{
+ struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+ plat->mmio = map_physmem(dev_read_addr(dev),
+ sizeof(struct qfw_mmio),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static int qfw_mmio_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_mmio_ops = {
+ .read_entry_io = qfw_mmio_read_entry_io,
+ .read_entry_dma = qfw_mmio_read_entry_dma,
+};
+
+static const struct udevice_id qfw_mmio_ids[] = {
+ { .compatible = "qemu,fw-cfg-mmio" },
+ {}
+};
+
+U_BOOT_DRIVER(qfw_mmio) = {
+ .name = "qfw_mmio",
+ .id = UCLASS_QFW,
+ .of_match = qfw_mmio_ids,
+ .plat_auto = sizeof(struct qfw_mmio_plat),
+ .of_to_plat = qfw_mmio_of_to_plat,
+ .probe = qfw_mmio_probe,
+ .ops = &qfw_mmio_ops,
+};
diff --git a/drivers/misc/qfw_pio.c b/drivers/misc/qfw_pio.c
new file mode 100644
index 00000000000..e2f628d3383
--- /dev/null
+++ b/drivers/misc/qfw_pio.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PIO interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/io.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+/*
+ * PIO ports are correct for x86, which appears to be the only arch that uses
+ * PIO.
+ */
+#define FW_CONTROL_PORT 0x510
+#define FW_DATA_PORT 0x511
+#define FW_DMA_PORT_LOW 0x514
+#define FW_DMA_PORT_HIGH 0x518
+
+static void qfw_pio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ /*
+ * writing FW_CFG_INVALID will cause read operation to resume at last
+ * offset, otherwise read will start at offset 0
+ *
+ * Note: on platform where the control register is IO port, the
+ * endianness is little endian.
+ */
+ if (entry != FW_CFG_INVALID)
+ outw(cpu_to_le16(entry), FW_CONTROL_PORT);
+
+ /* the endianness of data register is string-preserving */
+ u32 i = 0;
+ u8 *data = address;
+
+ while (size--)
+ data[i++] = inb(FW_DATA_PORT);
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+static void qfw_pio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ /* the DMA address register is big-endian */
+ outl(cpu_to_be32((uintptr_t)dma), FW_DMA_PORT_HIGH);
+
+ while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
+}
+
+static int qfw_pio_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_pio_ops = {
+ .read_entry_io = qfw_pio_read_entry_io,
+ .read_entry_dma = qfw_pio_read_entry_dma,
+};
+
+U_BOOT_DRIVER(qfw_pio) = {
+ .name = "qfw_pio",
+ .id = UCLASS_QFW,
+ .probe = qfw_pio_probe,
+ .ops = &qfw_pio_ops,
+};
diff --git a/drivers/misc/qfw_sandbox.c b/drivers/misc/qfw_sandbox.c
new file mode 100644
index 00000000000..b09974d33bd
--- /dev/null
+++ b/drivers/misc/qfw_sandbox.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sandbox interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+struct qfw_sandbox_plat {
+ u8 file_dir_offset;
+};
+
+static void qfw_sandbox_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ debug("%s: entry 0x%x size %u address %p\n", __func__, entry, size,
+ address);
+
+ switch (entry) {
+ case FW_CFG_SIGNATURE:
+ if (size == 4)
+ *((u32 *)address) = cpu_to_be32(QEMU_FW_CFG_SIGNATURE);
+ break;
+ case FW_CFG_ID:
+ /* Advertise DMA support */
+ if (size == 1)
+ *((u8 *)address) = FW_CFG_DMA_ENABLED;
+ break;
+ default:
+ debug("%s got unsupported entry 0x%x\n", __func__, entry);
+ /*
+ * Sandbox driver doesn't support other entries here, assume we use DMA
+ * to read them -- the uclass driver will exclusively use it when
+ * advertised.
+ */
+ }
+}
+
+static void qfw_sandbox_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ u16 entry;
+ u32 control = be32_to_cpu(dma->control);
+ void *address = (void *)be64_to_cpu(dma->address);
+ u32 length = be32_to_cpu(dma->length);
+ struct qfw_sandbox_plat *plat = dev_get_plat(dev);
+ struct fw_cfg_file *file;
+
+ debug("%s\n", __func__);
+
+ if (!(control & FW_CFG_DMA_READ))
+ return;
+
+ if (control & FW_CFG_DMA_SELECT) {
+ /* Start new read. */
+ entry = control >> 16;
+
+ /* Arbitrary values to be used by tests. */
+ switch (entry) {
+ case FW_CFG_NB_CPUS:
+ if (length == 2)
+ *((u16 *)address) = cpu_to_le16(5);
+ break;
+ case FW_CFG_FILE_DIR:
+ if (length == 4) {
+ *((u32 *)address) = cpu_to_be32(2);
+ plat->file_dir_offset = 1;
+ }
+ break;
+ default:
+ debug("%s got unsupported entry 0x%x\n", __func__,
+ entry);
+ }
+ } else if (plat->file_dir_offset && length == 64) {
+ file = address;
+ switch (plat->file_dir_offset) {
+ case 1:
+ file->size = cpu_to_be32(8);
+ file->select = cpu_to_be16(FW_CFG_FILE_FIRST);
+ strcpy(file->name, "test-one");
+ plat->file_dir_offset++;
+ break;
+ case 2:
+ file->size = cpu_to_be32(8);
+ file->select = cpu_to_be16(FW_CFG_FILE_FIRST + 1);
+ strcpy(file->name, "test-two");
+ plat->file_dir_offset++;
+ break;
+ }
+ }
+
+ /*
+ * Signal that we are finished. No-one checks this in sandbox --
+ * normally the platform-specific driver looks for it -- but let's
+ * replicate the behaviour in case someone relies on it later.
+ */
+ dma->control = 0;
+}
+
+static int qfw_sandbox_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_sandbox_ops = {
+ .read_entry_io = qfw_sandbox_read_entry_io,
+ .read_entry_dma = qfw_sandbox_read_entry_dma,
+};
+
+U_BOOT_DRIVER(qfw_sandbox) = {
+ .name = "qfw_sandbox",
+ .id = UCLASS_QFW,
+ .plat_auto = sizeof(struct qfw_sandbox_plat),
+ .probe = qfw_sandbox_probe,
+ .ops = &qfw_sandbox_ops,
+};
+
+U_BOOT_DRVINFO(qfw_sandbox) = {
+ .name = "qfw_sandbox",
+};
diff --git a/drivers/misc/test_drv.c b/drivers/misc/test_drv.c
index 827a50e954f..5d72982f258 100644
--- a/drivers/misc/test_drv.c
+++ b/drivers/misc/test_drv.c
@@ -86,7 +86,7 @@ static const struct udevice_id testbus_ids[] = {
{ }
};
-U_BOOT_DRIVER(testbus_drv) = {
+U_BOOT_DRIVER(denx_u_boot_test_bus) = {
.name = "testbus_drv",
.of_match = testbus_ids,
.id = UCLASS_TEST_BUS,
@@ -98,6 +98,7 @@ U_BOOT_DRIVER(testbus_drv) = {
.per_child_plat_auto = sizeof(struct dm_test_parent_plat),
.child_pre_probe = testbus_child_pre_probe,
.child_post_remove = testbus_child_post_remove,
+ DM_HEADER(<test.h>)
};
UCLASS_DRIVER(testbus) = {
@@ -106,6 +107,9 @@ UCLASS_DRIVER(testbus) = {
.flags = DM_UC_FLAG_SEQ_ALIAS,
.child_pre_probe = testbus_child_pre_probe_uclass,
.child_post_probe = testbus_child_post_probe_uclass,
+
+ /* This is for dtoc testing only */
+ .per_device_plat_auto = sizeof(struct dm_test_uclass_priv),
};
static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
@@ -160,7 +164,9 @@ static const struct udevice_id testfdt_ids[] = {
{ }
};
-U_BOOT_DRIVER(testfdt_drv) = {
+DM_DRIVER_ALIAS(denx_u_boot_fdt_test, google_another_fdt_test)
+
+U_BOOT_DRIVER(denx_u_boot_fdt_test) = {
.name = "testfdt_drv",
.of_match = testfdt_ids,
.id = UCLASS_TEST_FDT,
@@ -203,6 +209,7 @@ UCLASS_DRIVER(testfdt) = {
.name = "testfdt",
.id = UCLASS_TEST_FDT,
.flags = DM_UC_FLAG_SEQ_ALIAS,
+ .priv_auto = sizeof(struct dm_test_uc_priv),
};
static const struct udevice_id testfdtm_ids[] = {
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f8ca52efb6b..d862d1e2024 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -311,6 +311,7 @@ config MMC_MXS
config MMC_PCI
bool "Support for MMC controllers on PCI"
+ depends on MMC_SDHCI
help
This selects PCI-based MMC controllers.
If you have an MMC controller on a PCI bus, say Y here.
@@ -326,6 +327,15 @@ config MMC_OCTEONTX
If unsure, say N.
+config MVEBU_MMC
+ bool "Kirkwood MMC controller support"
+ depends on DM_MMC && BLK && ARCH_KIRKWOOD
+ help
+ Support for MMC host controller on Kirkwood SoCs.
+ If you are on a Kirkwood architecture, say Y here.
+
+ If unsure, say N.
+
config PXA_MMC_GENERIC
bool "Support for MMC controllers on PXA"
help
@@ -794,7 +804,7 @@ config FSL_ESDHC_IMX
config FSL_USDHC
bool "Freescale/NXP i.MX uSDHC controller support"
- depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMXRT || TARGET_S32V234EVB
+ depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMXRT
select FSL_ESDHC_IMX
help
This enables the Ultra Secured Digital Host Controller enhancements
@@ -812,3 +822,9 @@ config SYS_FSL_ERRATUM_ESDHC135
config SYS_FSL_ERRATUM_ESDHC_A001
bool
+
+config SYS_FSL_ERRATUM_A011334
+ bool
+
+config SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND
+ bool
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 6014e1c5cac..7501fdb71e1 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -71,7 +71,8 @@ struct fsl_esdhc {
uint sdtimingctl; /* SD timing control register */
char reserved8[20]; /* reserved */
uint dllcfg0; /* DLL config 0 register */
- char reserved9[12]; /* reserved */
+ uint dllcfg1; /* DLL config 1 register */
+ char reserved9[8]; /* reserved */
uint dllstat0; /* DLL status 0 register */
char reserved10[664];/* reserved */
uint esdhcctl; /* eSDHC control register */
@@ -518,6 +519,24 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
while (sdhc_clk / (div * pre_div) > clock && div < 16)
div++;
+ if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) &&
+ clock == 200000000 && mmc->selected_mode == MMC_HS_400) {
+ u32 div_ratio = pre_div * div;
+
+ if (div_ratio <= 4) {
+ pre_div = 4;
+ div = 1;
+ } else if (div_ratio <= 8) {
+ pre_div = 4;
+ div = 2;
+ } else if (div_ratio <= 12) {
+ pre_div = 4;
+ div = 3;
+ } else {
+ printf("unsupported clock division.\n");
+ }
+ }
+
mmc->clock = sdhc_clk / pre_div / div;
priv->clock = mmc->clock;
@@ -749,6 +768,9 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
/* Set timout to the maximum value */
esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
+ if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND))
+ esdhc_clrbits32(&regs->dllcfg1, DLL_PD_PULSE_STRETCH_SEL);
+
return 0;
}
@@ -1063,9 +1085,14 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
struct fsl_esdhc_plat *plat = dev_get_plat(dev);
struct fsl_esdhc_priv *priv = dev_get_priv(dev);
struct fsl_esdhc *regs = priv->esdhc_regs;
+ struct mmc *mmc = &plat->mmc;
u32 val, irqstaten;
int i;
+ if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) &&
+ plat->mmc.hs400_tuning)
+ set_sysctl(priv, mmc, mmc->clock);
+
esdhc_tuning_block_enable(priv, true);
esdhc_setbits32(&regs->autoc12err, EXECUTE_TUNING);
@@ -1073,7 +1100,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
esdhc_write32(&regs->irqstaten, IRQSTATEN_BRR);
for (i = 0; i < MAX_TUNING_LOOP; i++) {
- mmc_send_tuning(&plat->mmc, opcode, NULL);
+ mmc_send_tuning(mmc, opcode, NULL);
mdelay(1);
val = esdhc_read32(&regs->autoc12err);
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c
index 6a9403dc004..a4675838e58 100644
--- a/drivers/mmc/fsl_esdhc_imx.c
+++ b/drivers/mmc/fsl_esdhc_imx.c
@@ -146,6 +146,7 @@ struct esdhc_soc_data {
* @start_tuning_tap: the start point for tuning in tuning_ctrl register
* @strobe_dll_delay_target: settings in strobe_dllctrl
* @signal_voltage: indicating the current voltage
+ * @signal_voltage_switch_extra_delay_ms: extra delay for IO voltage switch
* @cd_gpio: gpio for card detection
* @wp_gpio: gpio for write protection
*/
@@ -170,6 +171,7 @@ struct fsl_esdhc_priv {
u32 tuning_start_tap;
u32 strobe_dll_delay_target;
u32 signal_voltage;
+ u32 signal_voltage_switch_extra_delay_ms;
#if CONFIG_IS_ENABLED(DM_REGULATOR)
struct udevice *vqmmc_dev;
struct udevice *vmmc_dev;
@@ -521,15 +523,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
goto out;
}
- /* Switch voltage to 1.8V if CMD11 succeeded */
- if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) {
- esdhc_setbits32(&regs->vendorspec, ESDHC_VENDORSPEC_VSELECT);
-
- printf("Run CMD11 1.8V switch\n");
- /* Sleep for 5 ms - max time for card to switch to 1.8V */
- udelay(5000);
- }
-
/* Workaround for ESDHC errata ENGcm03648 */
if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
int timeout = 50000;
@@ -660,7 +653,10 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
clk = (pre_div << 8) | (div << 4);
#ifdef CONFIG_FSL_USDHC
- esdhc_clrbits32(&regs->vendorspec, VENDORSPEC_CKEN);
+ esdhc_clrbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
+ ret = readx_poll_timeout(esdhc_read32, &regs->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100);
+ if (ret)
+ pr_warn("fsl_esdhc_imx: Internal clock never gate off.\n");
#else
esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
#endif
@@ -672,7 +668,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
pr_warn("fsl_esdhc_imx: Internal clock never stabilised.\n");
#ifdef CONFIG_FSL_USDHC
- esdhc_setbits32(&regs->vendorspec, VENDORSPEC_PEREN | VENDORSPEC_CKEN);
+ esdhc_setbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
#else
esdhc_setbits32(&regs->sysctl, SYSCTL_PEREN | SYSCTL_CKEN);
#endif
@@ -727,8 +723,14 @@ static void esdhc_set_strobe_dll(struct mmc *mmc)
struct fsl_esdhc_priv *priv = dev_get_priv(mmc->dev);
struct fsl_esdhc *regs = priv->esdhc_regs;
u32 val;
+ u32 tmp;
+ int ret;
if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+ esdhc_clrbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
+ ret = readx_poll_timeout(esdhc_read32, &regs->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100);
+ if (ret)
+ pr_warn("fsl_esdhc_imx: Internal clock never gate off.\n");
esdhc_write32(&regs->strobe_dllctrl, ESDHC_STROBE_DLL_CTRL_RESET);
/*
@@ -746,6 +748,7 @@ static void esdhc_set_strobe_dll(struct mmc *mmc)
pr_warn("HS400 strobe DLL status REF not lock!\n");
if (!(val & ESDHC_STROBE_DLL_STS_SLV_LOCK))
pr_warn("HS400 strobe DLL status SLV not lock!\n");
+ esdhc_setbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
}
}
@@ -835,6 +838,14 @@ static int esdhc_set_voltage(struct mmc *mmc)
}
#endif
esdhc_setbits32(&regs->vendorspec, ESDHC_VENDORSPEC_VSELECT);
+ /*
+ * some board like imx8mm-evk need about 18ms to switch
+ * the IO voltage from 3.3v to 1.8v, common code only
+ * delay 10ms, so need to delay extra time to make sure
+ * the IO voltage change to 1.8v.
+ */
+ if (priv->signal_voltage_switch_extra_delay_ms)
+ mdelay(priv->signal_voltage_switch_extra_delay_ms);
if (esdhc_read32(&regs->vendorspec) & ESDHC_VENDORSPEC_VSELECT)
return 0;
@@ -969,14 +980,18 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
#ifdef MMC_SUPPORTS_TUNING
if (mmc->clk_disable) {
#ifdef CONFIG_FSL_USDHC
- esdhc_clrbits32(&regs->vendorspec, VENDORSPEC_CKEN);
+ u32 tmp;
+
+ esdhc_clrbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
+ ret = readx_poll_timeout(esdhc_read32, &regs->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100);
+ if (ret)
+ pr_warn("fsl_esdhc_imx: Internal clock never gate off.\n");
#else
esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
#endif
} else {
#ifdef CONFIG_FSL_USDHC
- esdhc_setbits32(&regs->vendorspec, VENDORSPEC_PEREN |
- VENDORSPEC_CKEN);
+ esdhc_setbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
#else
esdhc_setbits32(&regs->sysctl, SYSCTL_PEREN | SYSCTL_CKEN);
#endif
@@ -1052,7 +1067,7 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
#ifndef CONFIG_FSL_USDHC
esdhc_setbits32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
#else
- esdhc_setbits32(&regs->vendorspec, VENDORSPEC_HCKEN | VENDORSPEC_IPGEN);
+ esdhc_setbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
#endif
/* Set the initial clock speed */
@@ -1190,8 +1205,7 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv,
esdhc_write32(&regs->autoc12err, 0);
esdhc_write32(&regs->clktunectrlstatus, 0);
#else
- esdhc_setbits32(&regs->vendorspec, VENDORSPEC_PEREN |
- VENDORSPEC_HCKEN | VENDORSPEC_IPGEN | VENDORSPEC_CKEN);
+ esdhc_setbits32(&regs->vendorspec, VENDORSPEC_FRC_SDCLK_ON);
#endif
if (priv->vs18_enable)
@@ -1446,6 +1460,8 @@ static int fsl_esdhc_of_to_plat(struct udevice *dev)
val = fdtdec_get_int(fdt, node, "fsl,strobe-dll-delay-target",
ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT);
priv->strobe_dll_delay_target = val;
+ val = fdtdec_get_int(fdt, node, "fsl,signal-voltage-switch-extra-delay-ms", 0);
+ priv->signal_voltage_switch_extra_delay_ms = val;
if (dev_read_bool(dev, "broken-cd"))
priv->broken_cd = 1;
@@ -1530,8 +1546,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) {
struct udevice *gpiodev;
- ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx,
- &gpiodev);
+ ret = device_get_by_ofplat_idx(dtplat->cd_gpios->idx, &gpiodev);
if (ret)
return ret;
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 53eabc9e612..d36aae367e7 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -383,18 +383,16 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
{
struct blk_desc *bdesc;
struct udevice *bdev;
- int ret, devnum = -1;
+ int ret;
if (!mmc_get_ops(dev))
return -ENOSYS;
-#ifndef CONFIG_SPL_BUILD
- /* Use the fixed index with aliase node's index */
- ret = dev_read_alias_seq(dev, &devnum);
- debug("%s: alias ret=%d, devnum=%d\n", __func__, ret, devnum);
-#endif
+
+ /* Use the fixed index with aliases node's index */
+ debug("%s: alias devnum=%d\n", __func__, dev_seq(dev));
ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC,
- devnum, 512, 0, &bdev);
+ dev_seq(dev), 512, 0, &bdev);
if (ret) {
debug("Cannot create block device\n");
return ret;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index b4c8e7f293b..1e83007286b 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -3052,9 +3052,11 @@ int mmc_init_device(int num)
struct mmc *m;
int ret;
- ret = uclass_get_device(UCLASS_MMC, num, &dev);
- if (ret)
- return ret;
+ if (uclass_get_device_by_seq(UCLASS_MMC, num, &dev)) {
+ ret = uclass_get_device(UCLASS_MMC, num, &dev);
+ if (ret)
+ return ret;
+ }
m = mmc_get_mmc_dev(dev);
if (!m)
diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c
index 8ec1f57a1b7..fea55c61ed7 100644
--- a/drivers/mmc/mvebu_mmc.c
+++ b/drivers/mmc/mvebu_mmc.c
@@ -11,60 +11,67 @@
#include <errno.h>
#include <log.h>
#include <malloc.h>
+#include <dm.h>
+#include <fdtdec.h>
#include <part.h>
#include <mmc.h>
-#include <asm/global_data.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <mvebu_mmc.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define DRIVER_NAME "MVEBU_MMC"
+#include <dm/device_compat.h>
#define MVEBU_TARGET_DRAM 0
#define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */
-static void mvebu_mmc_write(u32 offs, u32 val)
+static inline void *get_regbase(const struct mmc *mmc)
{
- writel(val, CONFIG_SYS_MMC_BASE + (offs));
+ struct mvebu_mmc_plat *pdata = mmc->priv;
+
+ return pdata->iobase;
}
-static u32 mvebu_mmc_read(u32 offs)
+static void mvebu_mmc_write(const struct mmc *mmc, u32 offs, u32 val)
{
- return readl(CONFIG_SYS_MMC_BASE + (offs));
+ writel(val, get_regbase(mmc) + (offs));
}
-static int mvebu_mmc_setup_data(struct mmc_data *data)
+static u32 mvebu_mmc_read(const struct mmc *mmc, u32 offs)
{
+ return readl(get_regbase(mmc) + (offs));
+}
+
+static int mvebu_mmc_setup_data(struct udevice *dev, struct mmc_data *data)
+{
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
u32 ctrl_reg;
- debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME,
- (data->flags & MMC_DATA_READ) ? "read" : "write",
- data->blocks, data->blocksize);
+ dev_dbg(dev, "data %s : blocks=%d blksz=%d\n",
+ (data->flags & MMC_DATA_READ) ? "read" : "write",
+ data->blocks, data->blocksize);
/* default to maximum timeout */
- ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL);
+ ctrl_reg = mvebu_mmc_read(mmc, SDIO_HOST_CTRL);
ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
- mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
+ mvebu_mmc_write(mmc, SDIO_HOST_CTRL, ctrl_reg);
if (data->flags & MMC_DATA_READ) {
- mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff);
- mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16);
+ mvebu_mmc_write(mmc, SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff);
+ mvebu_mmc_write(mmc, SDIO_SYS_ADDR_HI, (u32)data->dest >> 16);
} else {
- mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff);
- mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16);
+ mvebu_mmc_write(mmc, SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff);
+ mvebu_mmc_write(mmc, SDIO_SYS_ADDR_HI, (u32)data->src >> 16);
}
- mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks);
- mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize);
+ mvebu_mmc_write(mmc, SDIO_BLK_COUNT, data->blocks);
+ mvebu_mmc_write(mmc, SDIO_BLK_SIZE, data->blocksize);
return 0;
}
-static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+static int mvebu_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
ulong start;
@@ -72,12 +79,14 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
ushort resptype = 0;
ushort xfertype = 0;
ushort resp_indx = 0;
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
- debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n",
- DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
+ dev_dbg(dev, "cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n",
+ cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
- debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME,
- cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE));
+ dev_dbg(dev, "cmd %d (hw state 0x%04x)\n",
+ cmd->cmdidx, mvebu_mmc_read(mmc, SDIO_HW_STATE));
/*
* Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE
@@ -88,26 +97,26 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
* this bit comes to good sense (which eventually happens by
* itself) then the new transfer simply fails with a timeout.
*/
- if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) {
+ if (!(mvebu_mmc_read(mmc, SDIO_HW_STATE) & CMD_FIFO_EMPTY)) {
ushort hw_state, count = 0;
start = get_timer(0);
do {
- hw_state = mvebu_mmc_read(SDIO_HW_STATE);
+ hw_state = mvebu_mmc_read(mmc, SDIO_HW_STATE);
if ((get_timer(0) - start) > TIMEOUT_DELAY) {
printf("%s : FIFO_EMPTY bit missing\n",
- DRIVER_NAME);
+ dev->name);
break;
}
count++;
} while (!(hw_state & CMD_FIFO_EMPTY));
- debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n",
- DRIVER_NAME, hw_state, count, (get_timer(0) - (start)));
+ dev_dbg(dev, "*** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n",
+ hw_state, count, (get_timer(0) - (start)));
}
/* Clear status */
- mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
- mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
resptype = SDIO_CMD_INDEX(cmd->cmdidx);
@@ -133,11 +142,10 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
if (data) {
- int err = mvebu_mmc_setup_data(data);
+ int err = mvebu_mmc_setup_data(dev, data);
if (err) {
- debug("%s: command DATA error :%x\n",
- DRIVER_NAME, err);
+ dev_dbg(dev, "command DATA error :%x\n", err);
return err;
}
@@ -154,34 +162,33 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
/* Setting cmd arguments */
- mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff);
- mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16);
+ mvebu_mmc_write(mmc, SDIO_ARG_LOW, cmd->cmdarg & 0xffff);
+ mvebu_mmc_write(mmc, SDIO_ARG_HI, cmd->cmdarg >> 16);
/* Setting Xfer mode */
- mvebu_mmc_write(SDIO_XFER_MODE, xfertype);
+ mvebu_mmc_write(mmc, SDIO_XFER_MODE, xfertype);
/* Sending command */
- mvebu_mmc_write(SDIO_CMD, resptype);
+ mvebu_mmc_write(mmc, SDIO_CMD, resptype);
start = get_timer(0);
- while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) {
- if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) {
- debug("%s: error! cmdidx : %d, err reg: %04x\n",
- DRIVER_NAME, cmd->cmdidx,
- mvebu_mmc_read(SDIO_ERR_INTR_STATUS));
- if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
+ while (!((mvebu_mmc_read(mmc, SDIO_NOR_INTR_STATUS)) & waittype)) {
+ if (mvebu_mmc_read(mmc, SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) {
+ dev_dbg(dev, "error! cmdidx : %d, err reg: %04x\n",
+ cmd->cmdidx,
+ mvebu_mmc_read(mmc, SDIO_ERR_INTR_STATUS));
+ if (mvebu_mmc_read(mmc, SDIO_ERR_INTR_STATUS) &
(SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) {
- debug("%s: command READ timed out\n",
- DRIVER_NAME);
+ dev_dbg(dev, "command READ timed out\n");
return -ETIMEDOUT;
}
- debug("%s: command READ error\n", DRIVER_NAME);
+ dev_dbg(dev, "command READ error\n");
return -ECOMM;
}
if ((get_timer(0) - start) > TIMEOUT_DELAY) {
- debug("%s: command timed out\n", DRIVER_NAME);
+ dev_dbg(dev, "command timed out\n");
return -ETIMEDOUT;
}
}
@@ -191,8 +198,7 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
uint response[8];
for (resp_indx = 0; resp_indx < 8; resp_indx++)
- response[resp_indx]
- = mvebu_mmc_read(SDIO_RSP(resp_indx));
+ response[resp_indx] = mvebu_mmc_read(mmc, SDIO_RSP(resp_indx));
cmd->response[0] = ((response[0] & 0x03ff) << 22) |
((response[1] & 0xffff) << 6) |
@@ -209,8 +215,7 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
uint response[3];
for (resp_indx = 0; resp_indx < 3; resp_indx++)
- response[resp_indx]
- = mvebu_mmc_read(SDIO_RSP(resp_indx));
+ response[resp_indx] = mvebu_mmc_read(mmc, SDIO_RSP(resp_indx));
cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) |
((response[1] & 0xffff) << (14 - 8)) |
@@ -225,64 +230,71 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
cmd->response[3] = 0;
}
- debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type);
+ dev_dbg(dev, "resp[0x%x] ", cmd->resp_type);
debug("[0x%x] ", cmd->response[0]);
debug("[0x%x] ", cmd->response[1]);
debug("[0x%x] ", cmd->response[2]);
debug("[0x%x] ", cmd->response[3]);
debug("\n");
- if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
+ if (mvebu_mmc_read(mmc, SDIO_ERR_INTR_STATUS) &
(SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
return -ETIMEDOUT;
return 0;
}
-static void mvebu_mmc_power_up(void)
+static void mvebu_mmc_power_up(struct udevice *dev)
{
- debug("%s: power up\n", DRIVER_NAME);
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
+
+ dev_dbg(dev, "power up\n");
/* disable interrupts */
- mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
- mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
+ mvebu_mmc_write(mmc, SDIO_NOR_INTR_EN, 0);
+ mvebu_mmc_write(mmc, SDIO_ERR_INTR_EN, 0);
/* SW reset */
- mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
+ mvebu_mmc_write(mmc, SDIO_SW_RESET, SDIO_SW_RESET_NOW);
- mvebu_mmc_write(SDIO_XFER_MODE, 0);
+ mvebu_mmc_write(mmc, SDIO_XFER_MODE, 0);
/* enable status */
- mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
- mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
/* enable interrupts status */
- mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
- mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
}
-static void mvebu_mmc_set_clk(unsigned int clock)
+static void mvebu_mmc_set_clk(struct udevice *dev, unsigned int clock)
{
unsigned int m;
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
if (clock == 0) {
- debug("%s: clock off\n", DRIVER_NAME);
- mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK);
- mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX);
+ dev_dbg(dev, "clock off\n");
+ mvebu_mmc_write(mmc, SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK);
+ mvebu_mmc_write(mmc, SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX);
} else {
m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1;
if (m > MVEBU_MMC_BASE_DIV_MAX)
m = MVEBU_MMC_BASE_DIV_MAX;
- mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX);
- debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m);
+ mvebu_mmc_write(mmc, SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX);
+ dev_dbg(dev, "clock (%d) div : %d\n", clock, m);
}
}
-static void mvebu_mmc_set_bus(unsigned int bus)
+static void mvebu_mmc_set_bus(struct udevice *dev, unsigned int bus)
{
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
u32 ctrl_reg = 0;
- ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL);
+ ctrl_reg = mvebu_mmc_read(mmc, SDIO_HOST_CTRL);
ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
switch (bus) {
@@ -306,23 +318,26 @@ static void mvebu_mmc_set_bus(unsigned int bus)
ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY;
- debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg,
- (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ?
- "push-pull" : "open-drain",
- (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ?
- "4bit-width" : "1bit-width",
- (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ?
- "high-speed" : "");
+ dev_dbg(dev, "ctrl 0x%04x: %s %s %s\n", ctrl_reg,
+ (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ?
+ "push-pull" : "open-drain",
+ (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ?
+ "4bit-width" : "1bit-width",
+ (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ?
+ "high-speed" : "");
- mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
+ mvebu_mmc_write(mmc, SDIO_HOST_CTRL, ctrl_reg);
}
-static int mvebu_mmc_set_ios(struct mmc *mmc)
+static int mvebu_mmc_set_ios(struct udevice *dev)
{
- debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME,
- mmc->bus_width, mmc->clock);
- mvebu_mmc_set_bus(mmc->bus_width);
- mvebu_mmc_set_clk(mmc->clock);
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
+
+ dev_dbg(dev, "bus[%d] clock[%d]\n",
+ mmc->bus_width, mmc->clock);
+ mvebu_mmc_set_bus(dev, mmc->bus_width);
+ mvebu_mmc_set_clk(dev, mmc->clock);
return 0;
}
@@ -330,13 +345,13 @@ static int mvebu_mmc_set_ios(struct mmc *mmc)
/*
* Set window register.
*/
-static void mvebu_window_setup(void)
+static void mvebu_window_setup(const struct mmc *mmc)
{
int i;
for (i = 0; i < 4; i++) {
- mvebu_mmc_write(WINDOW_CTRL(i), 0);
- mvebu_mmc_write(WINDOW_BASE(i), 0);
+ mvebu_mmc_write(mmc, WINDOW_CTRL(i), 0);
+ mvebu_mmc_write(mmc, WINDOW_BASE(i), 0);
}
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
u32 size, base, attrib;
@@ -364,79 +379,119 @@ static void mvebu_window_setup(void)
size = gd->bd->bi_dram[i].size;
base = gd->bd->bi_dram[i].start;
if (size && attrib) {
- mvebu_mmc_write(WINDOW_CTRL(i),
+ mvebu_mmc_write(mmc, WINDOW_CTRL(i),
MVCPU_WIN_CTRL_DATA(size,
MVEBU_TARGET_DRAM,
attrib,
MVCPU_WIN_ENABLE));
} else {
- mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE);
+ mvebu_mmc_write(mmc, WINDOW_CTRL(i), MVCPU_WIN_DISABLE);
}
- mvebu_mmc_write(WINDOW_BASE(i), base);
+ mvebu_mmc_write(mmc, WINDOW_BASE(i), base);
}
}
-static int mvebu_mmc_initialize(struct mmc *mmc)
+static int mvebu_mmc_initialize(struct udevice *dev)
{
- debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME);
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc *mmc = &pdata->mmc;
+
+ dev_dbg(dev, "%s\n", __func__);
/*
* Setting host parameters
* Initial Host Ctrl : Timeout : max , Normal Speed mode,
* 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line
*/
- mvebu_mmc_write(SDIO_HOST_CTRL,
+ mvebu_mmc_write(mmc, SDIO_HOST_CTRL,
SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) |
SDIO_HOST_CTRL_DATA_WIDTH_4_BITS |
SDIO_HOST_CTRL_BIG_ENDIAN |
SDIO_HOST_CTRL_PUSH_PULL_EN |
SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY);
- mvebu_mmc_write(SDIO_CLK_CTRL, 0);
+ mvebu_mmc_write(mmc, SDIO_CLK_CTRL, 0);
/* enable status */
- mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
- mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
+ mvebu_mmc_write(mmc, SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
/* disable interrupts */
- mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
- mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
+ mvebu_mmc_write(mmc, SDIO_NOR_INTR_EN, 0);
+ mvebu_mmc_write(mmc, SDIO_ERR_INTR_EN, 0);
- mvebu_window_setup();
+ mvebu_window_setup(mmc);
/* SW reset */
- mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
+ mvebu_mmc_write(mmc, SDIO_SW_RESET, SDIO_SW_RESET_NOW);
return 0;
}
-static const struct mmc_ops mvebu_mmc_ops = {
- .send_cmd = mvebu_mmc_send_cmd,
- .set_ios = mvebu_mmc_set_ios,
- .init = mvebu_mmc_initialize,
-};
+static int mvebu_mmc_of_to_plat(struct udevice *dev)
+{
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ fdt_addr_t addr;
-static struct mmc_config mvebu_mmc_cfg = {
- .name = DRIVER_NAME,
- .ops = &mvebu_mmc_ops,
- .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX,
- .f_max = MVEBU_MMC_CLOCKRATE_MAX,
- .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
- .host_caps = MMC_MODE_4BIT | MMC_MODE_HS |
- MMC_MODE_HS_52MHz,
- .part_type = PART_TYPE_DOS,
- .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
-};
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
-int mvebu_mmc_init(struct bd_info *bis)
-{
- struct mmc *mmc;
+ pdata->iobase = (void *)addr;
- mvebu_mmc_power_up();
+ return 0;
+}
- mmc = mmc_create(&mvebu_mmc_cfg, bis);
- if (mmc == NULL)
- return -1;
+static int mvebu_mmc_probe(struct udevice *dev)
+{
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct mmc *mmc = &pdata->mmc;
+ struct mmc_config *cfg = &pdata->cfg;
+
+ cfg->name = dev->name;
+ cfg->f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX;
+ cfg->f_max = MVEBU_MMC_CLOCKRATE_MAX;
+ cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+ cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz;
+ cfg->part_type = PART_TYPE_DOS;
+ cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+ mmc->cfg = cfg;
+ mmc->priv = pdata;
+ mmc->dev = dev;
+ upriv->mmc = mmc;
+
+ mvebu_mmc_power_up(dev);
+ mvebu_mmc_initialize(dev);
return 0;
}
+
+static const struct dm_mmc_ops mvebu_dm_mmc_ops = {
+ .send_cmd = mvebu_mmc_send_cmd,
+ .set_ios = mvebu_mmc_set_ios,
+};
+
+static int mvebu_mmc_bind(struct udevice *dev)
+{
+ struct mvebu_mmc_plat *pdata = dev_get_plat(dev);
+
+ return mmc_bind(dev, &pdata->mmc, &pdata->cfg);
+}
+
+static const struct udevice_id mvebu_mmc_match[] = {
+ { .compatible = "marvell,orion-sdio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mvebu_mmc) = {
+ .name = "mvebu_mmc",
+ .id = UCLASS_MMC,
+ .of_match = mvebu_mmc_match,
+ .ops = &mvebu_dm_mmc_ops,
+ .probe = mvebu_mmc_probe,
+ .bind = mvebu_mmc_bind,
+ .of_to_plat = mvebu_mmc_of_to_plat,
+ .plat_auto = sizeof(struct mvebu_mmc_plat),
+};
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index fd5dd229b58..b9ab064b60e 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -53,6 +53,7 @@ static int pci_mmc_probe(struct udevice *dev)
host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
host->name = dev->name;
+ host->cd_gpio = priv->cd_gpio;
host->mmc = &plat->mmc;
host->mmc->dev = dev;
ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
@@ -68,8 +69,11 @@ static int pci_mmc_of_to_plat(struct udevice *dev)
{
if (CONFIG_IS_ENABLED(DM_GPIO)) {
struct pci_mmc_priv *priv = dev_get_priv(dev);
+ int ret;
- gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
+ ret = gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
+ GPIOD_IS_IN);
+ log_debug("cd-gpio %s done, ret=%d\n", dev->name, ret);
}
return 0;
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index b4512e3a5fc..9642d7c7dc3 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -218,7 +218,7 @@ flash_map(flash_info_t *info, flash_sect_t sect, uint offset)
{
unsigned int byte_offset = offset * info->portwidth;
- return (void *)(info->start[sect] + byte_offset);
+ return (void *)(info->start[sect] + (byte_offset << info->chip_lsb));
}
static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
@@ -1918,12 +1918,27 @@ static int __flash_detect_cfi(flash_info_t *info, struct cfi_qry *qry)
flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
sizeof(struct cfi_qry));
info->interface = le16_to_cpu(qry->interface_desc);
+ /* Some flash chips can support multiple bus widths.
+ * In this case, override the interface width and
+ * limit it to the port width.
+ */
+ if ((info->interface == FLASH_CFI_X8X16) &&
+ (info->portwidth == FLASH_CFI_8BIT)) {
+ debug("Overriding 16-bit interface width to"
+ " 8-bit port width\n");
+ info->interface = FLASH_CFI_X8;
+ } else if ((info->interface == FLASH_CFI_X16X32) &&
+ (info->portwidth == FLASH_CFI_16BIT)) {
+ debug("Overriding 16-bit interface width to"
+ " 16-bit port width\n");
+ info->interface = FLASH_CFI_X16;
+ }
info->cfi_offset = flash_offset_cfi[cfi_offset];
debug("device interface is %d\n",
info->interface);
- debug("found port %d chip %d ",
- info->portwidth, info->chipwidth);
+ debug("found port %d chip %d chip_lsb %d ",
+ info->portwidth, info->chipwidth, info->chip_lsb);
debug("port %d bits chip %d bits\n",
info->portwidth << CFI_FLASH_SHIFT_WIDTH,
info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
@@ -1962,9 +1977,23 @@ static int flash_detect_cfi(flash_info_t *info, struct cfi_qry *qry)
info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
for (info->chipwidth = FLASH_CFI_BY8;
info->chipwidth <= info->portwidth;
- info->chipwidth <<= 1)
+ info->chipwidth <<= 1) {
+ /*
+ * First, try detection without shifting the addresses
+ * for 8bit devices (16bit wide connection)
+ */
+ info->chip_lsb = 0;
+ if (__flash_detect_cfi(info, qry))
+ return 1;
+
+ /*
+ * Not detected, so let's try with shifting
+ * for 8bit devices
+ */
+ info->chip_lsb = 1;
if (__flash_detect_cfi(info, qry))
return 1;
+ }
}
debug("not found\n");
return 0;
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index 46dc29df369..17f46ae5e91 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -282,6 +282,11 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
return 0;
}
+struct mtd_info *nand_get_mtd(void)
+{
+ return mtd;
+}
+
int nand_default_bbt(struct mtd_info *mtd)
{
return 0;
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6557faddf94..3679ee727e9 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -3559,6 +3559,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
+ instr->fail_addr =
+ ((loff_t)page << chip->page_shift);
goto erase_exit;
}
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 12d132152d3..cfce00ef548 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -31,6 +31,15 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len)
return log_ret(sf_get_ops(dev)->erase(dev, offset, len));
}
+int spl_flash_get_sw_write_prot(struct udevice *dev)
+{
+ struct dm_spi_flash_ops *ops = sf_get_ops(dev);
+
+ if (!ops->get_sw_write_prot)
+ return -ENOSYS;
+ return log_ret(ops->get_sw_write_prot(dev));
+}
+
/*
* TODO(sjg@chromium.org): This is an old-style function. We should remove
* it when all SPI flash drivers use dm
@@ -46,11 +55,6 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
return dev_get_uclass_priv(dev);
}
-void spi_flash_free(struct spi_flash *flash)
-{
- device_remove(flash->spi->dev, DM_REMOVE_NORMAL);
-}
-
int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode,
struct udevice **devp)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 9ceff0e7c12..786301ba4a9 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -75,6 +75,10 @@ extern const struct flash_info spi_nor_ids[];
#define JEDEC_MFR(info) ((info)->id[0])
#define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2]))
+/* Get software write-protect value (BP bits) */
+int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash);
+
+
#if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
int spi_flash_mtd_register(struct spi_flash *flash);
void spi_flash_mtd_unregister(void);
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 6c874348676..3befbe91cac 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -130,6 +130,13 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
return mtd->_erase(mtd, &instr);
}
+static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
+{
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+ return spi_flash_cmd_get_sw_write_prot(flash);
+}
+
int spi_flash_std_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parent_priv(dev);
@@ -153,6 +160,7 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = {
.read = spi_flash_std_read,
.write = spi_flash_std_write,
.erase = spi_flash_std_erase,
+ .get_sw_write_prot = spi_flash_std_get_sw_write_prot,
};
static const struct udevice_id spi_flash_std_ids[] = {
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index e0efebc3555..a6625535a70 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2647,3 +2647,14 @@ int spi_nor_scan(struct spi_nor *nor)
return 0;
}
+
+/* U-Boot specific functions, need to extend MTD to support these */
+int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor)
+{
+ int sr = read_sr(nor);
+
+ if (sr < 0)
+ return sr;
+
+ return (sr >> 2) & 7;
+}
diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index 07c8c7b82b1..1d5861d55cd 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -809,3 +809,9 @@ int spi_nor_scan(struct spi_nor *nor)
return 0;
}
+
+/* U-Boot specific functions, need to extend MTD to support these */
+int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor)
+{
+ return -ENOTSUPP;
+}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0e84c22b507..72822eaec4b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -78,6 +78,15 @@ config DM_ETH_PHY
help
Enable driver model for Ethernet Generic PHY .
+config DSA_SANDBOX
+ depends on DM_DSA && SANDBOX
+ default y
+ bool "Sandbox: Mocked DSA driver"
+ help
+ This driver implements a dummy DSA switch connected to a dummy sandbox
+ Ethernet device used as DSA master, to test DSA class code, including
+ exported DSA API and datapath processing of Ethernet traffic.
+
menuconfig NETDEVICES
bool "Network device support"
depends on NET
@@ -271,6 +280,14 @@ config ETH_DESIGNWARE
100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to
provide the PHY (physical media interface).
+config ETH_DESIGNWARE_MESON8B
+ bool "Amlogic Meson8b and later glue driver for Synopsys Designware Ethernet MAC"
+ depends on DM_ETH
+ select ETH_DESIGNWARE
+ help
+ This provides glue layer to use Synopsys Designware Ethernet MAC
+ present on the Amlogic Meson8b, GX, AXG & G12A SoCs.
+
config ETH_DESIGNWARE_SOCFPGA
select REGMAP
select SYSCON
@@ -713,13 +730,11 @@ config SYS_DPAA_QBMAN
ARCH_T1040 || \
ARCH_T1042 || \
ARCH_T2080 || \
- ARCH_T2081 || \
ARCH_T4240 || \
ARCH_T4160 || \
ARCH_P4080 || \
ARCH_P3041 || \
ARCH_P5040 || \
- ARCH_P5020 || \
ARCH_LS1043A || \
ARCH_LS1046A
help
@@ -790,4 +805,18 @@ config FSL_LS_MDIO
This driver supports the MDIO bus found on the Fman 10G Ethernet MACs and
on the mEMAC (which supports both Clauses 22 and 45).
+config MDIO_MUX_MMIOREG
+ bool "MDIO MUX accessed as a MMIO register access"
+ depends on DM_MDIO_MUX
+ help
+ This driver is used for MDIO muxes driven by writing to a register in
+ the MMIO physical memory.
+
+config MDIO_MUX_MESON_G12A
+ bool "MDIO MUX for Amlogic Meson G12A SoCs"
+ depends on DM_MDIO_MUX
+ help
+ This driver is used for the MDIO mux found on the Amlogic G12A & compatible
+ SoCs.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a19511aaa7b..2ce89f7e3c6 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -18,10 +18,12 @@ obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
obj-$(CONFIG_CS8900) += cs8900.o
obj-$(CONFIG_TULIP) += dc2114x.o
obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
+obj-$(CONFIG_ETH_DESIGNWARE_MESON8B) += dwmac_meson8b.o
obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
obj-$(CONFIG_ETH_DESIGNWARE_S700) += dwmac_s700.o
obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
obj-$(CONFIG_DNET) += dnet.o
+obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
obj-$(CONFIG_E1000) += e1000.o
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
@@ -43,6 +45,8 @@ obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o
obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o
+obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o
+obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o
obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 9dba55adaa7..b8ba00b7c0c 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -21,7 +21,9 @@
#include <reset.h>
#include <asm/cache.h>
#include <dm/device_compat.h>
+#include <dm/device-internal.h>
#include <dm/devres.h>
+#include <dm/lists.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -122,6 +124,55 @@ static int dw_mdio_reset(struct mii_dev *bus)
}
#endif
+#if IS_ENABLED(CONFIG_DM_MDIO)
+int designware_eth_mdio_read(struct udevice *mdio_dev, int addr, int devad, int reg)
+{
+ struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdio_dev);
+
+ return dw_mdio_read(pdata->mii_bus, addr, devad, reg);
+}
+
+int designware_eth_mdio_write(struct udevice *mdio_dev, int addr, int devad, int reg, u16 val)
+{
+ struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdio_dev);
+
+ return dw_mdio_write(pdata->mii_bus, addr, devad, reg, val);
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+int designware_eth_mdio_reset(struct udevice *mdio_dev)
+{
+ struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdio_dev);
+
+ return dw_mdio_reset(pdata->mii_bus);
+}
+#endif
+
+static const struct mdio_ops designware_eth_mdio_ops = {
+ .read = designware_eth_mdio_read,
+ .write = designware_eth_mdio_write,
+#if CONFIG_IS_ENABLED(DM_GPIO)
+ .reset = designware_eth_mdio_reset,
+#endif
+};
+
+static int designware_eth_mdio_probe(struct udevice *dev)
+{
+ /* Use the priv data of parent */
+ dev_set_priv(dev, dev_get_priv(dev->parent));
+
+ return 0;
+}
+
+U_BOOT_DRIVER(designware_eth_mdio) = {
+ .name = "eth_designware_mdio",
+ .id = UCLASS_MDIO,
+ .probe = designware_eth_mdio_probe,
+ .ops = &designware_eth_mdio_ops,
+ .plat_auto = sizeof(struct mdio_perdev_priv),
+};
+#endif
+
static int dw_mdio_init(const char *name, void *priv)
{
struct mii_dev *bus = mdio_alloc();
@@ -143,6 +194,34 @@ static int dw_mdio_init(const char *name, void *priv)
return mdio_register(bus);
}
+#if IS_ENABLED(CONFIG_DM_MDIO)
+static int dw_dm_mdio_init(const char *name, void *priv)
+{
+ struct udevice *dev = priv;
+ ofnode node;
+ int ret;
+
+ ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+ const char *subnode_name = ofnode_get_name(node);
+ struct udevice *mdiodev;
+
+ if (strcmp(subnode_name, "mdio"))
+ continue;
+
+ ret = device_bind_driver_to_node(dev, "eth_designware_mdio",
+ subnode_name, node, &mdiodev);
+ if (ret)
+ debug("%s: not able to bind mdio device node\n", __func__);
+
+ return 0;
+ }
+
+ printf("%s: mdio node is missing, registering legacy mdio bus", __func__);
+
+ return dw_mdio_init(name, priv);
+}
+#endif
+
static void tx_descs_init(struct dw_eth_dev *priv)
{
struct eth_dma_regs *dma_p = priv->dma_regs_p;
@@ -487,7 +566,14 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
- int phy_addr = -1, ret;
+ int ret;
+
+#if IS_ENABLED(CONFIG_DM_MDIO) && IS_ENABLED(CONFIG_DM_ETH)
+ phydev = dm_eth_phy_connect(dev);
+ if (!phydev)
+ return -ENODEV;
+#else
+ int phy_addr = -1;
#ifdef CONFIG_PHY_ADDR
phy_addr = CONFIG_PHY_ADDR;
@@ -496,6 +582,7 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
phydev = phy_connect(priv->bus, phy_addr, dev, priv->interface);
if (!phydev)
return -ENODEV;
+#endif
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
@@ -759,7 +846,11 @@ int designware_eth_probe(struct udevice *dev)
priv->interface = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
+#if IS_ENABLED(CONFIG_DM_MDIO)
+ ret = dw_dm_mdio_init(dev->name, dev);
+#else
ret = dw_mdio_init(dev->name, dev);
+#endif
if (ret) {
err = ret;
goto mdio_err;
@@ -856,9 +947,6 @@ int designware_eth_of_to_plat(struct udevice *dev)
static const struct udevice_id designware_eth_ids[] = {
{ .compatible = "allwinner,sun7i-a20-gmac" },
{ .compatible = "amlogic,meson6-dwmac" },
- { .compatible = "amlogic,meson-gx-dwmac" },
- { .compatible = "amlogic,meson-gxbb-dwmac" },
- { .compatible = "amlogic,meson-axg-dwmac" },
{ .compatible = "st,stm32-dwmac" },
{ .compatible = "snps,arc-dwmac-3.70a" },
{ }
diff --git a/drivers/net/dsa_sandbox.c b/drivers/net/dsa_sandbox.c
new file mode 100644
index 00000000000..4b62670e5d1
--- /dev/null
+++ b/drivers/net/dsa_sandbox.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2021 NXP Semiconductors
+ */
+
+#include <asm/eth.h>
+#include <net/dsa.h>
+#include <net.h>
+
+#define DSA_SANDBOX_MAGIC 0x00415344
+#define DSA_SANDBOX_TAG_LEN sizeof(struct dsa_sandbox_tag)
+
+struct dsa_sandbox_priv {
+ struct eth_sandbox_priv *master_priv;
+ int port_en_mask;
+};
+
+struct dsa_sandbox_tag {
+ u32 magic;
+ u32 port;
+};
+
+static bool sb_dsa_port_enabled(struct udevice *dev, int port)
+{
+ struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+ return priv->port_en_mask & BIT(port);
+}
+
+static bool sb_dsa_master_enabled(struct udevice *dev)
+{
+ struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+ return !priv->master_priv->disabled;
+}
+
+static int dsa_sandbox_port_enable(struct udevice *dev, int port,
+ struct phy_device *phy)
+{
+ struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+ if (!sb_dsa_master_enabled(dev))
+ return -EFAULT;
+
+ priv->port_en_mask |= BIT(port);
+
+ return 0;
+}
+
+static void dsa_sandbox_port_disable(struct udevice *dev, int port,
+ struct phy_device *phy)
+{
+ struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+ priv->port_en_mask &= ~BIT(port);
+}
+
+static int dsa_sandbox_xmit(struct udevice *dev, int port, void *packet,
+ int length)
+{
+ struct dsa_sandbox_tag *tag = packet;
+
+ if (!sb_dsa_master_enabled(dev))
+ return -EFAULT;
+
+ if (!sb_dsa_port_enabled(dev, port))
+ return -EFAULT;
+
+ tag->magic = DSA_SANDBOX_MAGIC;
+ tag->port = port;
+
+ return 0;
+}
+
+static int dsa_sandbox_rcv(struct udevice *dev, int *port, void *packet,
+ int length)
+{
+ struct dsa_sandbox_tag *tag = packet;
+
+ if (!sb_dsa_master_enabled(dev))
+ return -EFAULT;
+
+ if (tag->magic != DSA_SANDBOX_MAGIC)
+ return -EFAULT;
+
+ *port = tag->port;
+ if (!sb_dsa_port_enabled(dev, tag->port))
+ return -EFAULT;
+
+ return 0;
+}
+
+static const struct dsa_ops dsa_sandbox_ops = {
+ .port_enable = dsa_sandbox_port_enable,
+ .port_disable = dsa_sandbox_port_disable,
+ .xmit = dsa_sandbox_xmit,
+ .rcv = dsa_sandbox_rcv,
+};
+
+static int sb_dsa_handler(struct udevice *dev, void *packet,
+ unsigned int len)
+{
+ struct eth_sandbox_priv *master_priv;
+ struct dsa_sandbox_tag *tag = packet;
+ struct udevice *dsa_dev;
+ u32 port_index;
+ void *rx_buf;
+ int i;
+
+ /* this emulates the switch hw and the network side */
+ if (tag->magic != DSA_SANDBOX_MAGIC)
+ return -EFAULT;
+
+ port_index = tag->port;
+ master_priv = dev_get_priv(dev);
+ dsa_dev = master_priv->priv;
+ if (!sb_dsa_port_enabled(dsa_dev, port_index))
+ return -EFAULT;
+
+ packet += DSA_SANDBOX_TAG_LEN;
+ len -= DSA_SANDBOX_TAG_LEN;
+
+ if (!sandbox_eth_arp_req_to_reply(dev, packet, len))
+ goto dsa_tagging;
+ if (!sandbox_eth_ping_req_to_reply(dev, packet, len))
+ goto dsa_tagging;
+
+ return 0;
+
+dsa_tagging:
+ master_priv->recv_packets--;
+ i = master_priv->recv_packets;
+ rx_buf = master_priv->recv_packet_buffer[i];
+ len = master_priv->recv_packet_length[i];
+ memmove(rx_buf + DSA_SANDBOX_TAG_LEN, rx_buf, len);
+
+ tag = rx_buf;
+ tag->magic = DSA_SANDBOX_MAGIC;
+ tag->port = port_index;
+ len += DSA_SANDBOX_TAG_LEN;
+ master_priv->recv_packet_length[i] = len;
+ master_priv->recv_packets++;
+
+ return 0;
+}
+
+static int dsa_sandbox_probe(struct udevice *dev)
+{
+ struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+ struct udevice *master = dsa_get_master(dev);
+ struct eth_sandbox_priv *master_priv;
+
+ if (!master)
+ return -ENODEV;
+
+ dsa_set_tagging(dev, DSA_SANDBOX_TAG_LEN, 0);
+
+ master_priv = dev_get_priv(master);
+ master_priv->priv = dev;
+ master_priv->tx_handler = sb_dsa_handler;
+
+ priv->master_priv = master_priv;
+
+ return 0;
+}
+
+static const struct udevice_id dsa_sandbox_ids[] = {
+ { .compatible = "sandbox,dsa" },
+ { }
+};
+
+U_BOOT_DRIVER(dsa_sandbox) = {
+ .name = "dsa_sandbox",
+ .id = UCLASS_DSA,
+ .of_match = dsa_sandbox_ids,
+ .probe = dsa_sandbox_probe,
+ .ops = &dsa_sandbox_ops,
+ .priv_auto = sizeof(struct dsa_sandbox_priv),
+};
diff --git a/drivers/net/dwmac_meson8b.c b/drivers/net/dwmac_meson8b.c
new file mode 100644
index 00000000000..c0b6ef49942
--- /dev/null
+++ b/drivers/net/dwmac_meson8b.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 BayLibre, SAS
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <phy.h>
+#include "designware.h"
+#include <dm/device_compat.h>
+#include <linux/err.h>
+
+#define ETH_REG_0 0x0
+#define ETH_REG_1 0x4
+#define ETH_REG_2 0x18
+#define ETH_REG_3 0x1c
+
+#define GX_ETH_REG_0_PHY_INTF BIT(0)
+#define GX_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5)
+#define GX_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7)
+#define GX_ETH_REG_0_PHY_CLK_EN BIT(10)
+#define GX_ETH_REG_0_INVERT_RMII_CLK BIT(11)
+#define GX_ETH_REG_0_CLK_EN BIT(12)
+
+#define AXG_ETH_REG_0_PHY_INTF_RGMII BIT(0)
+#define AXG_ETH_REG_0_PHY_INTF_RMII BIT(2)
+#define AXG_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5)
+#define AXG_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7)
+#define AXG_ETH_REG_0_PHY_CLK_EN BIT(10)
+#define AXG_ETH_REG_0_INVERT_RMII_CLK BIT(11)
+#define AXG_ETH_REG_0_CLK_EN BIT(12)
+
+struct dwmac_meson8b_plat {
+ struct dw_eth_pdata dw_eth_pdata;
+ int (*dwmac_setup)(struct udevice *dev, struct eth_pdata *edata);
+ void *regs;
+};
+
+static int dwmac_meson8b_of_to_plat(struct udevice *dev)
+{
+ struct dwmac_meson8b_plat *pdata = dev_get_plat(dev);
+
+ pdata->regs = (void *)dev_read_addr_index(dev, 1);
+ if ((fdt_addr_t)pdata->regs == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ pdata->dwmac_setup = (void *)dev_get_driver_data(dev);
+ if (!pdata->dwmac_setup)
+ return -EINVAL;
+
+ return designware_eth_of_to_plat(dev);
+}
+
+static int dwmac_setup_axg(struct udevice *dev, struct eth_pdata *edata)
+{
+ struct dwmac_meson8b_plat *plat = dev_get_plat(dev);
+
+ switch (edata->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ /* Set RGMII mode */
+ setbits_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RGMII |
+ AXG_ETH_REG_0_TX_PHASE(1) |
+ AXG_ETH_REG_0_TX_RATIO(4) |
+ AXG_ETH_REG_0_PHY_CLK_EN |
+ AXG_ETH_REG_0_CLK_EN);
+ break;
+
+ case PHY_INTERFACE_MODE_RMII:
+ /* Set RMII mode */
+ out_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RMII |
+ AXG_ETH_REG_0_INVERT_RMII_CLK |
+ AXG_ETH_REG_0_CLK_EN);
+ break;
+ default:
+ dev_err(dev, "Unsupported PHY mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dwmac_setup_gx(struct udevice *dev, struct eth_pdata *edata)
+{
+ struct dwmac_meson8b_plat *plat = dev_get_plat(dev);
+
+ switch (edata->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ /* Set RGMII mode */
+ setbits_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_PHY_INTF |
+ GX_ETH_REG_0_TX_PHASE(1) |
+ GX_ETH_REG_0_TX_RATIO(4) |
+ GX_ETH_REG_0_PHY_CLK_EN |
+ GX_ETH_REG_0_CLK_EN);
+
+ break;
+
+ case PHY_INTERFACE_MODE_RMII:
+ /* Set RMII mode */
+ out_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_INVERT_RMII_CLK |
+ GX_ETH_REG_0_CLK_EN);
+
+ if (!IS_ENABLED(CONFIG_MESON_GXBB))
+ writel(0x10110181, plat->regs + ETH_REG_2);
+
+ break;
+ default:
+ dev_err(dev, "Unsupported PHY mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dwmac_meson8b_probe(struct udevice *dev)
+{
+ struct dwmac_meson8b_plat *pdata = dev_get_plat(dev);
+ struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata;
+ int ret;
+
+ ret = pdata->dwmac_setup(dev, edata);
+ if (ret)
+ return ret;
+
+ return designware_eth_probe(dev);
+}
+
+static const struct udevice_id dwmac_meson8b_ids[] = {
+ { .compatible = "amlogic,meson-gxbb-dwmac", .data = (ulong)dwmac_setup_gx },
+ { .compatible = "amlogic,meson-axg-dwmac", .data = (ulong)dwmac_setup_axg },
+ { }
+};
+
+U_BOOT_DRIVER(dwmac_meson8b) = {
+ .name = "dwmac_meson8b",
+ .id = UCLASS_ETH,
+ .of_match = dwmac_meson8b_ids,
+ .of_to_plat = dwmac_meson8b_of_to_plat,
+ .probe = dwmac_meson8b_probe,
+ .ops = &designware_eth_ops,
+ .priv_auto = sizeof(struct dw_eth_dev),
+ .plat_auto = sizeof(struct dwmac_meson8b_plat),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
index e10db710e6e..b4ede61113f 100644
--- a/drivers/net/fm/Makefile
+++ b/drivers/net/fm/Makefile
@@ -20,14 +20,12 @@ obj-$(CONFIG_ARCH_P1023) += p1023.o
obj-$(CONFIG_ARCH_P2041) += p5020.o
obj-$(CONFIG_ARCH_P3041) += p5020.o
obj-$(CONFIG_ARCH_P4080) += p4080.o
-obj-$(CONFIG_ARCH_P5020) += p5020.o
obj-$(CONFIG_ARCH_P5040) += p5040.o
obj-$(CONFIG_ARCH_T1040) += t1040.o
obj-$(CONFIG_ARCH_T1042) += t1040.o
obj-$(CONFIG_ARCH_T1023) += t1024.o
obj-$(CONFIG_ARCH_T1024) += t1024.o
obj-$(CONFIG_ARCH_T2080) += t2080.o
-obj-$(CONFIG_ARCH_T2081) += t2080.o
obj-$(CONFIG_ARCH_T4240) += t4240.o
obj-$(CONFIG_ARCH_T4160) += t4240.o
obj-$(CONFIG_ARCH_B4420) += b4860.o
diff --git a/drivers/net/mdio_mux_meson_g12a.c b/drivers/net/mdio_mux_meson_g12a.c
new file mode 100644
index 00000000000..b520bf98f06
--- /dev/null
+++ b/drivers/net/mdio_mux_meson_g12a.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+
+#define ETH_PLL_STS 0x40
+#define ETH_PLL_CTL0 0x44
+#define PLL_CTL0_LOCK_DIG BIT(30)
+#define PLL_CTL0_RST BIT(29)
+#define PLL_CTL0_EN BIT(28)
+#define PLL_CTL0_SEL BIT(23)
+#define PLL_CTL0_N GENMASK(14, 10)
+#define PLL_CTL0_M GENMASK(8, 0)
+#define PLL_LOCK_TIMEOUT 1000000
+#define PLL_MUX_NUM_PARENT 2
+#define ETH_PLL_CTL1 0x48
+#define ETH_PLL_CTL2 0x4c
+#define ETH_PLL_CTL3 0x50
+#define ETH_PLL_CTL4 0x54
+#define ETH_PLL_CTL5 0x58
+#define ETH_PLL_CTL6 0x5c
+#define ETH_PLL_CTL7 0x60
+
+#define ETH_PHY_CNTL0 0x80
+#define EPHY_G12A_ID 0x33010180
+#define ETH_PHY_CNTL1 0x84
+#define PHY_CNTL1_ST_MODE GENMASK(2, 0)
+#define PHY_CNTL1_ST_PHYADD GENMASK(7, 3)
+#define EPHY_DFLT_ADD 8
+#define PHY_CNTL1_MII_MODE GENMASK(15, 14)
+#define EPHY_MODE_RMII 0x1
+#define PHY_CNTL1_CLK_EN BIT(16)
+#define PHY_CNTL1_CLKFREQ BIT(17)
+#define PHY_CNTL1_PHY_ENB BIT(18)
+#define ETH_PHY_CNTL2 0x88
+#define PHY_CNTL2_USE_INTERNAL BIT(5)
+#define PHY_CNTL2_SMI_SRC_MAC BIT(6)
+#define PHY_CNTL2_RX_CLK_EPHY BIT(9)
+
+#define MESON_G12A_MDIO_EXTERNAL_ID 0
+#define MESON_G12A_MDIO_INTERNAL_ID 1
+
+struct mdio_mux_meson_g12a_priv {
+ struct udevice *chip;
+ phys_addr_t phys;
+};
+
+static int meson_g12a_ephy_pll_init(struct mdio_mux_meson_g12a_priv *priv)
+{
+ /* Fire up the PHY PLL */
+ writel(0x29c0040a, priv->phys + ETH_PLL_CTL0);
+ writel(0x927e0000, priv->phys + ETH_PLL_CTL1);
+ writel(0xac5f49e5, priv->phys + ETH_PLL_CTL2);
+ writel(0x00000000, priv->phys + ETH_PLL_CTL3);
+ writel(0x00000000, priv->phys + ETH_PLL_CTL4);
+ writel(0x20200000, priv->phys + ETH_PLL_CTL5);
+ writel(0x0000c002, priv->phys + ETH_PLL_CTL6);
+ writel(0x00000023, priv->phys + ETH_PLL_CTL7);
+ writel(0x39c0040a, priv->phys + ETH_PLL_CTL0);
+ writel(0x19c0040a, priv->phys + ETH_PLL_CTL0);
+
+ return 0;
+}
+
+static int meson_g12a_enable_internal_mdio(struct mdio_mux_meson_g12a_priv *priv)
+{
+ /* Initialize ephy control */
+ writel(EPHY_G12A_ID, priv->phys + ETH_PHY_CNTL0);
+ writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
+ FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
+ FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
+ PHY_CNTL1_CLK_EN |
+ PHY_CNTL1_CLKFREQ |
+ PHY_CNTL1_PHY_ENB,
+ priv->phys + ETH_PHY_CNTL1);
+ writel(PHY_CNTL2_USE_INTERNAL |
+ PHY_CNTL2_SMI_SRC_MAC |
+ PHY_CNTL2_RX_CLK_EPHY,
+ priv->phys + ETH_PHY_CNTL2);
+
+ return 0;
+}
+
+static int meson_g12a_enable_external_mdio(struct mdio_mux_meson_g12a_priv *priv)
+{
+ /* Reset the mdio bus mux */
+ writel(0x0, priv->phys + ETH_PHY_CNTL2);
+
+ return 0;
+}
+
+static int mdio_mux_meson_g12a_select(struct udevice *mux, int cur, int sel)
+{
+ struct mdio_mux_meson_g12a_priv *priv = dev_get_priv(mux);
+
+ debug("%s: %x -> %x\n", __func__, (u32)cur, (u32)sel);
+
+ /* if last selection didn't change we're good to go */
+ if (cur == sel)
+ return 0;
+
+ switch (sel) {
+ case MESON_G12A_MDIO_EXTERNAL_ID:
+ return meson_g12a_enable_external_mdio(priv);
+ case MESON_G12A_MDIO_INTERNAL_ID:
+ return meson_g12a_enable_internal_mdio(priv);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct mdio_mux_ops mdio_mux_meson_g12a_ops = {
+ .select = mdio_mux_meson_g12a_select,
+};
+
+static int mdio_mux_meson_g12a_probe(struct udevice *dev)
+{
+ struct mdio_mux_meson_g12a_priv *priv = dev_get_priv(dev);
+
+ priv->phys = dev_read_addr(dev);
+
+ meson_g12a_ephy_pll_init(priv);
+
+ return 0;
+}
+
+static const struct udevice_id mdio_mux_meson_g12a_ids[] = {
+ { .compatible = "amlogic,g12a-mdio-mux" },
+ { }
+};
+
+U_BOOT_DRIVER(mdio_mux_meson_g12a) = {
+ .name = "mdio_mux_meson_g12a",
+ .id = UCLASS_MDIO_MUX,
+ .of_match = mdio_mux_meson_g12a_ids,
+ .probe = mdio_mux_meson_g12a_probe,
+ .ops = &mdio_mux_meson_g12a_ops,
+ .priv_auto = sizeof(struct mdio_mux_meson_g12a_priv),
+};
diff --git a/drivers/net/mdio_mux_mmioreg.c b/drivers/net/mdio_mux_mmioreg.c
new file mode 100644
index 00000000000..e1a23e40a26
--- /dev/null
+++ b/drivers/net/mdio_mux_mmioreg.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on linux/drivers/net/phy/mdio-mux-mmioreg.c :
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <miiphy.h>
+#include <linux/io.h>
+
+struct mdio_mux_mmioreg_priv {
+ struct udevice *chip;
+ phys_addr_t phys;
+ unsigned int iosize;
+ unsigned int mask;
+};
+
+static int mdio_mux_mmioreg_select(struct udevice *mux, int cur, int sel)
+{
+ struct mdio_mux_mmioreg_priv *priv = dev_get_priv(mux);
+
+ debug("%s: %x -> %x\n", __func__, (u32)cur, (u32)sel);
+
+ /* if last selection didn't change we're good to go */
+ if (cur == sel)
+ return 0;
+
+ switch (priv->iosize) {
+ case sizeof(u8): {
+ u8 x, y;
+
+ x = ioread8((void *)priv->phys);
+ y = (x & ~priv->mask) | (u32)sel;
+ if (x != y) {
+ iowrite8((x & ~priv->mask) | sel, (void *)priv->phys);
+ debug("%s: %02x -> %02x\n", __func__, x, y);
+ }
+
+ break;
+ }
+ case sizeof(u16): {
+ u16 x, y;
+
+ x = ioread16((void *)priv->phys);
+ y = (x & ~priv->mask) | (u32)sel;
+ if (x != y) {
+ iowrite16((x & ~priv->mask) | sel, (void *)priv->phys);
+ debug("%s: %04x -> %04x\n", __func__, x, y);
+ }
+
+ break;
+ }
+ case sizeof(u32): {
+ u32 x, y;
+
+ x = ioread32((void *)priv->phys);
+ y = (x & ~priv->mask) | (u32)sel;
+ if (x != y) {
+ iowrite32((x & ~priv->mask) | sel, (void *)priv->phys);
+ debug("%s: %08x -> %08x\n", __func__, x, y);
+ }
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct mdio_mux_ops mdio_mux_mmioreg_ops = {
+ .select = mdio_mux_mmioreg_select,
+};
+
+static int mdio_mux_mmioreg_probe(struct udevice *dev)
+{
+ struct mdio_mux_mmioreg_priv *priv = dev_get_priv(dev);
+ phys_addr_t reg_base, reg_size;
+ u32 reg_mask;
+ int err;
+
+ reg_base = ofnode_get_addr_size_index(dev_ofnode(dev), 0, &reg_size);
+ if (reg_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ if (reg_size != sizeof(u8) &&
+ reg_size != sizeof(u16) &&
+ reg_size != sizeof(u32)) {
+ printf("%s: only 8/16/32-bit registers are supported\n", __func__);
+ return -EINVAL;
+ }
+
+ err = dev_read_u32(dev, "mux-mask", &reg_mask);
+ if (err) {
+ debug("%s: error reading mux-mask property\n", __func__);
+ return err;
+ }
+
+ if (reg_mask >= BIT(reg_size * 8)) {
+ printf("%s: mask doesn't fix in register width\n", __func__);
+ return -EINVAL;
+ }
+
+ priv->phys = reg_base;
+ priv->iosize = reg_size;
+ priv->mask = reg_mask;
+
+ debug("%s: %llx@%lld / %x\n", __func__, reg_base, reg_size, reg_mask);
+
+ return 0;
+}
+
+static const struct udevice_id mdio_mux_mmioreg_ids[] = {
+ { .compatible = "mdio-mux-mmioreg" },
+ { }
+};
+
+U_BOOT_DRIVER(mdio_mux_mmioreg) = {
+ .name = "mdio_mux_mmioreg",
+ .id = UCLASS_MDIO_MUX,
+ .of_match = mdio_mux_mmioreg_ids,
+ .probe = mdio_mux_mmioreg_probe,
+ .ops = &mdio_mux_mmioreg_ops,
+ .priv_auto = sizeof(struct mdio_mux_mmioreg_priv),
+};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d69503067d8..070ffa82cb9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -292,6 +292,7 @@ config PHY_XILINX
config PHY_XILINX_GMII2RGMII
bool "Xilinx GMII to RGMII Ethernet PHYs support"
+ depends on DM_ETH
help
This adds support for Xilinx GMII to RGMII IP core. This IP acts
as bridge between MAC connected over GMII and external phy that
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 1a38c29469a..1192915ee52 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -15,18 +15,42 @@
DECLARE_GLOBAL_DATA_PTR;
-int fixedphy_probe(struct phy_device *phydev)
+static int fixedphy_probe(struct phy_device *phydev)
{
+ /* fixed-link phy must not be reset by core phy code */
+ phydev->flags |= PHY_FLAG_BROKEN_RESET;
+
+ return 0;
+}
+
+static int fixedphy_config(struct phy_device *phydev)
+{
+ ofnode node = phy_get_ofnode(phydev);
struct fixed_link *priv;
- int ofnode = phydev->addr;
+ bool old_binding = false;
+ u32 old_val[5];
u32 val;
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
/* check for mandatory properties within fixed-link node */
- val = fdt_getprop_u32_default_node(gd->fdt_blob,
- ofnode, 0, "speed", 0);
+ val = ofnode_read_u32_default(node, "speed", 0);
+
+ if (!val) {
+ /* try old binding */
+ old_binding = true;
+ if (ofnode_read_u32_array(node, "fixed-link", old_val,
+ ARRAY_SIZE(old_val))) {
+ printf("ERROR: no/invalid <fixed-link> property!\n");
+ return -ENOENT;
+ }
+ val = old_val[2];
+ }
+
if (val != SPEED_10 && val != SPEED_100 && val != SPEED_1000 &&
val != SPEED_2500 && val != SPEED_10000) {
- printf("ERROR: no/invalid speed given in fixed-link node!");
+ printf("ERROR: no/invalid speed given in fixed-link node!\n");
return -EINVAL;
}
@@ -38,17 +62,20 @@ int fixedphy_probe(struct phy_device *phydev)
phydev->priv = priv;
priv->link_speed = val;
- priv->duplex = fdtdec_get_bool(gd->fdt_blob, ofnode, "full-duplex");
- priv->pause = fdtdec_get_bool(gd->fdt_blob, ofnode, "pause");
- priv->asym_pause = fdtdec_get_bool(gd->fdt_blob, ofnode, "asym-pause");
-
- /* fixed-link phy must not be reset by core phy code */
- phydev->flags |= PHY_FLAG_BROKEN_RESET;
+ if (!old_binding) {
+ priv->duplex = ofnode_read_bool(node, "full-duplex");
+ priv->pause = ofnode_read_bool(node, "pause");
+ priv->asym_pause = ofnode_read_bool(node, "asym-pause");
+ } else {
+ priv->duplex = old_val[1];
+ priv->pause = old_val[3];
+ priv->asym_pause = old_val[4];
+ }
return 0;
}
-int fixedphy_startup(struct phy_device *phydev)
+static int fixedphy_startup(struct phy_device *phydev)
{
struct fixed_link *priv = phydev->priv;
@@ -61,7 +88,7 @@ int fixedphy_startup(struct phy_device *phydev)
return 0;
}
-int fixedphy_shutdown(struct phy_device *phydev)
+static int fixedphy_shutdown(struct phy_device *phydev)
{
return 0;
}
@@ -72,6 +99,7 @@ static struct phy_driver fixedphy_driver = {
.name = "Fixed PHY",
.features = PHY_GBIT_FEATURES | SUPPORTED_MII,
.probe = fixedphy_probe,
+ .config = fixedphy_config,
.startup = fixedphy_startup,
.shutdown = fixedphy_shutdown,
};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 89e3076bfd2..dcdef9e661d 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -18,6 +18,7 @@
#include <phy.h>
#include <errno.h>
#include <asm/global_data.h>
+#include <dm/of_extra.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -942,34 +943,25 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
}
#ifdef CONFIG_PHY_XILINX_GMII2RGMII
-#ifdef CONFIG_DM_ETH
static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
struct udevice *dev,
phy_interface_t interface)
-#else
-static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
- struct eth_device *dev,
- phy_interface_t interface)
-#endif
{
struct phy_device *phydev = NULL;
- int sn = dev_of_offset(dev);
- int off;
-
- while (sn > 0) {
- off = fdt_node_offset_by_compatible(gd->fdt_blob, sn,
- "xlnx,gmii-to-rgmii-1.0");
- if (off > 0) {
- phydev = phy_device_create(bus, off,
+ ofnode node = dev_ofnode(dev);
+
+ while (ofnode_valid(node)) {
+ node = ofnode_by_compatible(node, "xlnx,gmii-to-rgmii-1.0");
+ if (ofnode_valid(node)) {
+ phydev = phy_device_create(bus, 0,
PHY_GMII2RGMII_ID, false,
interface);
+ if (phydev)
+ phydev->node = node;
break;
}
- if (off == -FDT_ERR_NOTFOUND)
- sn = fdt_first_subnode(gd->fdt_blob, sn);
- else
- printf("%s: Error finding compat string:%d\n",
- __func__, off);
+
+ node = ofnode_first_subnode(node);
}
return phydev;
@@ -988,6 +980,7 @@ static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
struct phy_device *fixed_phy_create(ofnode node)
{
phy_interface_t interface = PHY_INTERFACE_MODE_NONE;
+ struct phy_device *phydev;
const char *if_str;
ofnode subnode;
@@ -1004,33 +997,25 @@ struct phy_device *fixed_phy_create(ofnode node)
return NULL;
}
- return phy_device_create(NULL, ofnode_to_offset(subnode), PHY_FIXED_ID,
- false, interface);
+ phydev = phy_device_create(NULL, 0, PHY_FIXED_ID, false, interface);
+ if (phydev)
+ phydev->node = subnode;
+
+ return phydev;
}
-#ifdef CONFIG_DM_ETH
static struct phy_device *phy_connect_fixed(struct mii_dev *bus,
struct udevice *dev,
phy_interface_t interface)
-#else
-static struct phy_device *phy_connect_fixed(struct mii_dev *bus,
- struct eth_device *dev,
- phy_interface_t interface)
-#endif
{
+ ofnode node = dev_ofnode(dev), subnode;
struct phy_device *phydev = NULL;
- int sn;
- const char *name;
-
- sn = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev));
- while (sn > 0) {
- name = fdt_get_name(gd->fdt_blob, sn, NULL);
- if (name && strcmp(name, "fixed-link") == 0) {
- phydev = phy_device_create(bus, sn, PHY_FIXED_ID, false,
- interface);
- break;
- }
- sn = fdt_next_subnode(gd->fdt_blob, sn);
+
+ if (ofnode_phy_is_fixed_link(node, &subnode)) {
+ phydev = phy_device_create(bus, 0, PHY_FIXED_ID,
+ false, interface);
+ if (phydev)
+ phydev->node = subnode;
}
return phydev;
diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c
index 74105c0b7d6..635c0570efe 100644
--- a/drivers/net/phy/xilinx_gmii2rgmii.c
+++ b/drivers/net/phy/xilinx_gmii2rgmii.c
@@ -18,9 +18,38 @@ DECLARE_GLOBAL_DATA_PTR;
static int xilinxgmiitorgmii_config(struct phy_device *phydev)
{
- struct phy_device *ext_phydev = phydev->priv;
+ ofnode node = phy_get_ofnode(phydev);
+ struct phy_device *ext_phydev;
+ struct ofnode_phandle_args phandle;
+ int ext_phyaddr = -1;
+ int ret;
debug("%s\n", __func__);
+
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
+ phydev->addr = ofnode_read_u32_default(node, "reg", -1);
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle",
+ NULL, 0, 0, &phandle);
+ if (ret)
+ return ret;
+
+ ext_phyaddr = ofnode_read_u32_default(phandle.node, "reg", -1);
+ ext_phydev = phy_find_by_mask(phydev->bus,
+ 1 << ext_phyaddr,
+ PHY_INTERFACE_MODE_RGMII);
+ if (!ext_phydev) {
+ printf("%s, No external phy device found\n", __func__);
+ return -EINVAL;
+ }
+
+ ext_phydev->node = phandle.node;
+ phydev->priv = ext_phydev;
+
+ debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr,
+ ext_phyaddr);
+
if (ext_phydev->drv->config)
ext_phydev->drv->config(ext_phydev);
@@ -83,11 +112,6 @@ static int xilinxgmiitorgmii_startup(struct phy_device *phydev)
static int xilinxgmiitorgmii_probe(struct phy_device *phydev)
{
- int ofnode = phydev->addr;
- u32 phy_of_handle;
- int ext_phyaddr = -1;
- struct phy_device *ext_phydev;
-
debug("%s\n", __func__);
if (phydev->interface != PHY_INTERFACE_MODE_GMII) {
@@ -95,31 +119,6 @@ static int xilinxgmiitorgmii_probe(struct phy_device *phydev)
return -EINVAL;
}
- /*
- * Read the phy address again as the one we read in ethernet driver
- * was overwritten for the purpose of storing the ofnode
- */
- phydev->addr = fdtdec_get_int(gd->fdt_blob, ofnode, "reg", -1);
- phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, ofnode,
- "phy-handle");
- if (phy_of_handle > 0)
- ext_phyaddr = fdtdec_get_int(gd->fdt_blob,
- phy_of_handle,
- "reg", -1);
- ext_phydev = phy_find_by_mask(phydev->bus,
- 1 << ext_phyaddr,
- PHY_INTERFACE_MODE_RGMII);
- if (!ext_phydev) {
- printf("%s, No external phy device found\n", __func__);
- return -EINVAL;
- }
-
- ext_phydev->node = offset_to_ofnode(phy_of_handle);
- phydev->priv = ext_phydev;
-
- debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr,
- ext_phyaddr);
-
phydev->flags |= PHY_FLAG_BROKEN_RESET;
return 0;
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index ec486893725..c68e4b7fb5e 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -707,11 +707,7 @@ static int init_phy(struct tsec_private *priv)
tsec_configure_serdes(priv);
#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_MDIO)
- if (ofnode_valid(ofnode_find_subnode(dev_ofnode(priv->dev),
- "fixed-link")))
- phydev = phy_connect(NULL, 0, priv->dev, priv->interface);
- else
- phydev = dm_eth_phy_connect(priv->dev);
+ phydev = dm_eth_phy_connect(priv->dev);
#else
phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
priv->interface);
@@ -830,14 +826,40 @@ int tsec_probe(struct udevice *dev)
u32 tbiaddr = CONFIG_SYS_TBIPA_VALUE;
struct tsec_data *data;
const char *phy_mode;
+ ofnode parent, child;
fdt_addr_t reg;
- ofnode parent;
int ret;
data = (struct tsec_data *)dev_get_driver_data(dev);
pdata->iobase = (phys_addr_t)dev_read_addr(dev);
- priv->regs = dev_remap_addr(dev);
+ if (pdata->iobase == FDT_ADDR_T_NONE) {
+ ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+ if (strncmp(ofnode_get_name(child), "queue-group",
+ strlen("queue-group")))
+ continue;
+
+ reg = ofnode_get_addr(child);
+ if (reg == FDT_ADDR_T_NONE) {
+ printf("No 'reg' property of <queue-group>\n");
+ return -ENOENT;
+ }
+ pdata->iobase = reg;
+
+ /*
+ * if there are multiple queue groups,
+ * only the first one is used.
+ */
+ break;
+ }
+
+ if (!ofnode_valid(child)) {
+ printf("No child node for <queue-group>?\n");
+ return -ENOENT;
+ }
+ }
+
+ priv->regs = map_physmem(pdata->iobase, 0, MAP_NOCACHE);
ret = dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
&phandle_args);
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index baf06a2ad89..ff599822673 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -454,14 +454,6 @@ static int zynq_gem_init(struct udevice *dev)
priv->int_pcs) {
nwconfig |= ZYNQ_GEM_NWCFG_SGMII_ENBL |
ZYNQ_GEM_NWCFG_PCS_SEL;
-#ifdef CONFIG_ARM64
- if (priv->phydev->phy_id != PHY_FIXED_ID)
- writel(readl(&regs->pcscntrl) | ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
- &regs->pcscntrl);
- else
- writel(readl(&regs->pcscntrl) & ~ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
- &regs->pcscntrl);
-#endif
}
switch (priv->phydev->speed) {
@@ -480,6 +472,23 @@ static int zynq_gem_init(struct udevice *dev)
break;
}
+#ifdef CONFIG_ARM64
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII &&
+ priv->int_pcs) {
+ /*
+ * Disable AN for fixed link configuration, enable otherwise.
+ * Must be written after PCS_SEL is set in nwconfig,
+ * otherwise writes will not take effect.
+ */
+ if (priv->phydev->phy_id != PHY_FIXED_ID)
+ writel(readl(&regs->pcscntrl) | ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
+ &regs->pcscntrl);
+ else
+ writel(readl(&regs->pcscntrl) & ~ZYNQ_GEM_PCS_CTL_ANEG_ENBL,
+ &regs->pcscntrl);
+ }
+#endif
+
ret = clk_set_rate(&priv->tx_clk, clk_rate);
if (IS_ERR_VALUE(ret)) {
dev_err(dev, "failed to set tx clock rate\n");
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index ba41787f64d..cdcdd8f456b 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -258,9 +258,13 @@ config PCI_MVEBU
Say Y here if you want to enable PCIe controller support on
Armada XP/38x SoCs.
+config PCIE_DW_COMMON
+ bool
+ select DM_PCI
+
config PCI_KEYSTONE
bool "TI Keystone PCIe controller"
- depends on DM_PCI
+ select PCIE_DW_COMMON
help
Say Y here if you want to enable PCI controller support on AM654 SoC.
@@ -272,6 +276,14 @@ config PCIE_MEDIATEK
Say Y here if you want to enable Gen2 PCIe controller,
which could be found on MT7623 SoC family.
+config PCIE_DW_MESON
+ bool "Amlogic Meson DesignWare based PCIe controller"
+ depends on ARCH_MESON
+ select PCIE_DW_COMMON
+ help
+ Say Y here if you want to enable DW PCIe controller support on
+ Amlogic SoCs.
+
config PCIE_ROCKCHIP
bool "Enable Rockchip PCIe driver"
depends on ARCH_ROCKCHIP
@@ -285,7 +297,7 @@ config PCIE_ROCKCHIP
config PCIE_DW_ROCKCHIP
bool "Rockchip DesignWare based PCIe controller"
depends on ARCH_ROCKCHIP
- select DM_PCI
+ select PCIE_DW_COMMON
select PHY_ROCKCHIP_SNPS_PCIE3
help
Say Y here if you want to enable DW PCIe controller support on
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 5ed94bc95c2..96d61821fe3 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -45,9 +45,11 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
+obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
+obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o
obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index da76148c583..05663c72b4b 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -88,8 +88,9 @@ static void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
else
bar_res = mem;
- debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ",
+ debug("PCI Autoconfig: BAR %d, %s%s, size=0x%llx, ",
bar_nr, bar_res == prefetch ? "Prf" : "Mem",
+ found_mem64 ? "64" : "",
(unsigned long long)bar_size);
}
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index a14a4db3c2f..7bad4c82c0c 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -349,13 +349,10 @@ int vbe_setup_video_priv(struct vesa_mode_info *vesa,
}
/* Use double buffering if enabled */
- if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
- if (!plat->base)
- return log_msg_ret("copy", -ENFILE);
+ if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->base)
plat->copy_base = vesa->phys_base_ptr;
- } else {
+ else
plat->base = vesa->phys_base_ptr;
- }
log_debug("base = %lx, copy_base = %lx\n", plat->base, plat->copy_base);
plat->size = vesa->bytes_per_scanline * vesa->y_resolution;
diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c
new file mode 100644
index 00000000000..785fd3aad00
--- /dev/null
+++ b/drivers/pci/pcie_dw_common.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <dm/device_compat.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "pcie_dw_common.h"
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci)
+{
+ return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+ PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
+}
+
+int pcie_dw_get_link_width(struct pcie_dw *pci)
+{
+ return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+ PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
+}
+
+static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg,
+ u32 val)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+ void __iomem *base = pci->atu_base;
+
+ writel(val, base + offset + reg);
+}
+
+static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+ void __iomem *base = pci->atu_base;
+
+ return readl(base + offset + reg);
+}
+
+/**
+ * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ *
+ * Return: 0 is successful and -1 is failure
+ */
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index,
+ int type, u64 cpu_addr,
+ u64 pci_addr, u32 size)
+{
+ u32 retries, val;
+
+ dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
+ index, type, cpu_addr, pci_addr, size);
+
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
+ lower_32_bits(cpu_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
+ upper_32_bits(cpu_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
+ lower_32_bits(cpu_addr + size - 1));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+ lower_32_bits(pci_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+ upper_32_bits(pci_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
+ type);
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+ PCIE_ATU_ENABLE);
+
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = dw_pcie_readl_ob_unroll(pci, index,
+ PCIE_ATU_UNR_REGION_CTRL2);
+ if (val & PCIE_ATU_ENABLE)
+ return 0;
+
+ udelay(LINK_WAIT_IATU);
+ }
+ dev_err(pci->dev, "outbound iATU is not being enabled\n");
+
+ return -1;
+}
+
+/**
+ * set_cfg_address() - Configure the PCIe controller config space access
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @d: PCI device to access
+ * @where: Offset in the configuration space
+ *
+ * Configures the PCIe controller to access the configuration space of
+ * a specific PCIe device and returns the address to use for this
+ * access.
+ *
+ * Return: Address that can be used to access the configation space
+ * of the requested device / offset
+ */
+static uintptr_t set_cfg_address(struct pcie_dw *pcie,
+ pci_dev_t d, uint where)
+{
+ int bus = PCI_BUS(d) - pcie->first_busno;
+ uintptr_t va_address;
+ u32 atu_type;
+ int ret;
+
+ /* Use dbi_base for own configuration read and write */
+ if (!bus) {
+ va_address = (uintptr_t)pcie->dbi_base;
+ goto out;
+ }
+
+ if (bus == 1)
+ /*
+ * For local bus whose primary bus number is root bridge,
+ * change TLP Type field to 4.
+ */
+ atu_type = PCIE_ATU_TYPE_CFG0;
+ else
+ /* Otherwise, change TLP Type field to 5. */
+ atu_type = PCIE_ATU_TYPE_CFG1;
+
+ /*
+ * Not accessing root port configuration space?
+ * Region #0 is used for Outbound CFG space access.
+ * Direction = Outbound
+ * Region Index = 0
+ */
+ d = PCI_MASK_BUS(d);
+ d = PCI_ADD_BUS(bus, d);
+ ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+ atu_type, (u64)pcie->cfg_base,
+ d << 8, pcie->cfg_size);
+ if (ret)
+ return (uintptr_t)ret;
+
+ va_address = (uintptr_t)pcie->cfg_base;
+
+out:
+ va_address += where & ~0x3;
+
+ return va_address;
+}
+
+/**
+ * pcie_dw_addr_valid() - Check for valid bus address
+ *
+ * @d: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return 1 (true) if the PCI device can be accessed by this controller.
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
+{
+ if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
+ return 0;
+ if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * pcie_dw_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct pcie_dw *pcie = dev_get_priv(bus);
+ uintptr_t va_address;
+ ulong value;
+
+ dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+ debug("- out of range\n");
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, offset);
+
+ value = readl(va_address);
+
+ debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+ *valuep = pci_conv_32_to_size(value, offset, size);
+
+ return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct pcie_dw *pcie = dev_get_priv(bus);
+ uintptr_t va_address;
+ ulong old;
+
+ dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+ if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+ debug("- out of range\n");
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, offset);
+
+ old = readl(va_address);
+ value = pci_conv_size_to_32(old, value, offset, size);
+ writel(value, va_address);
+
+ return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
+ *
+ * @pcie: Pointer to the PCI controller state
+ *
+ * Configure the host BARs of the PCIe controller root port so that
+ * PCI(e) devices may access the system memory.
+ */
+void pcie_dw_setup_host(struct pcie_dw *pci)
+{
+ struct udevice *ctlr = pci_get_controller(pci->dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ u32 ret;
+
+ if (!pci->atu_base)
+ pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+
+ /* setup RC BARs */
+ writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
+ pci->dbi_base + PCI_BASE_ADDRESS_0);
+ writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
+
+ /* setup interrupt pins */
+ clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE,
+ 0xff00, 0x100);
+
+ /* setup bus numbers */
+ clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+ 0xffffff, 0x00ff0100);
+
+ /* setup command register */
+ clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+ 0xffff,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+
+ /* Enable write permission for the DBI read-only register */
+ dw_pcie_dbi_write_enable(pci, true);
+ /* program correct class for RC */
+ writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
+ /* Better disable write permission right after the update */
+ dw_pcie_dbi_write_enable(pci, false);
+
+ setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
+ PORT_LOGIC_SPEED_CHANGE);
+
+ for (ret = 0; ret < hose->region_count; ret++) {
+ if (hose->regions[ret].flags == PCI_REGION_IO) {
+ pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */
+ pci->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */
+ pci->io.size = hose->regions[ret].size; /* IO size */
+ } else if (hose->regions[ret].flags == PCI_REGION_MEM) {
+ pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
+ pci->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */
+ pci->mem.size = hose->regions[ret].size; /* MEM size */
+ } else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
+ pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */
+ pci->prefetch.bus_start = hose->regions[ret].bus_start; /* PREFETCH_bus_addr */
+ pci->prefetch.size = hose->regions[ret].size; /* PREFETCH size */
+ } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
+ pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size);
+ pci->cfg_size = pci->io.size;
+ } else {
+ dev_err(pci->dev, "invalid flags type!\n");
+ }
+ }
+
+ dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
+ pci->cfg_base, pci->cfg_base + pci->cfg_size,
+ pci->cfg_size);
+
+ dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
+ pci->io.phys_start, pci->io.phys_start + pci->io.size,
+ pci->io.size);
+
+ dev_dbg(pci->dev, "IO bus: [0x%lx - 0x%lx, size 0x%lx]\n",
+ pci->io.bus_start, pci->io.bus_start + pci->io.size,
+ pci->io.size);
+
+ dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
+ pci->mem.phys_start, pci->mem.phys_start + pci->mem.size,
+ pci->mem.size);
+
+ dev_dbg(pci->dev, "MEM bus: [0x%lx - 0x%lx, size 0x%lx]\n",
+ pci->mem.bus_start, pci->mem.bus_start + pci->mem.size,
+ pci->mem.size);
+
+ if (pci->prefetch.size) {
+ dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n",
+ pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size,
+ pci->prefetch.size);
+
+ dev_dbg(pci->dev, "PREFETCH bus: [0x%lx - 0x%lx, size 0x%lx]\n",
+ pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size,
+ pci->prefetch.size);
+ }
+}
diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h
new file mode 100644
index 00000000000..6b701645af6
--- /dev/null
+++ b/drivers/pci/pcie_dw_common.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#ifndef PCIE_DW_COMMON_H
+#define PCIE_DW_COMMON_H
+
+#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG 0x80
+#define PCIE_LINK_STATUS_SPEED_OFF 16
+#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF 20
+#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll.
+ * The registers are offset from atu_base
+ */
+#define PCIE_ATU_UNR_REGION_CTRL1 0x00
+#define PCIE_ATU_UNR_REGION_CTRL2 0x04
+#define PCIE_ATU_UNR_LOWER_BASE 0x08
+#define PCIE_ATU_UNR_UPPER_BASE 0x0c
+#define PCIE_ATU_UNR_LIMIT 0x10
+#define PCIE_ATU_UNR_LOWER_TARGET 0x14
+#define PCIE_ATU_UNR_UPPER_TARGET 0x18
+
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+
+/* Register address builder */
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES 5
+#define LINK_WAIT_IATU_US 10000
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG 0x80
+#define PCIE_LINK_STATUS_SPEED_OFF 16
+#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF 20
+#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+#define PCIE_LINK_CAPABILITY 0x7c
+#define PCIE_LINK_CTL_2 0xa0
+#define TARGET_LINK_SPEED_MASK 0xf
+#define LINK_SPEED_GEN_1 0x1
+#define LINK_SPEED_GEN_2 0x2
+#define LINK_SPEED_GEN_3 0x3
+
+/* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_LINK_CONTROL 0x710
+#define PORT_LINK_DLL_LINK_EN BIT(5)
+#define PORT_LINK_FAST_LINK_MODE BIT(7)
+#define PORT_LINK_MODE_MASK GENMASK(21, 16)
+#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)
+#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)
+#define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3)
+#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)
+#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
+#define PORT_LOGIC_N_FTS_MASK GENMASK(7, 0)
+#define PORT_LOGIC_SPEED_CHANGE BIT(17)
+#define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8)
+#define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8)
+
+#define PCIE_MISC_CONTROL_1_OFF 0x8bc
+#define PCIE_DBI_RO_WR_EN BIT(0)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES 5
+#define LINK_WAIT_IATU 10000
+
+/**
+ * struct pcie_dw - DW PCIe controller state
+ *
+ * @dbi_base: The base address of dbi register space
+ * @cfg_base: The base address of configuration space
+ * @atu_base: The base address of ATU space
+ * @cfg_size: The size of the configuration space which is needed
+ * as it gets written into the PCIE_ATU_LIMIT register
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup
+ * (PEX switches etc).
+ * @io: The IO space for EP's BAR
+ * @mem: The memory space for EP's BAR
+ * @prefetch: The prefetch space for EP's BAR
+ */
+struct pcie_dw {
+ struct udevice *dev;
+ void __iomem *dbi_base;
+ void __iomem *cfg_base;
+ void __iomem *atu_base;
+ fdt_size_t cfg_size;
+
+ int first_busno;
+
+ /* IO, MEM & PREFETCH PCI regions */
+ struct pci_region io;
+ struct pci_region mem;
+ struct pci_region prefetch;
+};
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci);
+
+int pcie_dw_get_link_width(struct pcie_dw *pci);
+
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr,
+ u64 pci_addr, u32 size);
+
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep,
+ enum pci_size_t size);
+
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value,
+ enum pci_size_t size);
+
+static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en)
+{
+ u32 val;
+
+ val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+ if (en)
+ val |= PCIE_DBI_RO_WR_EN;
+ else
+ val &= ~PCIE_DBI_RO_WR_EN;
+ writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+}
+
+void pcie_dw_setup_host(struct pcie_dw *pci);
+
+#endif
diff --git a/drivers/pci/pcie_dw_meson.c b/drivers/pci/pcie_dw_meson.c
new file mode 100644
index 00000000000..0525ecbea64
--- /dev/null
+++ b/drivers/pci/pcie_dw_meson.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic DesignWare based PCIe host controller driver
+ *
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on pcie_dw_rockchip.c
+ * Copyright (c) 2021 Rockchip, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/bitfield.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct meson_pcie - Amlogic Meson DW PCIe controller state
+ *
+ * @pci: The common PCIe DW structure
+ * @meson_cfg_base: The base address of vendor regs
+ * @phy
+ * @clk_port
+ * @clk_general
+ * @clk_pclk
+ * @rsts
+ * @rst_gpio: The #PERST signal for slot
+ */
+struct meson_pcie {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
+ void *meson_cfg_base;
+ struct phy phy;
+ struct clk clk_port;
+ struct clk clk_general;
+ struct clk clk_pclk;
+ struct reset_ctl_bulk rsts;
+ struct gpio_desc rst_gpio;
+};
+
+#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
+
+#define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5)
+#define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12)
+
+/* PCIe specific config registers */
+#define PCIE_CFG0 0x0
+#define APP_LTSSM_ENABLE BIT(7)
+
+#define PCIE_CFG_STATUS12 0x30
+#define IS_SMLH_LINK_UP(x) ((x) & (1 << 6))
+#define IS_RDLH_LINK_UP(x) ((x) & (1 << 16))
+#define IS_LTSSM_UP(x) ((((x) >> 10) & 0x1f) == 0x11)
+
+#define PCIE_CFG_STATUS17 0x44
+#define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1)
+
+#define WAIT_LINKUP_TIMEOUT 4000
+#define PORT_CLK_RATE 100000000UL
+#define MAX_PAYLOAD_SIZE 256
+#define MAX_READ_REQ_SIZE 256
+#define PCIE_RESET_DELAY 500
+#define PCIE_SHARED_RESET 1
+#define PCIE_NORMAL_RESET 0
+
+enum pcie_data_rate {
+ PCIE_GEN1,
+ PCIE_GEN2,
+ PCIE_GEN3,
+ PCIE_GEN4
+};
+
+/* Parameters for the waiting for #perst signal */
+#define PERST_WAIT_US 1000000
+
+static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg)
+{
+ return readl(priv->meson_cfg_base + reg);
+}
+
+static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg)
+{
+ writel(val, priv->meson_cfg_base + reg);
+}
+
+/**
+ * meson_pcie_configure() - Configure link
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ *
+ * Configure the link mode and width
+ */
+static void meson_pcie_configure(struct meson_pcie *priv)
+{
+ u32 val;
+
+ dw_pcie_dbi_write_enable(&priv->dw, true);
+
+ val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+ val &= ~PORT_LINK_FAST_LINK_MODE;
+ val |= PORT_LINK_DLL_LINK_EN;
+ val &= ~PORT_LINK_MODE_MASK;
+ val |= PORT_LINK_MODE_1_LANES;
+ writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+
+ val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+ val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+ writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+
+ dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv)
+{
+ u32 val;
+
+ val = meson_cfg_readl(priv, PCIE_CFG0);
+ val |= APP_LTSSM_ENABLE;
+ meson_cfg_writel(priv, val, PCIE_CFG0);
+}
+
+static int meson_pcie_wait_link_up(struct meson_pcie *priv)
+{
+ u32 speed_okay = 0;
+ u32 cnt = 0;
+ u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
+
+ do {
+ state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12);
+ state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17);
+ smlh_up = IS_SMLH_LINK_UP(state12);
+ rdlh_up = IS_RDLH_LINK_UP(state12);
+ ltssm_up = IS_LTSSM_UP(state12);
+
+ if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
+ speed_okay = 1;
+
+ if (smlh_up)
+ debug("%s: smlh_link_up is on\n", __func__);
+ if (rdlh_up)
+ debug("%s: rdlh_link_up is on\n", __func__);
+ if (ltssm_up)
+ debug("%s: ltssm_up is on\n", __func__);
+ if (speed_okay)
+ debug("%s: speed_okay\n", __func__);
+
+ if (smlh_up && rdlh_up && ltssm_up && speed_okay)
+ return 0;
+
+ cnt++;
+
+ udelay(10);
+ } while (cnt < WAIT_LINKUP_TIMEOUT);
+
+ printf("%s: error: wait linkup timeout\n", __func__);
+ return -EIO;
+}
+
+/**
+ * meson_pcie_link_up() - Wait for the link to come up
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ * @cap_speed: Desired link speed
+ *
+ * Return: 1 (true) for active line and negative (false) for no link (timeout)
+ */
+static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed)
+{
+ /* DW link configurations */
+ meson_pcie_configure(priv);
+
+ /* Reset the device */
+ if (dm_gpio_is_valid(&priv->rst_gpio)) {
+ dm_gpio_set_value(&priv->rst_gpio, 1);
+ /*
+ * Minimal is 100ms from spec but we see
+ * some wired devices need much more, such as 600ms.
+ * Add a enough delay to cover all cases.
+ */
+ udelay(PERST_WAIT_US);
+ dm_gpio_set_value(&priv->rst_gpio, 0);
+ }
+
+ /* Enable LTSSM */
+ meson_pcie_enable_ltssm(priv);
+
+ return meson_pcie_wait_link_up(priv);
+}
+
+static int meson_size_to_payload(int size)
+{
+ /*
+ * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
+ * So if input size is not 2^order alignment or less than 2^7 or bigger
+ * than 2^12, just set to default size 2^(1+7).
+ */
+ if (!is_power_of_2(size) || size < 128 || size > 4096) {
+ debug("%s: payload size %d, set to default 256\n", __func__, size);
+ return 1;
+ }
+
+ return fls(size) - 8;
+}
+
+static void meson_set_max_payload(struct meson_pcie *priv, int size)
+{
+ u32 val;
+ u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+ int max_payload_size = meson_size_to_payload(size);
+
+ dw_pcie_dbi_write_enable(&priv->dw, true);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+ writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
+ writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+ dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size)
+{
+ u32 val;
+ u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+ int max_rd_req_size = meson_size_to_payload(size);
+
+ dw_pcie_dbi_write_enable(&priv->dw, true);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+ writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
+ writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+ dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static int meson_pcie_init_port(struct udevice *dev)
+{
+ int ret;
+ struct meson_pcie *priv = dev_get_priv(dev);
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to init phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = generic_phy_reset(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to reset phy (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_assert_bulk(&priv->rsts);
+ if (ret) {
+ dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ udelay(PCIE_RESET_DELAY);
+
+ ret = reset_deassert_bulk(&priv->rsts);
+ if (ret) {
+ dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ udelay(PCIE_RESET_DELAY);
+
+ ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE);
+ if (ret) {
+ dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ ret = clk_enable(&priv->clk_general);
+ if (ret) {
+ dev_err(dev, "failed to enable clk general (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ ret = clk_enable(&priv->clk_pclk);
+ if (ret) {
+ dev_err(dev, "failed to enable pclk (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ meson_set_max_payload(priv, MAX_PAYLOAD_SIZE);
+ meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE);
+
+ pcie_dw_setup_host(&priv->dw);
+
+ ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2);
+ if (ret < 0)
+ goto err_link_up;
+
+ return 0;
+err_link_up:
+ clk_disable(&priv->clk_port);
+ clk_disable(&priv->clk_general);
+ clk_disable(&priv->clk_pclk);
+err_deassert_bulk:
+ reset_assert_bulk(&priv->rsts);
+err_power_off_phy:
+ generic_phy_power_off(&priv->phy);
+err_exit_phy:
+ generic_phy_exit(&priv->phy);
+
+ return ret;
+}
+
+static int meson_pcie_parse_dt(struct udevice *dev)
+{
+ struct meson_pcie *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+ if (!priv->dw.dbi_base)
+ return -ENODEV;
+
+ dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base);
+
+ priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1);
+ if (!priv->meson_cfg_base)
+ return -ENODEV;
+
+ dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base);
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->rst_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ dev_err(dev, "failed to find reset-gpios property\n");
+ return ret;
+ }
+
+ ret = reset_get_bulk(dev, &priv->rsts);
+ if (ret) {
+ dev_err(dev, "Can't get reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "port", &priv->clk_port);
+ if (ret) {
+ dev_err(dev, "Can't get port clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "general", &priv->clk_general);
+ if (ret) {
+ dev_err(dev, "Can't get port clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk);
+ if (ret) {
+ dev_err(dev, "Can't get port clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * meson_pcie_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int meson_pcie_probe(struct udevice *dev)
+{
+ struct meson_pcie *priv = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ int ret = 0;
+
+ priv->dw.first_busno = dev_seq(dev);
+ priv->dw.dev = dev;
+
+ ret = meson_pcie_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ ret = meson_pcie_init_port(dev);
+ if (ret) {
+ dm_gpio_free(dev, &priv->rst_gpio);
+ return ret;
+ }
+
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+ dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+ pcie_dw_get_link_width(&priv->dw),
+ hose->first_busno);
+
+ return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ priv->dw.mem.phys_start,
+ priv->dw.mem.bus_start,
+ priv->dw.mem.size);
+}
+
+static const struct dm_pci_ops meson_pcie_ops = {
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
+};
+
+static const struct udevice_id meson_pcie_ids[] = {
+ { .compatible = "amlogic,axg-pcie" },
+ { .compatible = "amlogic,g12a-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_dw_pcie) = {
+ .name = "pcie_dw_meson",
+ .id = UCLASS_PCI,
+ .of_match = meson_pcie_ids,
+ .ops = &meson_pcie_ops,
+ .probe = meson_pcie_probe,
+ .priv_auto = sizeof(struct meson_pcie),
+};
diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c
index 77f1a1b48f1..bc22af4230c 100644
--- a/drivers/pci/pcie_dw_rockchip.c
+++ b/drivers/pci/pcie_dw_rockchip.c
@@ -22,39 +22,26 @@
#include <linux/delay.h>
#include <power/regulator.h>
+#include "pcie_dw_common.h"
+
DECLARE_GLOBAL_DATA_PTR;
/**
* struct rk_pcie - RK DW PCIe controller state
*
* @vpcie3v3: The 3.3v power supply for slot
- * @dbi_base: The base address of dwc core regs
* @apb_base: The base address of vendor regs
- * @cfg_base: The base address of config header space
- * @cfg_size: The size of the configuration space which is needed
- * as it gets written into the PCIE_ATU_LIMIT register
- * @first_busno: This driver supports multiple PCIe controllers.
- * first_busno stores the bus number of the PCIe root-port
- * number which may vary depending on the PCIe setup
- * (PEX switches etc).
* @rst_gpio: The #PERST signal for slot
- * @io: The IO space for EP's BAR
- * @mem: The memory space for EP's BAR
*/
struct rk_pcie {
- struct udevice *dev;
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
struct udevice *vpcie3v3;
- void *dbi_base;
void *apb_base;
- void *cfg_base;
- fdt_size_t cfg_size;
struct phy phy;
struct clk_bulk clks;
- int first_busno;
struct reset_ctl_bulk rsts;
struct gpio_desc rst_gpio;
- struct pci_region io;
- struct pci_region mem;
};
/* Parameters for the waiting for iATU enabled routine */
@@ -73,59 +60,6 @@ struct rk_pcie {
#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
#define PCIE_CLIENT_DBF_EN 0xffff0003
-/* PCI DBICS registers */
-#define PCIE_LINK_STATUS_REG 0x80
-#define PCIE_LINK_STATUS_SPEED_OFF 16
-#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
-#define PCIE_LINK_STATUS_WIDTH_OFF 20
-#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
-
-#define PCIE_LINK_CAPABILITY 0x7c
-#define PCIE_LINK_CTL_2 0xa0
-#define TARGET_LINK_SPEED_MASK 0xf
-#define LINK_SPEED_GEN_1 0x1
-#define LINK_SPEED_GEN_2 0x2
-#define LINK_SPEED_GEN_3 0x3
-
-#define PCIE_MISC_CONTROL_1_OFF 0x8bc
-#define PCIE_DBI_RO_WR_EN BIT(0)
-
-#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c
-#define PORT_LOGIC_SPEED_CHANGE BIT(17)
-
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll.
- * The registers are offset from atu_base
- */
-#define PCIE_ATU_UNR_REGION_CTRL1 0x00
-#define PCIE_ATU_UNR_REGION_CTRL2 0x04
-#define PCIE_ATU_UNR_LOWER_BASE 0x08
-#define PCIE_ATU_UNR_UPPER_BASE 0x0c
-#define PCIE_ATU_UNR_LIMIT 0x10
-#define PCIE_ATU_UNR_LOWER_TARGET 0x14
-#define PCIE_ATU_UNR_UPPER_TARGET 0x18
-
-#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
-#define PCIE_ATU_TYPE_MEM (0x0 << 0)
-#define PCIE_ATU_TYPE_IO (0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
-#define PCIE_ATU_ENABLE (0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
-#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
-
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
- ((0x3 << 20) | ((region) << 9))
-
-/* Parameters for the waiting for iATU enabled routine */
-#define LINK_WAIT_MAX_IATU_RETRIES 5
-#define LINK_WAIT_IATU_US 10000
-
/* Parameters for the waiting for #perst signal */
#define PERST_WAIT_MS 1000
@@ -175,7 +109,7 @@ static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base,
ret = rk_pcie_read(base + reg, size, &val);
if (ret)
- dev_err(rk_pcie->dev, "Read APB address failed\n");
+ dev_err(rk_pcie->dw.dev, "Read APB address failed\n");
return val;
}
@@ -187,7 +121,7 @@ static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base,
ret = rk_pcie_write(base + reg, size, val);
if (ret)
- dev_err(rk_pcie->dev, "Write APB address failed\n");
+ dev_err(rk_pcie->dw.dev, "Write APB address failed\n");
}
/**
@@ -214,91 +148,6 @@ static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
__rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val);
}
-static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie)
-{
- return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
- PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
-}
-
-static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie)
-{
- return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
- PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
-}
-
-static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index,
- u32 reg, u32 val)
-{
- u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- void __iomem *base = rk_pcie->dbi_base;
-
- writel(val, base + offset + reg);
-}
-
-static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg)
-{
- u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- void __iomem *base = rk_pcie->dbi_base;
-
- return readl(base + offset + reg);
-}
-
-static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en)
-{
- u32 val;
-
- val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-
- if (en)
- val |= PCIE_DBI_RO_WR_EN;
- else
- val &= ~PCIE_DBI_RO_WR_EN;
- writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-}
-
-/**
- * rockchip_pcie_setup_host() - Setup the PCIe controller for RC opertaion
- *
- * @rk_pcie: Pointer to the PCI controller state
- *
- * Configure the host BARs of the PCIe controller root port so that
- * PCI(e) devices may access the system memory.
- */
-static void rk_pcie_setup_host(struct rk_pcie *rk_pcie)
-{
- u32 val;
-
- rk_pcie_dbi_write_enable(rk_pcie, true);
-
- /* setup RC BARs */
- writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
- rk_pcie->dbi_base + PCI_BASE_ADDRESS_0);
- writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1);
-
- /* setup interrupt pins */
- clrsetbits_le32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE,
- 0xff00, 0x100);
-
- /* setup bus numbers */
- clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
- 0xffffff, 0x00ff0100);
-
- /* setup command register */
- clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
- 0xffff,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
-
- /* program correct class for RC */
- writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE);
- /* Better disable write permission right after the update */
-
- setbits_le32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
- PORT_LOGIC_SPEED_CHANGE)
-
- rk_pcie_dbi_write_enable(rk_pcie, false);
-}
-
/**
* rk_pcie_configure() - Configure link capabilities and speed
*
@@ -311,242 +160,15 @@ static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
{
u32 val;
- rk_pcie_dbi_write_enable(pci, true);
+ dw_pcie_dbi_write_enable(&pci->dw, true);
- clrsetbits_le32(pci->dbi_base + PCIE_LINK_CAPABILITY,
+ clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CAPABILITY,
TARGET_LINK_SPEED_MASK, cap_speed);
- clrsetbits_le32(pci->dbi_base + PCIE_LINK_CTL_2,
+ clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CTL_2,
TARGET_LINK_SPEED_MASK, cap_speed);
- rk_pcie_dbi_write_enable(pci, false);
-}
-
-/**
- * rk_pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
- *
- * @rk_pcie: Pointer to the PCI controller state
- * @index: ATU region index
- * @type: ATU accsess type
- * @cpu_addr: the physical address for the translation entry
- * @pci_addr: the pcie bus address for the translation entry
- * @size: the size of the translation entry
- *
- * Return: 0 is successful and -1 is failure
- */
-static int rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index,
- int type, u64 cpu_addr,
- u64 pci_addr, u32 size)
-{
- u32 retries, val;
-
- dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
- index, type, cpu_addr, pci_addr, size);
-
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
- lower_32_bits(cpu_addr));
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
- upper_32_bits(cpu_addr));
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
- lower_32_bits(cpu_addr + size - 1));
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
- lower_32_bits(pci_addr));
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
- upper_32_bits(pci_addr));
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
- type);
- rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
- PCIE_ATU_ENABLE);
-
- /*
- * Make sure ATU enable takes effect before any subsequent config
- * and I/O accesses.
- */
- for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
- val = rk_pcie_readl_ob_unroll(pci, index,
- PCIE_ATU_UNR_REGION_CTRL2);
- if (val & PCIE_ATU_ENABLE)
- return 0;
-
- udelay(LINK_WAIT_IATU_US);
- }
- dev_err(pci->dev, "outbound iATU is not being enabled\n");
-
- return -1;
-}
-
-/**
- * rk_pcie_dw_addr_valid() - Check for valid bus address
- *
- * @d: The PCI device to access
- * @first_busno: Bus number of the PCIe controller root complex
- *
- * Return 1 (true) if the PCI device can be accessed by this controller.
- *
- * Return: 1 on valid, 0 on invalid
- */
-static int rk_pcie_addr_valid(pci_dev_t d, int first_busno)
-{
- if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
- return 0;
- if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
- return 0;
-
- return 1;
-}
-
-/**
- * set_cfg_address() - Configure the PCIe controller config space access
- *
- * @rk_pcie: Pointer to the PCI controller state
- * @d: PCI device to access
- * @where: Offset in the configuration space
- *
- * Configures the PCIe controller to access the configuration space of
- * a specific PCIe device and returns the address to use for this
- * access.
- *
- * Return: Address that can be used to access the configation space
- * of the requested device / offset
- */
-static uintptr_t set_cfg_address(struct rk_pcie *pcie,
- pci_dev_t d, uint where)
-{
- int rel_bus = PCI_BUS(d) - pcie->first_busno;
- uintptr_t va_address;
- u32 atu_type;
- int ret;
-
- /* Use dbi_base for own configuration read and write */
- if (!rel_bus) {
- va_address = (uintptr_t)pcie->dbi_base;
- goto out;
- }
-
- if (rel_bus == 1)
- /*
- * For local bus whose primary bus number is root bridge,
- * change TLP Type field to 4.
- */
- atu_type = PCIE_ATU_TYPE_CFG0;
- else
- /* Otherwise, change TLP Type field to 5. */
- atu_type = PCIE_ATU_TYPE_CFG1;
-
- /*
- * Not accessing root port configuration space?
- * Region #0 is used for Outbound CFG space access.
- * Direction = Outbound
- * Region Index = 0
- */
- d = PCI_MASK_BUS(d);
- d = PCI_ADD_BUS(rel_bus, d);
- ret = rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
- atu_type, (u64)pcie->cfg_base,
- d << 8, pcie->cfg_size);
- if (ret)
- return (uintptr_t)ret;
-
- va_address = (uintptr_t)pcie->cfg_base;
-
-out:
- va_address += where & ~0x3;
-
- return va_address;
-}
-
-/**
- * rockchip_pcie_rd_conf() - Read from configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @valuep: A pointer at which to store the read value
- * @size: Indicates the size of access to perform
- *
- * Read a value of size @size from offset @offset within the configuration
- * space of the device identified by the bus, device & function numbers in @bdf
- * on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int rockchip_pcie_rd_conf(const struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong *valuep,
- enum pci_size_t size)
-{
- struct rk_pcie *pcie = dev_get_priv(bus);
- uintptr_t va_address;
- ulong value;
-
- debug("PCIE CFG read: bdf=%2x:%2x:%2x\n",
- PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
- if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
- debug("- out of range\n");
- *valuep = pci_get_ff(size);
- return 0;
- }
-
- va_address = set_cfg_address(pcie, bdf, offset);
-
- value = readl(va_address);
-
- debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
- *valuep = pci_conv_32_to_size(value, offset, size);
-
- return rk_pcie_prog_outbound_atu_unroll(pcie,
- PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_TYPE_IO,
- pcie->io.phys_start,
- pcie->io.bus_start,
- pcie->io.size);
-}
-
-/**
- * rockchip_pcie_wr_conf() - Write to configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @value: The value to write
- * @size: Indicates the size of access to perform
- *
- * Write the value @value of size @size from offset @offset within the
- * configuration space of the device identified by the bus, device & function
- * numbers in @bdf on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong value,
- enum pci_size_t size)
-{
- struct rk_pcie *pcie = dev_get_priv(bus);
- uintptr_t va_address;
- ulong old;
-
- debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n",
- PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
- debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
- if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
- debug("- out of range\n");
- return 0;
- }
-
- va_address = set_cfg_address(pcie, bdf, offset);
-
- old = readl(va_address);
- value = pci_conv_size_to_32(old, value, offset, size);
- writel(value, va_address);
-
- return rk_pcie_prog_outbound_atu_unroll(pcie,
- PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_TYPE_IO,
- pcie->io.phys_start,
- pcie->io.bus_start,
- pcie->io.size);
-
+ dw_pcie_dbi_write_enable(&pci->dw, false);
}
static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
@@ -642,19 +264,19 @@ static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
for (retries = 0; retries < 5; retries++) {
if (is_link_up(priv)) {
- dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n",
+ dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n",
rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
rk_pcie_debug_dump(priv);
return 0;
}
- dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n",
+ dev_info(priv->dw.dev, "PCIe Linking... LTSSM is 0x%x\n",
rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
rk_pcie_debug_dump(priv);
msleep(1000);
}
- dev_err(priv->dev, "PCIe-%d Link Fail\n", dev_seq(priv->dev));
+ dev_err(priv->dw.dev, "PCIe-%d Link Fail\n", dev_seq(priv->dw.dev));
/* Link maybe in Gen switch recovery but we need to wait more 1s */
msleep(1000);
return -EIO;
@@ -670,7 +292,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
if (priv->vpcie3v3) {
ret = regulator_set_value(priv->vpcie3v3, 3300000);
if (ret) {
- dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n",
+ dev_err(priv->dw.dev, "failed to enable vpcie3v3 (ret=%d)\n",
ret);
return ret;
}
@@ -709,7 +331,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
/* Set RC mode */
rk_pcie_writel_apb(priv, 0x0, 0xf00040);
- rk_pcie_setup_host(priv);
+ pcie_dw_setup_host(&priv->dw);
ret = rk_pcie_link_up(priv, LINK_SPEED_GEN_3);
if (ret < 0)
@@ -733,11 +355,11 @@ static int rockchip_pcie_parse_dt(struct udevice *dev)
struct rk_pcie *priv = dev_get_priv(dev);
int ret;
- priv->dbi_base = (void *)dev_read_addr_index(dev, 0);
- if (!priv->dbi_base)
+ priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+ if (!priv->dw.dbi_base)
return -ENODEV;
- dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base);
+ dev_dbg(dev, "DBI address is 0x%p\n", priv->dw.dbi_base);
priv->apb_base = (void *)dev_read_addr_index(dev, 1);
if (!priv->apb_base)
@@ -795,10 +417,10 @@ static int rockchip_pcie_probe(struct udevice *dev)
struct rk_pcie *priv = dev_get_priv(dev);
struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
- int reti = 0;
+ int ret = 0;
- priv->first_busno = dev_seq(dev);
- priv->dev = dev;
+ priv->dw.first_busno = dev_seq(dev);
+ priv->dw.dev = dev;
ret = rockchip_pcie_parse_dt(dev);
if (ret)
@@ -809,58 +431,22 @@ static int rockchip_pcie_probe(struct udevice *dev)
return ret;
dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
- dev_seq(dev), rk_pcie_get_link_speed(priv),
- rk_pcie_get_link_width(priv),
+ dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+ pcie_dw_get_link_width(&priv->dw),
hose->first_busno);
- for (ret = 0; ret < hose->region_count; ret++) {
- if (hose->regions[ret].flags == PCI_REGION_IO) {
- priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */
- priv->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */
- priv->io.size = hose->regions[ret].size; /* IO size */
- } else if (hose->regions[ret].flags == PCI_REGION_MEM) {
- priv->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
- priv->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */
- priv->mem.size = hose->regions[ret].size; /* MEM size */
- } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
- priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size);
- priv->cfg_size = priv->io.size;
- } else {
- dev_err(dev, "invalid flags type!\n");
- }
- }
-
- dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
- priv->cfg_base, priv->cfg_base + priv->cfg_size,
- priv->cfg_size);
-
- dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
- priv->io.phys_start, priv->io.phys_start + priv->io.size,
- priv->io.size);
-
- dev_dbg(dev, "IO bus: [0x%lx - 0x%lx, size 0x%lx]\n",
- priv->io.bus_start, priv->io.bus_start + priv->io.size,
- priv->io.size);
-
- dev_dbg(dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
- priv->mem.phys_start, priv->mem.phys_start + priv->mem.size,
- priv->mem.size);
-
- dev_dbg(dev, "MEM bus: [0x%lx - 0x%lx, size 0x%lx]\n",
- priv->mem.bus_start, priv->mem.bus_start + priv->mem.size,
- priv->mem.size);
- return rk_pcie_prog_outbound_atu_unroll(priv,
+ return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM,
- priv->mem.phys_start,
- priv->mem.bus_start,
- priv->mem.size);
+ priv->dw.mem.phys_start,
+ priv->dw.mem.bus_start,
+ priv->dw.mem.size);
}
static const struct dm_pci_ops rockchip_pcie_ops = {
- .read_config = rockchip_pcie_rd_conf,
- .write_config = rockchip_pcie_wr_conf,
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
};
static const struct udevice_id rockchip_pcie_ids[] = {
diff --git a/drivers/pci/pcie_dw_ti.c b/drivers/pci/pcie_dw_ti.c
index 33a5c3cc208..4195a02de39 100644
--- a/drivers/pci/pcie_dw_ti.c
+++ b/drivers/pci/pcie_dw_ti.c
@@ -19,19 +19,13 @@
#include <linux/delay.h>
#include <linux/err.h>
+#include "pcie_dw_common.h"
+
DECLARE_GLOBAL_DATA_PTR;
#define PCIE_VENDORID_MASK GENMASK(15, 0)
#define PCIE_DEVICEID_SHIFT 16
-/* PCI DBICS registers */
-#define PCIE_CONFIG_BAR0 0x10
-#define PCIE_LINK_STATUS_REG 0x80
-#define PCIE_LINK_STATUS_SPEED_OFF 16
-#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
-#define PCIE_LINK_STATUS_WIDTH_OFF 20
-#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
-
#define PCIE_LINK_CAPABILITY 0x7c
#define PCIE_LINK_CTL_2 0xa0
#define TARGET_LINK_SPEED_MASK 0xf
@@ -47,46 +41,12 @@ DECLARE_GLOBAL_DATA_PTR;
#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
-#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c
-#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
-
#define PCIE_LINK_UP_TIMEOUT_MS 100
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll.
- * The registers are offset from atu_base
- */
-#define PCIE_ATU_UNR_REGION_CTRL1 0x00
-#define PCIE_ATU_UNR_REGION_CTRL2 0x04
-#define PCIE_ATU_UNR_LOWER_BASE 0x08
-#define PCIE_ATU_UNR_UPPER_BASE 0x0c
-#define PCIE_ATU_UNR_LIMIT 0x10
-#define PCIE_ATU_UNR_LOWER_TARGET 0x14
-#define PCIE_ATU_UNR_UPPER_TARGET 0x18
-
-#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
-#define PCIE_ATU_TYPE_MEM (0x0 << 0)
-#define PCIE_ATU_TYPE_IO (0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
-#define PCIE_ATU_ENABLE (0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
-#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
-
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9)
-
/* Offsets from App base */
#define PCIE_CMD_STATUS 0x04
#define LTSSM_EN_VAL BIT(0)
-/* Parameters for the waiting for iATU enabled routine */
-#define LINK_WAIT_MAX_IATU_RETRIES 5
-#define LINK_WAIT_IATU 10000
#define AM654_PCIE_DEV_TYPE_MASK 0x3
#define EP 0x0
@@ -96,29 +56,13 @@ DECLARE_GLOBAL_DATA_PTR;
/**
* struct pcie_dw_ti - TI DW PCIe controller state
*
+ * @pci: The common PCIe DW structure
* @app_base: The base address of application register space
- * @dbics_base: The base address of dbics register space
- * @cfg_base: The base address of configuration space
- * @atu_base: The base address of ATU space
- * @cfg_size: The size of the configuration space which is needed
- * as it gets written into the PCIE_ATU_LIMIT register
- * @first_busno: This driver supports multiple PCIe controllers.
- * first_busno stores the bus number of the PCIe root-port
- * number which may vary depending on the PCIe setup
- * (PEX switches etc).
*/
struct pcie_dw_ti {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
void *app_base;
- void *dbi_base;
- void *cfg_base;
- void *atu_base;
- fdt_size_t cfg_size;
- int first_busno;
- struct udevice *dev;
-
- /* IO and MEM PCI regions */
- struct pci_region io;
- struct pci_region mem;
};
enum dw_pcie_device_mode {
@@ -128,261 +72,6 @@ enum dw_pcie_device_mode {
DW_PCIE_RC_TYPE,
};
-static int pcie_dw_get_link_speed(struct pcie_dw_ti *pci)
-{
- return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
- PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
-}
-
-static int pcie_dw_get_link_width(struct pcie_dw_ti *pci)
-{
- return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
- PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
-}
-
-static void dw_pcie_writel_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg,
- u32 val)
-{
- u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- void __iomem *base = pci->atu_base;
-
- writel(val, base + offset + reg);
-}
-
-static u32 dw_pcie_readl_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg)
-{
- u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- void __iomem *base = pci->atu_base;
-
- return readl(base + offset + reg);
-}
-
-/**
- * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
- *
- * @pcie: Pointer to the PCI controller state
- * @index: ATU region index
- * @type: ATU accsess type
- * @cpu_addr: the physical address for the translation entry
- * @pci_addr: the pcie bus address for the translation entry
- * @size: the size of the translation entry
- */
-static void pcie_dw_prog_outbound_atu_unroll(struct pcie_dw_ti *pci, int index,
- int type, u64 cpu_addr,
- u64 pci_addr, u32 size)
-{
- u32 retries, val;
-
- debug("ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
- index, type, cpu_addr, pci_addr, size);
-
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
- lower_32_bits(cpu_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
- upper_32_bits(cpu_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
- lower_32_bits(cpu_addr + size - 1));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
- lower_32_bits(pci_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
- upper_32_bits(pci_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
- type);
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
- PCIE_ATU_ENABLE);
-
- /*
- * Make sure ATU enable takes effect before any subsequent config
- * and I/O accesses.
- */
- for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
- val = dw_pcie_readl_ob_unroll(pci, index,
- PCIE_ATU_UNR_REGION_CTRL2);
- if (val & PCIE_ATU_ENABLE)
- return;
-
- udelay(LINK_WAIT_IATU);
- }
- dev_err(pci->dev, "outbound iATU is not being enabled\n");
-}
-
-/**
- * set_cfg_address() - Configure the PCIe controller config space access
- *
- * @pcie: Pointer to the PCI controller state
- * @d: PCI device to access
- * @where: Offset in the configuration space
- *
- * Configures the PCIe controller to access the configuration space of
- * a specific PCIe device and returns the address to use for this
- * access.
- *
- * Return: Address that can be used to access the configation space
- * of the requested device / offset
- */
-static uintptr_t set_cfg_address(struct pcie_dw_ti *pcie,
- pci_dev_t d, uint where)
-{
- int bus = PCI_BUS(d) - pcie->first_busno;
- uintptr_t va_address;
- u32 atu_type;
-
- /* Use dbi_base for own configuration read and write */
- if (!bus) {
- va_address = (uintptr_t)pcie->dbi_base;
- goto out;
- }
-
- if (bus == 1)
- /* For local bus, change TLP Type field to 4. */
- atu_type = PCIE_ATU_TYPE_CFG0;
- else
- /* Otherwise, change TLP Type field to 5. */
- atu_type = PCIE_ATU_TYPE_CFG1;
-
- /*
- * Not accessing root port configuration space?
- * Region #0 is used for Outbound CFG space access.
- * Direction = Outbound
- * Region Index = 0
- */
- d = PCI_MASK_BUS(d);
- d = PCI_ADD_BUS(bus, d);
- pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
- atu_type, (u64)pcie->cfg_base,
- d << 8, pcie->cfg_size);
-
- va_address = (uintptr_t)pcie->cfg_base;
-
-out:
- va_address += where & ~0x3;
-
- return va_address;
-}
-
-/**
- * pcie_dw_addr_valid() - Check for valid bus address
- *
- * @d: The PCI device to access
- * @first_busno: Bus number of the PCIe controller root complex
- *
- * Return 1 (true) if the PCI device can be accessed by this controller.
- *
- * Return: 1 on valid, 0 on invalid
- */
-static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
-{
- if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
- return 0;
- if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
- return 0;
-
- return 1;
-}
-
-/**
- * pcie_dw_ti_read_config() - Read from configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @valuep: A pointer at which to store the read value
- * @size: Indicates the size of access to perform
- *
- * Read a value of size @size from offset @offset within the configuration
- * space of the device identified by the bus, device & function numbers in @bdf
- * on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int pcie_dw_ti_read_config(const struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong *valuep,
- enum pci_size_t size)
-{
- struct pcie_dw_ti *pcie = dev_get_priv(bus);
- uintptr_t va_address;
- ulong value;
-
- debug("PCIE CFG read: bdf=%2x:%2x:%2x ",
- PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
- if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
- debug("- out of range\n");
- *valuep = pci_get_ff(size);
- return 0;
- }
-
- va_address = set_cfg_address(pcie, bdf, offset);
-
- value = readl(va_address);
-
- debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
- *valuep = pci_conv_32_to_size(value, offset, size);
-
- pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_TYPE_IO, pcie->io.phys_start,
- pcie->io.bus_start, pcie->io.size);
-
- return 0;
-}
-
-/**
- * pcie_dw_ti_write_config() - Write to configuration space
- *
- * @bus: Pointer to the PCI bus
- * @bdf: Identifies the PCIe device to access
- * @offset: The offset into the device's configuration space
- * @value: The value to write
- * @size: Indicates the size of access to perform
- *
- * Write the value @value of size @size from offset @offset within the
- * configuration space of the device identified by the bus, device & function
- * numbers in @bdf on the PCI bus @bus.
- *
- * Return: 0 on success
- */
-static int pcie_dw_ti_write_config(struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong value,
- enum pci_size_t size)
-{
- struct pcie_dw_ti *pcie = dev_get_priv(bus);
- uintptr_t va_address;
- ulong old;
-
- debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
- PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
- debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
-
- if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
- debug("- out of range\n");
- return 0;
- }
-
- va_address = set_cfg_address(pcie, bdf, offset);
-
- old = readl(va_address);
- value = pci_conv_size_to_32(old, value, offset, size);
- writel(value, va_address);
-
- pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_TYPE_IO, pcie->io.phys_start,
- pcie->io.bus_start, pcie->io.size);
-
- return 0;
-}
-
-static inline void dw_pcie_dbi_write_enable(struct pcie_dw_ti *pci, bool en)
-{
- u32 val;
-
- val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
- if (en)
- val |= PCIE_DBI_RO_WR_EN;
- else
- val &= ~PCIE_DBI_RO_WR_EN;
- writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
-}
-
/**
* pcie_dw_configure() - Configure link capabilities and speed
*
@@ -395,19 +84,19 @@ static void pcie_dw_configure(struct pcie_dw_ti *pci, u32 cap_speed)
{
u32 val;
- dw_pcie_dbi_write_enable(pci, true);
+ dw_pcie_dbi_write_enable(&pci->dw, true);
- val = readl(pci->dbi_base + PCIE_LINK_CAPABILITY);
+ val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
val &= ~TARGET_LINK_SPEED_MASK;
val |= cap_speed;
- writel(val, pci->dbi_base + PCIE_LINK_CAPABILITY);
+ writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
- val = readl(pci->dbi_base + PCIE_LINK_CTL_2);
+ val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2);
val &= ~TARGET_LINK_SPEED_MASK;
val |= cap_speed;
- writel(val, pci->dbi_base + PCIE_LINK_CTL_2);
+ writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2);
- dw_pcie_dbi_write_enable(pci, false);
+ dw_pcie_dbi_write_enable(&pci->dw, false);
}
/**
@@ -421,7 +110,7 @@ static int is_link_up(struct pcie_dw_ti *pci)
{
u32 val;
- val = readl(pci->dbi_base + PCIE_PORT_DEBUG0);
+ val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0);
val &= PORT_LOGIC_LTSSM_STATE_MASK;
return (val == PORT_LOGIC_LTSSM_STATE_L0);
@@ -477,56 +166,6 @@ static int pcie_dw_ti_pcie_link_up(struct pcie_dw_ti *pci, u32 cap_speed)
return 1;
}
-/**
- * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
- *
- * @pcie: Pointer to the PCI controller state
- *
- * Configure the host BARs of the PCIe controller root port so that
- * PCI(e) devices may access the system memory.
- */
-static void pcie_dw_setup_host(struct pcie_dw_ti *pci)
-{
- u32 val;
-
- /* setup RC BARs */
- writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
- pci->dbi_base + PCI_BASE_ADDRESS_0);
- writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
-
- /* setup interrupt pins */
- dw_pcie_dbi_write_enable(pci, true);
- val = readl(pci->dbi_base + PCI_INTERRUPT_LINE);
- val &= 0xffff00ff;
- val |= 0x00000100;
- writel(val, pci->dbi_base + PCI_INTERRUPT_LINE);
- dw_pcie_dbi_write_enable(pci, false);
-
- /* setup bus numbers */
- val = readl(pci->dbi_base + PCI_PRIMARY_BUS);
- val &= 0xff000000;
- val |= 0x00ff0100;
- writel(val, pci->dbi_base + PCI_PRIMARY_BUS);
-
- /* setup command register */
- val = readl(pci->dbi_base + PCI_COMMAND);
- val &= 0xffff0000;
- val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
- writel(val, pci->dbi_base + PCI_COMMAND);
-
- /* Enable write permission for the DBI read-only register */
- dw_pcie_dbi_write_enable(pci, true);
- /* program correct class for RC */
- writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
- /* Better disable write permission right after the update */
- dw_pcie_dbi_write_enable(pci, false);
-
- val = readl(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
- val |= PORT_LOGIC_SPEED_CHANGE;
- writel(val, pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
-}
-
static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
enum dw_pcie_device_mode mode)
{
@@ -535,7 +174,7 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
u32 mask;
int ret;
- syscon = syscon_regmap_lookup_by_phandle(pci->dev,
+ syscon = syscon_regmap_lookup_by_phandle(pci->dw.dev,
"ti,syscon-pcie-mode");
if (IS_ERR(syscon))
return 0;
@@ -550,13 +189,13 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
val = EP;
break;
default:
- dev_err(pci->dev, "INVALID device type %d\n", mode);
+ dev_err(pci->dw.dev, "INVALID device type %d\n", mode);
return -EINVAL;
}
ret = regmap_update_bits(syscon, 0, mask, val);
if (ret) {
- dev_err(pci->dev, "failed to set pcie mode\n");
+ dev_err(pci->dw.dev, "failed to set pcie mode\n");
return ret;
}
@@ -569,7 +208,7 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci)
unsigned int id;
int ret;
- devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dev,
+ devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dw.dev,
"ti,syscon-pcie-id");
if (IS_ERR(devctrl_regs))
return PTR_ERR(devctrl_regs);
@@ -578,10 +217,10 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci)
if (ret)
return ret;
- dw_pcie_dbi_write_enable(pci, true);
- writew(id & PCIE_VENDORID_MASK, pci->dbi_base + PCI_VENDOR_ID);
- writew(id >> PCIE_DEVICEID_SHIFT, pci->dbi_base + PCI_DEVICE_ID);
- dw_pcie_dbi_write_enable(pci, false);
+ dw_pcie_dbi_write_enable(&pci->dw, true);
+ writew(id & PCIE_VENDORID_MASK, pci->dw.dbi_base + PCI_VENDOR_ID);
+ writew(id >> PCIE_DEVICEID_SHIFT, pci->dw.dbi_base + PCI_DEVICE_ID);
+ dw_pcie_dbi_write_enable(&pci->dw, false);
return 0;
}
@@ -635,10 +274,10 @@ static int pcie_dw_ti_probe(struct udevice *dev)
generic_phy_init(&phy1);
generic_phy_power_on(&phy1);
- pci->first_busno = dev_seq(dev);
- pci->dev = dev;
+ pci->dw.first_busno = dev_seq(dev);
+ pci->dw.dev = dev;
- pcie_dw_setup_host(pci);
+ pcie_dw_setup_host(&pci->dw);
pcie_dw_init_id(pci);
if (device_is_compatible(dev, "ti,am654-pcie-rc"))
@@ -650,23 +289,14 @@ static int pcie_dw_ti_probe(struct udevice *dev)
}
printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
- pcie_dw_get_link_speed(pci),
- pcie_dw_get_link_width(pci),
+ pcie_dw_get_link_speed(&pci->dw),
+ pcie_dw_get_link_width(&pci->dw),
hose->first_busno);
- /* Store the IO and MEM windows settings for future use by the ATU */
- pci->io.phys_start = hose->regions[0].phys_start; /* IO base */
- pci->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */
- pci->io.size = hose->regions[0].size; /* IO size */
-
- pci->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
- pci->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */
- pci->mem.size = hose->regions[1].size; /* MEM size */
-
- pcie_dw_prog_outbound_atu_unroll(pci, PCIE_ATU_REGION_INDEX0,
+ pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM,
- pci->mem.phys_start,
- pci->mem.bus_start, pci->mem.size);
+ pci->dw.mem.phys_start,
+ pci->dw.mem.bus_start, pci->dw.mem.size);
return 0;
}
@@ -687,19 +317,19 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev)
struct pcie_dw_ti *pcie = dev_get_priv(dev);
/* Get the controller base address */
- pcie->dbi_base = (void *)dev_read_addr_name(dev, "dbics");
- if ((fdt_addr_t)pcie->dbi_base == FDT_ADDR_T_NONE)
+ pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbics");
+ if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE)
return -EINVAL;
/* Get the config space base address and size */
- pcie->cfg_base = (void *)dev_read_addr_size_name(dev, "config",
- &pcie->cfg_size);
- if ((fdt_addr_t)pcie->cfg_base == FDT_ADDR_T_NONE)
+ pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+ &pcie->dw.cfg_size);
+ if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE)
return -EINVAL;
/* Get the iATU base address and size */
- pcie->atu_base = (void *)dev_read_addr_name(dev, "atu");
- if ((fdt_addr_t)pcie->atu_base == FDT_ADDR_T_NONE)
+ pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+ if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE)
return -EINVAL;
/* Get the app base address and size */
@@ -711,8 +341,8 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev)
}
static const struct dm_pci_ops pcie_dw_ti_ops = {
- .read_config = pcie_dw_ti_read_config,
- .write_config = pcie_dw_ti_write_config,
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
};
static const struct udevice_id pcie_dw_ti_ids[] = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
index 7ce64fde25f..5d4bec22346 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7629.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
@@ -201,6 +201,10 @@ static int mt7629_wf2g_led_funcs[] = { 1, };
static int mt7629_wf5g_led_pins[] = { 18, };
static int mt7629_wf5g_led_funcs[] = { 1, };
+/* LED for EPHY used as JTAG */
+static int mt7629_ephy_leds_jtag_pins[] = { 12, 13, 14, 15, 16, };
+static int mt7629_ephy_leds_jtag_funcs[] = { 7, 7, 7, 7, 7, };
+
/* Watchdog */
static int mt7629_watchdog_pins[] = { 11, };
static int mt7629_watchdog_funcs[] = { 1, };
@@ -297,6 +301,7 @@ static const struct mtk_group_desc mt7629_groups[] = {
PINCTRL_PIN_GROUP("ephy_led2", mt7629_ephy_led2),
PINCTRL_PIN_GROUP("ephy_led3", mt7629_ephy_led3),
PINCTRL_PIN_GROUP("ephy_led4", mt7629_ephy_led4),
+ PINCTRL_PIN_GROUP("ephy_leds_jtag", mt7629_ephy_leds_jtag),
PINCTRL_PIN_GROUP("wf2g_led", mt7629_wf2g_led),
PINCTRL_PIN_GROUP("wf5g_led", mt7629_wf5g_led),
PINCTRL_PIN_GROUP("watchdog", mt7629_watchdog),
@@ -364,6 +369,7 @@ static const char *const mt7629_uart_groups[] = { "uart1_0_txd_rxd",
static const char *const mt7629_wdt_groups[] = { "watchdog", };
static const char *const mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", };
static const char *const mt7629_flash_groups[] = { "snfi", "spi_nor" };
+static const char *const mt7629_jtag_groups[] = { "ephy_leds_jtag" };
static const struct mtk_function_desc mt7629_functions[] = {
{"eth", mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)},
@@ -376,6 +382,7 @@ static const struct mtk_function_desc mt7629_functions[] = {
{"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)},
{"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)},
{"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)},
+ {"jtag", mt7629_jtag_groups, ARRAY_SIZE(mt7629_jtag_groups)},
};
static struct mtk_pinctrl_soc mt7629_data = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 4dd3f73ead2..3bd23befd88 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -219,7 +219,7 @@ static const char *mtk_get_pin_name(struct udevice *dev,
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
- if (!priv->soc->grps[selector].name)
+ if (!priv->soc->pins[selector].name)
return mtk_pinctrl_dummy_name;
return priv->soc->pins[selector].name;
@@ -232,6 +232,19 @@ static int mtk_get_pins_count(struct udevice *dev)
return priv->soc->npins;
}
+static int mtk_get_pin_muxing(struct udevice *dev, unsigned int selector,
+ char *buf, int size)
+{
+ int val, err;
+
+ err = mtk_hw_get_value(dev, selector, PINCTRL_PIN_REG_MODE, &val);
+ if (err)
+ return err;
+
+ snprintf(buf, size, "Aux Func.%d", val);
+ return 0;
+}
+
static const char *mtk_get_group_name(struct udevice *dev,
unsigned int selector)
{
@@ -512,6 +525,7 @@ static int mtk_pinconf_group_set(struct udevice *dev,
const struct pinctrl_ops mtk_pinctrl_ops = {
.get_pins_count = mtk_get_pins_count,
.get_pin_name = mtk_get_pin_name,
+ .get_pin_muxing = mtk_get_pin_muxing,
.get_groups_count = mtk_get_groups_count,
.get_group_name = mtk_get_group_name,
.get_functions_count = mtk_get_functions_count,
@@ -526,6 +540,8 @@ const struct pinctrl_ops mtk_pinctrl_ops = {
.set_state = pinctrl_generic_set_state,
};
+#if CONFIG_IS_ENABLED(DM_GPIO) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
static int mtk_gpio_get(struct udevice *dev, unsigned int off)
{
int val, err;
@@ -633,12 +649,13 @@ static int mtk_gpiochip_register(struct udevice *parent)
return 0;
}
+#endif
int mtk_pinctrl_common_probe(struct udevice *dev,
struct mtk_pinctrl_soc *soc)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
- int ret;
+ int ret = 0;
priv->base = dev_read_addr_ptr(dev);
if (!priv->base)
@@ -646,9 +663,10 @@ int mtk_pinctrl_common_probe(struct udevice *dev,
priv->soc = soc;
+#if CONFIG_IS_ENABLED(DM_GPIO) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
ret = mtk_gpiochip_register(dev);
- if (ret)
- return ret;
+#endif
- return 0;
+ return ret;
}
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index b7ae2f6adab..26fb5d61d5d 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -25,6 +25,7 @@ DECLARE_GLOBAL_DATA_PTR;
struct atmel_pio4_plat {
struct atmel_pio4_port *reg_base;
+ unsigned int slew_rate_support;
};
static const struct pinconf_param conf_params[] = {
@@ -36,9 +37,11 @@ static const struct pinconf_param conf_params[] = {
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
{ "atmel,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "slew-rate", PIN_CONFIG_SLEW_RATE, 0},
};
-static u32 atmel_pinctrl_get_pinconf(struct udevice *config)
+static u32 atmel_pinctrl_get_pinconf(struct udevice *config,
+ struct atmel_pio4_plat *plat)
{
const struct pinconf_param *params;
u32 param, arg, conf = 0;
@@ -53,6 +56,10 @@ static u32 atmel_pinctrl_get_pinconf(struct udevice *config)
param = params->param;
arg = params->default_value;
+ /* Keep slew rate enabled by default. */
+ if (plat->slew_rate_support)
+ conf |= ATMEL_PIO_SR;
+
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
conf &= (~ATMEL_PIO_PUEN_MASK);
@@ -91,6 +98,15 @@ static u32 atmel_pinctrl_get_pinconf(struct udevice *config)
conf |= (val << ATMEL_PIO_DRVSTR_OFFSET)
& ATMEL_PIO_DRVSTR_MASK;
break;
+ case PIN_CONFIG_SLEW_RATE:
+ if (!plat->slew_rate_support)
+ break;
+
+ dev_read_u32(config, params->property, &val);
+ /* And disable it if requested. */
+ if (val == 0)
+ conf &= ~ATMEL_PIO_SR;
+ break;
default:
printf("%s: Unsupported configuration parameter: %u\n",
__func__, param);
@@ -116,6 +132,7 @@ static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
+ struct atmel_pio4_plat *plat = dev_get_plat(dev);
struct atmel_pio4_port *bank_base;
const void *blob = gd->fdt_blob;
int node = dev_of_offset(config);
@@ -124,7 +141,7 @@ static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
u32 i, conf;
int count;
- conf = atmel_pinctrl_get_pinconf(config);
+ conf = atmel_pinctrl_get_pinconf(config, plat);
count = fdtdec_get_int_array_count(blob, node, "pinmux",
cells, ARRAY_SIZE(cells));
@@ -164,6 +181,7 @@ const struct pinctrl_ops atmel_pinctrl_ops = {
static int atmel_pinctrl_probe(struct udevice *dev)
{
struct atmel_pio4_plat *plat = dev_get_plat(dev);
+ ulong priv = dev_get_driver_data(dev);
fdt_addr_t addr_base;
dev = dev_get_parent(dev);
@@ -172,13 +190,15 @@ static int atmel_pinctrl_probe(struct udevice *dev)
return -EINVAL;
plat->reg_base = (struct atmel_pio4_port *)addr_base;
+ plat->slew_rate_support = priv;
return 0;
}
static const struct udevice_id atmel_pinctrl_match[] = {
{ .compatible = "atmel,sama5d2-pinctrl" },
- { .compatible = "microchip,sama7g5-pinctrl" },
+ { .compatible = "microchip,sama7g5-pinctrl",
+ .data = (ulong)1, },
{}
};
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index 1a8d0a3a35e..fe7a59d4313 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -163,12 +163,14 @@ static int stmfx_gpio_direction_output(struct udevice *dev,
return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1);
}
-static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
+static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
{
int ret = -ENOTSUPP;
if (flags & GPIOD_IS_OUT) {
+ bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
if (flags & GPIOD_OPEN_SOURCE)
return -ENOTSUPP;
if (flags & GPIOD_OPEN_DRAIN)
@@ -177,8 +179,7 @@ static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
ret = stmfx_conf_set_type(dev, offset, 1);
if (ret)
return ret;
- ret = stmfx_gpio_direction_output(dev, offset,
- GPIOD_FLAGS_OUTPUT(flags));
+ ret = stmfx_gpio_direction_output(dev, offset, value);
} else if (flags & GPIOD_IS_IN) {
ret = stmfx_gpio_direction_input(dev, offset);
if (ret)
@@ -199,8 +200,8 @@ static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
return ret;
}
-static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
- ulong *flags)
+static int stmfx_gpio_get_flags(struct udevice *dev, unsigned int offset,
+ ulong *flagsp)
{
ulong dir_flags = 0;
int ret;
@@ -233,7 +234,7 @@ static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
dir_flags |= GPIOD_PULL_DOWN;
}
}
- *flags = dir_flags;
+ *flagsp = dir_flags;
return 0;
}
@@ -266,8 +267,8 @@ static const struct dm_gpio_ops stmfx_gpio_ops = {
.get_function = stmfx_gpio_get_function,
.direction_input = stmfx_gpio_direction_input,
.direction_output = stmfx_gpio_direction_output,
- .set_dir_flags = stmfx_gpio_set_dir_flags,
- .get_dir_flags = stmfx_gpio_get_dir_flags,
+ .set_flags = stmfx_gpio_set_flags,
+ .get_flags = stmfx_gpio_get_flags,
};
U_BOOT_DRIVER(stmfx_gpio) = {
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index b0f30aa1f75..6e68e52c32c 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -235,8 +235,9 @@ int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
return ret;
ops = pinctrl_get_ops(pctldev);
- if (!ops || !ops->gpio_request_enable)
- return -ENOTSUPP;
+ assert(ops);
+ if (!ops->gpio_request_enable)
+ return -ENOSYS;
return ops->gpio_request_enable(pctldev, pin_selector);
}
@@ -261,8 +262,9 @@ int pinctrl_gpio_free(struct udevice *dev, unsigned offset)
return ret;
ops = pinctrl_get_ops(pctldev);
- if (!ops || !ops->gpio_disable_free)
- return -ENOTSUPP;
+ assert(ops);
+ if (!ops->gpio_disable_free)
+ return -ENOSYS;
return ops->gpio_disable_free(pctldev, pin_selector);
}
diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig
index d2be4c84ba1..8fb9cba3875 100644
--- a/drivers/pinctrl/renesas/Kconfig
+++ b/drivers/pinctrl/renesas/Kconfig
@@ -77,6 +77,16 @@ config PINCTRL_PFC_R8A774B1
the GPIO definitions and pin control functions for each available
multiplex function.
+config PINCTRL_PFC_R8A774C0
+ bool "Renesas RZ/G2 R8A774C0 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas RZ/G2E R8A774C0 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.
+
config PINCTRL_PFC_R8A774E1
bool "Renesas RZ/G2 R8A774E1 pin control driver"
depends on PINCTRL_PFC
diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile
index 1d007520512..0e2ac3c5136 100644
--- a/drivers/pinctrl/renesas/Makefile
+++ b/drivers/pinctrl/renesas/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_PINCTRL_PFC) += pfc.o
obj-$(CONFIG_PINCTRL_PFC_R8A774A1) += pfc-r8a7796.o
obj-$(CONFIG_PINCTRL_PFC_R8A774B1) += pfc-r8a77965.o
+obj-$(CONFIG_PINCTRL_PFC_R8A774C0) += pfc-r8a77990.o
obj-$(CONFIG_PINCTRL_PFC_R8A774E1) += pfc-r8a7795.o
obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o
obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o
diff --git a/drivers/pinctrl/renesas/pfc-r8a77990.c b/drivers/pinctrl/renesas/pfc-r8a77990.c
index b13fc0ba632..572b041b83e 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77990.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77990.c
@@ -1603,6 +1603,7 @@ static const unsigned int canfd1_data_mux[] = {
CANFD1_TX_MARK, CANFD1_RX_MARK,
};
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
/* - DRIF0 --------------------------------------------------------------- */
static const unsigned int drif0_ctrl_a_pins[] = {
/* CLK, SYNC */
@@ -1795,6 +1796,7 @@ static const unsigned int drif3_data1_b_pins[] = {
static const unsigned int drif3_data1_b_mux[] = {
RIF3_D1_B_MARK,
};
+#endif /* CONFIG_PINCTRL_PFC_R8A77990 */
/* - DU --------------------------------------------------------------------- */
static const unsigned int du_rgb666_pins[] = {
@@ -2818,6 +2820,57 @@ static const unsigned int pwm6_b_mux[] = {
PWM6_B_MARK,
};
+/* - QSPI0 ------------------------------------------------------------------ */
+static const unsigned int qspi0_ctrl_pins[] = {
+ /* QSPI0_SPCLK, QSPI0_SSL */
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 5),
+};
+static const unsigned int qspi0_ctrl_mux[] = {
+ QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
+};
+static const unsigned int qspi0_data2_pins[] = {
+ /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */
+ RCAR_GP_PIN(2, 1), RCAR_GP_PIN(2, 2),
+};
+static const unsigned int qspi0_data2_mux[] = {
+ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
+};
+static const unsigned int qspi0_data4_pins[] = {
+ /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */
+ RCAR_GP_PIN(2, 1), RCAR_GP_PIN(2, 2),
+ /* QSPI0_IO2, QSPI0_IO3 */
+ RCAR_GP_PIN(2, 3), RCAR_GP_PIN(2, 4),
+};
+static const unsigned int qspi0_data4_mux[] = {
+ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
+ QSPI0_IO2_MARK, QSPI0_IO3_MARK,
+};
+/* - QSPI1 ------------------------------------------------------------------ */
+static const unsigned int qspi1_ctrl_pins[] = {
+ /* QSPI1_SPCLK, QSPI1_SSL */
+ RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 11),
+};
+static const unsigned int qspi1_ctrl_mux[] = {
+ QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
+};
+static const unsigned int qspi1_data2_pins[] = {
+ /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */
+ RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+};
+static const unsigned int qspi1_data2_mux[] = {
+ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
+};
+static const unsigned int qspi1_data4_pins[] = {
+ /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */
+ RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+ /* QSPI1_IO2, QSPI1_IO3 */
+ RCAR_GP_PIN(2, 9), RCAR_GP_PIN(2, 10),
+};
+static const unsigned int qspi1_data4_mux[] = {
+ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
+ QSPI1_IO2_MARK, QSPI1_IO3_MARK,
+};
+
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_a_pins[] = {
/* RX, TX */
@@ -3770,8 +3823,10 @@ static const unsigned int vin5_clk_b_mux[] = {
};
static const struct {
- struct sh_pfc_pin_group common[247];
+ struct sh_pfc_pin_group common[253];
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
struct sh_pfc_pin_group automotive[21];
+#endif
} pinmux_groups = {
.common = {
SH_PFC_PIN_GROUP(audio_clk_a),
@@ -3916,6 +3971,12 @@ static const struct {
SH_PFC_PIN_GROUP(pwm5_b),
SH_PFC_PIN_GROUP(pwm6_a),
SH_PFC_PIN_GROUP(pwm6_b),
+ SH_PFC_PIN_GROUP(qspi0_ctrl),
+ SH_PFC_PIN_GROUP(qspi0_data2),
+ SH_PFC_PIN_GROUP(qspi0_data4),
+ SH_PFC_PIN_GROUP(qspi1_ctrl),
+ SH_PFC_PIN_GROUP(qspi1_data2),
+ SH_PFC_PIN_GROUP(qspi1_data4),
SH_PFC_PIN_GROUP(scif0_data_a),
SH_PFC_PIN_GROUP(scif0_clk_a),
SH_PFC_PIN_GROUP(scif0_ctrl_a),
@@ -4022,6 +4083,7 @@ static const struct {
SH_PFC_PIN_GROUP(vin5_clk_a),
SH_PFC_PIN_GROUP(vin5_clk_b),
},
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
.automotive = {
SH_PFC_PIN_GROUP(drif0_ctrl_a),
SH_PFC_PIN_GROUP(drif0_data0_a),
@@ -4045,6 +4107,7 @@ static const struct {
SH_PFC_PIN_GROUP(drif3_data0_b),
SH_PFC_PIN_GROUP(drif3_data1_b),
}
+#endif /* CONFIG_PINCTRL_PFC_R8A77990 */
};
static const char * const audio_clk_groups[] = {
@@ -4098,6 +4161,7 @@ static const char * const canfd1_groups[] = {
"canfd1_data",
};
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
static const char * const drif0_groups[] = {
"drif0_ctrl_a",
"drif0_data0_a",
@@ -4130,6 +4194,7 @@ static const char * const drif3_groups[] = {
"drif3_data0_b",
"drif3_data1_b",
};
+#endif /* CONFIG_PINCTRL_PFC_R8A77990 */
static const char * const du_groups[] = {
"du_rgb666",
@@ -4315,6 +4380,18 @@ static const char * const pwm6_groups[] = {
"pwm6_b",
};
+static const char * const qspi0_groups[] = {
+ "qspi0_ctrl",
+ "qspi0_data2",
+ "qspi0_data4",
+};
+
+static const char * const qspi1_groups[] = {
+ "qspi1_ctrl",
+ "qspi1_data2",
+ "qspi1_data4",
+};
+
static const char * const scif0_groups[] = {
"scif0_data_a",
"scif0_clk_a",
@@ -4469,8 +4546,10 @@ static const char * const vin5_groups[] = {
};
static const struct {
- struct sh_pfc_function common[47];
+ struct sh_pfc_function common[49];
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
struct sh_pfc_function automotive[4];
+#endif
} pinmux_functions = {
.common = {
SH_PFC_FUNCTION(audio_clk),
@@ -4504,6 +4583,8 @@ static const struct {
SH_PFC_FUNCTION(pwm4),
SH_PFC_FUNCTION(pwm5),
SH_PFC_FUNCTION(pwm6),
+ SH_PFC_FUNCTION(qspi0),
+ SH_PFC_FUNCTION(qspi1),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
@@ -4521,12 +4602,14 @@ static const struct {
SH_PFC_FUNCTION(vin4),
SH_PFC_FUNCTION(vin5),
},
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
.automotive = {
SH_PFC_FUNCTION(drif0),
SH_PFC_FUNCTION(drif1),
SH_PFC_FUNCTION(drif2),
SH_PFC_FUNCTION(drif3),
}
+#endif /* CONFIG_PINCTRL_PFC_R8A77990 */
};
static const struct pinmux_cfg_reg pinmux_config_regs[] = {
diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c
index 6ff948420c5..07fcc3d3931 100644
--- a/drivers/pinctrl/renesas/pfc.c
+++ b/drivers/pinctrl/renesas/pfc.c
@@ -34,6 +34,7 @@ enum sh_pfc_model {
SH_PFC_R8A7796,
SH_PFC_R8A774A1,
SH_PFC_R8A774B1,
+ SH_PFC_R8A774C0,
SH_PFC_R8A774E1,
SH_PFC_R8A77965,
SH_PFC_R8A77970,
@@ -927,6 +928,10 @@ static int sh_pfc_pinctrl_probe(struct udevice *dev)
if (model == SH_PFC_R8A774B1)
priv->pfc.info = &r8a774b1_pinmux_info;
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A774C0
+ if (model == SH_PFC_R8A774C0)
+ priv->pfc.info = &r8a774c0_pinmux_info;
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A774E1
if (model == SH_PFC_R8A774E1)
priv->pfc.info = &r8a774e1_pinmux_info;
@@ -1014,6 +1019,12 @@ static const struct udevice_id sh_pfc_pinctrl_ids[] = {
.data = SH_PFC_R8A774B1,
},
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A774C0
+ {
+ .compatible = "renesas,pfc-r8a774c0",
+ .data = SH_PFC_R8A774C0,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A774E1
{
.compatible = "renesas,pfc-r8a774e1",
diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h
index 22cc860f296..f563916f109 100644
--- a/drivers/pinctrl/renesas/sh_pfc.h
+++ b/drivers/pinctrl/renesas/sh_pfc.h
@@ -295,6 +295,7 @@ sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin,
extern const struct sh_pfc_soc_info r8a774a1_pinmux_info;
extern const struct sh_pfc_soc_info r8a774b1_pinmux_info;
+extern const struct sh_pfc_soc_info r8a774c0_pinmux_info;
extern const struct sh_pfc_soc_info r8a774e1_pinmux_info;
extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 7b4c0f02c60..89099fde573 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
-obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o
obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
diff --git a/drivers/power/pmic/pmic_max77696.c b/drivers/power/pmic/pmic_max77696.c
deleted file mode 100644
index f3a73d6405f..00000000000
--- a/drivers/power/pmic/pmic_max77696.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2015 Freescale Semiconductor, Inc.
- * Fabio Estevam <fabio.estevam@freescale.com>
- */
-
-#include <common.h>
-#include <errno.h>
-#include <i2c.h>
-#include <power/pmic.h>
-#include <power/max77696_pmic.h>
-
-int power_max77696_init(unsigned char bus)
-{
- static const char name[] = "MAX77696";
- struct pmic *p = pmic_alloc();
-
- if (!p) {
- printf("%s: POWER allocation error!\n", __func__);
- return -ENOMEM;
- }
-
- p->name = name;
- p->interface = PMIC_I2C;
- p->number_of_regs = PMIC_NUM_OF_REGS;
- p->hw.i2c.addr = CONFIG_POWER_MAX77696_I2C_ADDR;
- p->hw.i2c.tx_num = 1;
- p->bus = bus;
-
- return 0;
-}
diff --git a/drivers/power/pmic/pmic_pca9450.c b/drivers/power/pmic/pmic_pca9450.c
index d4f27428bd1..8c4d0a92306 100644
--- a/drivers/power/pmic/pmic_pca9450.c
+++ b/drivers/power/pmic/pmic_pca9450.c
@@ -11,7 +11,7 @@
static const char pca9450_name[] = "PCA9450";
-int power_pca9450_init(unsigned char bus)
+int power_pca9450_init(unsigned char bus, unsigned char addr)
{
struct pmic *p = pmic_alloc();
@@ -23,7 +23,7 @@ int power_pca9450_init(unsigned char bus)
p->name = pca9450_name;
p->interface = PMIC_I2C;
p->number_of_regs = PCA9450_REG_NUM;
- p->hw.i2c.addr = 0x25;
+ p->hw.i2c.addr = addr;
p->hw.i2c.tx_num = 1;
p->bus = bus;
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index fbbea18c7d1..5d6180229e9 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -353,3 +353,11 @@ config DM_REGULATOR_TPS65941
TPS65941 series of PMICs have 5 single phase BUCKs that can also
be configured in multi phase modes & 4 LDOs. The driver implements
get/set api for value and enable.
+
+config DM_REGULATOR_SCMI
+ bool "Enable driver for SCMI voltage domain regulators"
+ depends on DM_REGULATOR
+ select SCMI_AGENT
+ help
+ Enable this option if you want to support regulators exposed through
+ the SCMI voltage domain protocol by a SCMI server.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 9d58112dcb1..b2f5972ea79 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
+obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c
new file mode 100644
index 00000000000..b3142bf4e1f
--- /dev/null
+++ b/drivers/power/regulator/scmi_regulator.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2021 Linaro Limited
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <linux/kernel.h>
+#include <power/regulator.h>
+
+/**
+ * struct scmi_regulator_platdata - Platform data for a scmi voltage domain regulator
+ * @domain_id: ID representing the regulator for the related SCMI agent
+ */
+struct scmi_regulator_platdata {
+ u32 domain_id;
+};
+
+static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_config_set_in in = {
+ .domain_id = pdata->domain_id,
+ .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
+ };
+ struct scmi_voltd_config_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int scmi_voltd_get_enable(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_config_get_in in = {
+ .domain_id = pdata->domain_id,
+ };
+ struct scmi_voltd_config_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return out.config == SCMI_VOLTD_CONFIG_ON;
+}
+
+static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_level_set_in in = {
+ .domain_id = pdata->domain_id,
+ .voltage_level = uV,
+ };
+ struct scmi_voltd_level_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_voltd_get_voltage_level(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_level_get_in in = {
+ .domain_id = pdata->domain_id,
+ };
+ struct scmi_voltd_level_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return out.voltage_level;
+}
+
+static int scmi_regulator_of_to_plat(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ fdt_addr_t reg;
+
+ reg = dev_read_addr(dev);
+ if (reg == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ pdata->domain_id = (u32)reg;
+
+ return 0;
+}
+
+static int scmi_regulator_probe(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_attr_in in = { 0 };
+ struct scmi_voltd_attr_out out = { 0 };
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ .message_id = SCMI_VOLTAGE_DOMAIN_ATTRIBUTES,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ /* Check voltage domain is known from SCMI server */
+ in.domain_id = pdata->domain_id;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &scmi_msg);
+ if (ret) {
+ dev_err(dev, "Failed to query voltage domain %u: %d\n",
+ pdata->domain_id, ret);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops scmi_voltd_ops = {
+ .get_value = scmi_voltd_get_voltage_level,
+ .set_value = scmi_voltd_set_voltage_level,
+ .get_enable = scmi_voltd_get_enable,
+ .set_enable = scmi_voltd_set_enable,
+};
+
+U_BOOT_DRIVER(scmi_regulator) = {
+ .name = "scmi_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &scmi_voltd_ops,
+ .probe = scmi_regulator_probe,
+ .of_to_plat = scmi_regulator_of_to_plat,
+ .plat_auto = sizeof(struct scmi_regulator_platdata),
+};
+
+static int scmi_regulator_bind(struct udevice *dev)
+{
+ struct driver *drv;
+ ofnode node;
+ int ret;
+
+ drv = DM_DRIVER_GET(scmi_regulator);
+
+ ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+ ret = device_bind(dev, drv, ofnode_get_name(node),
+ NULL, node, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(scmi_voltage_domain) = {
+ .name = "scmi_voltage_domain",
+ .id = UCLASS_NOP,
+ .bind = scmi_regulator_bind,
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index ccf81abbe93..cf7f4c6840c 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -9,6 +9,15 @@ config DM_PWM
frequency/period can be controlled along with the proportion of that
time that the signal is high.
+config PWM_CROS_EC
+ bool "Enable support for the Chrome OS EC PWM"
+ depends on DM_PWM
+ help
+ This PWM is found on several Chrome OS devices and controlled by
+ the Chrome OS embedded controller. It may be used to control the
+ screen brightness and/or the keyboard backlight depending on the
+ device.
+
config PWM_EXYNOS
bool "Enable support for the Exynos PWM"
depends on DM_PWM
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0b9d2698a31..10d244bfb79 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -10,6 +10,7 @@
obj-$(CONFIG_DM_PWM) += pwm-uclass.o
+obj-$(CONFIG_PWM_CROS_EC) += cros_ec_pwm.o
obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o
obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o
obj-$(CONFIG_PWM_MESON) += pwm-meson.o
diff --git a/drivers/pwm/cros_ec_pwm.c b/drivers/pwm/cros_ec_pwm.c
new file mode 100644
index 00000000000..44f4105dfd5
--- /dev/null
+++ b/drivers/pwm/cros_ec_pwm.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <pwm.h>
+
+struct cros_ec_pwm_priv {
+ bool enabled;
+ uint duty;
+};
+
+static int cros_ec_pwm_set_config(struct udevice *dev, uint channel,
+ uint period_ns, uint duty_ns)
+{
+ struct cros_ec_pwm_priv *priv = dev_get_priv(dev);
+ uint duty;
+ int ret;
+
+ debug("%s: period_ns=%u, duty_ns=%u asked\n", __func__,
+ period_ns, duty_ns);
+
+ /* No way to set the period, only a relative duty cycle */
+ duty = EC_PWM_MAX_DUTY * duty_ns / period_ns;
+ if (duty > EC_PWM_MAX_DUTY)
+ duty = EC_PWM_MAX_DUTY;
+
+ if (!priv->enabled) {
+ priv->duty = duty;
+ debug("%s: duty=%#x to-be-set\n", __func__, duty);
+ return 0;
+ }
+
+ ret = cros_ec_set_pwm_duty(dev->parent, channel, duty);
+ if (ret) {
+ debug("%s: duty=%#x failed\n", __func__, duty);
+ return ret;
+ }
+
+ priv->duty = duty;
+ debug("%s: duty=%#x set\n", __func__, duty);
+
+ return 0;
+}
+
+static int cros_ec_pwm_set_enable(struct udevice *dev, uint channel,
+ bool enable)
+{
+ struct cros_ec_pwm_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = cros_ec_set_pwm_duty(dev->parent, channel,
+ enable ? priv->duty : 0);
+ if (ret) {
+ debug("%s: enable=%d failed\n", __func__, enable);
+ return ret;
+ }
+
+ priv->enabled = enable;
+ debug("%s: enable=%d (duty=%#x) set\n", __func__,
+ enable, priv->duty);
+
+ return 0;
+}
+
+static const struct pwm_ops cros_ec_pwm_ops = {
+ .set_config = cros_ec_pwm_set_config,
+ .set_enable = cros_ec_pwm_set_enable,
+};
+
+static const struct udevice_id cros_ec_pwm_ids[] = {
+ { .compatible = "google,cros-ec-pwm" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_pwm) = {
+ .name = "cros_ec_pwm",
+ .id = UCLASS_PWM,
+ .of_match = cros_ec_pwm_ids,
+ .ops = &cros_ec_pwm_ops,
+ .priv_auto_alloc_size = sizeof(struct cros_ec_pwm_priv),
+};
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c
index 9cf09803457..071eb04fda7 100644
--- a/drivers/pwm/rk_pwm.c
+++ b/drivers/pwm/rk_pwm.c
@@ -147,7 +147,7 @@ static int rk_pwm_probe(struct udevice *dev)
priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
if (priv->data->supports_polarity)
- priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
+ priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
return 0;
}
diff --git a/drivers/pwm/sandbox_pwm.c b/drivers/pwm/sandbox_pwm.c
index 318dce7c149..4df15f0a2e8 100644
--- a/drivers/pwm/sandbox_pwm.c
+++ b/drivers/pwm/sandbox_pwm.c
@@ -59,8 +59,15 @@ static int sandbox_pwm_set_config(struct udevice *dev, uint channel,
if (channel >= NUM_CHANNELS)
return -ENOSPC;
chan = &priv->chan[channel];
- chan->period_ns = period_ns;
- chan->duty_ns = duty_ns;
+
+ if (channel == 2) {
+ /* Pretend to have some fixed period */
+ chan->period_ns = 4096;
+ chan->duty_ns = duty_ns * 4096 / period_ns;
+ } else {
+ chan->period_ns = period_ns;
+ chan->duty_ns = duty_ns;
+ }
return 0;
}
diff --git a/drivers/qe/Kconfig b/drivers/qe/Kconfig
index 864b36b8225..553ed5780e5 100644
--- a/drivers/qe/Kconfig
+++ b/drivers/qe/Kconfig
@@ -14,7 +14,6 @@ config U_QE
default y if (ARCH_LS1021A && !SD_BOOT && !NAND_BOOT && !QSPI_BOOT) \
|| (TARGET_T1024QDS) \
|| (TARGET_T1024RDB) \
- || (TARGET_T1040QDS && !NOBQFMAN) \
|| (TARGET_LS1043ARDB && !SPL_NO_QE && !NAND_BOOT && !QSPI_BOOT)
help
Choose this option to add support for U QUICC Engine.
diff --git a/drivers/ram/sifive/Kconfig b/drivers/ram/sifive/Kconfig
index 6aca22ab2ab..08de692e026 100644
--- a/drivers/ram/sifive/Kconfig
+++ b/drivers/ram/sifive/Kconfig
@@ -8,6 +8,6 @@ config RAM_SIFIVE
config SIFIVE_FU540_DDR
bool "SiFive FU540 DDR driver"
depends on RAM_SIFIVE
- default y if TARGET_SIFIVE_FU540
+ default y if TARGET_SIFIVE_UNLEASHED
help
This enables DDR support for the platforms based on SiFive FU540 SoC.
diff --git a/drivers/ram/stm32_sdram.c b/drivers/ram/stm32_sdram.c
index 540ad851387..3e25cc7a018 100644
--- a/drivers/ram/stm32_sdram.c
+++ b/drivers/ram/stm32_sdram.c
@@ -268,6 +268,7 @@ static int stm32_fmc_of_to_plat(struct udevice *dev)
u32 swp_fmc;
ofnode bank_node;
char *bank_name;
+ char _bank_name[128] = {0};
u8 bank = 0;
int ret;
@@ -300,6 +301,8 @@ static int stm32_fmc_of_to_plat(struct udevice *dev)
dev_for_each_subnode(bank_node, dev) {
/* extract the bank index from DT */
bank_name = (char *)ofnode_get_name(bank_node);
+ strlcpy(_bank_name, bank_name, sizeof(_bank_name));
+ bank_name = (char *)_bank_name;
strsep(&bank_name, "@");
if (!bank_name) {
pr_err("missing sdram bank index");
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index f5b3f8826fb..019565f9796 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -166,7 +166,7 @@ config RESET_IPQ419
config RESET_SIFIVE
bool "Reset Driver for SiFive SoC's"
- depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_FU540
+ depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_UNLEASHED
default y
help
PRCI module within SiFive SoC's provides mechanism to reset
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index aa6d90158cd..c84a9d2b27b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -38,6 +38,13 @@ config RTC_ENABLE_32KHZ_OUTPUT
Some real-time clocks support the output of 32kHz square waves (such as ds3231),
the config symbol choose Real Time Clock device 32Khz output feature.
+config RTC_ARMADA38X
+ bool "Enable Armada 38x Marvell SoC RTC"
+ depends on DM_RTC && ARCH_MVEBU
+ help
+ This adds support for the in-chip RTC that can be found in the
+ Armada 38x Marvell's SoC devices.
+
config RTC_PCF2127
bool "Enable PCF2127 driver"
depends on DM_RTC
@@ -95,6 +102,12 @@ config RTC_PCF8563
If you say yes here you get support for the Philips PCF8563 RTC
and compatible chips.
+config RTC_RV3028
+ bool "Enable RV3028 driver"
+ depends on DM_RTC
+ help
+ The MicroCrystal RV3028 is a I2C Real Time Clock (RTC)
+
config RTC_RV3029
bool "Enable RV3029 driver"
depends on DM_RTC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6a45a9c8749..f668cf9050c 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
obj-y += rtc-lib.o
+obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o
obj-$(CONFIG_RTC_DAVINCI) += davinci.o
obj-$(CONFIG_RTC_DS1302) += ds1302.o
obj-$(CONFIG_RTC_DS1306) += ds1306.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_RTC_PCF2127) += pcf2127.o
obj-$(CONFIG_RTC_PL031) += pl031.o
obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o
+obj-$(CONFIG_RTC_RV3028) += rv3028.o
obj-$(CONFIG_RTC_RV3029) += rv3029.o
obj-$(CONFIG_RTC_RV8803) += rv8803.o
obj-$(CONFIG_RTC_RX8025) += rx8025.o
diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c
new file mode 100644
index 00000000000..2d264acf779
--- /dev/null
+++ b/drivers/rtc/armada38x.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Armada 38x Marvell SoCs
+ *
+ * Copyright (C) 2021 Marek Behun <marek.behun@nic.cz>
+ *
+ * Based on Linux' driver by Gregory Clement and Marvell
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <rtc.h>
+
+#define RTC_STATUS 0x0
+#define RTC_TIME 0xC
+#define RTC_CONF_TEST 0x1C
+
+/* Armada38x SoC registers */
+#define RTC_38X_BRIDGE_TIMING_CTL 0x0
+#define RTC_38X_PERIOD_OFFS 0
+#define RTC_38X_PERIOD_MASK (0x3FF << RTC_38X_PERIOD_OFFS)
+#define RTC_38X_READ_DELAY_OFFS 26
+#define RTC_38X_READ_DELAY_MASK (0x1F << RTC_38X_READ_DELAY_OFFS)
+
+#define SAMPLE_NR 100
+
+struct armada38x_rtc {
+ void __iomem *regs;
+ void __iomem *regs_soc;
+};
+
+/*
+ * According to Erratum RES-3124064 we have to do some configuration in MBUS.
+ * To read an RTC register we need to read it 100 times and return the most
+ * frequent value.
+ * To write an RTC register we need to write 2x zero into STATUS register,
+ * followed by the proper write. Linux adds an 5 us delay after this, so we do
+ * it here as well.
+ */
+static void update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
+{
+ u32 reg;
+
+ reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+ reg &= ~RTC_38X_PERIOD_MASK;
+ reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
+ reg &= ~RTC_38X_READ_DELAY_MASK;
+ reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
+ writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+}
+
+static void armada38x_rtc_write(u32 val, struct armada38x_rtc *rtc, u8 reg)
+{
+ writel(0, rtc->regs + RTC_STATUS);
+ writel(0, rtc->regs + RTC_STATUS);
+ writel(val, rtc->regs + reg);
+ udelay(5);
+}
+
+static u32 armada38x_rtc_read(struct armada38x_rtc *rtc, u8 reg)
+{
+ u8 counts[SAMPLE_NR], max_idx;
+ u32 samples[SAMPLE_NR], max;
+ int i, j, last;
+
+ for (i = 0, last = 0; i < SAMPLE_NR; ++i) {
+ u32 sample = readl(rtc->regs + reg);
+
+ /* find if this value was already read */
+ for (j = 0; j < last; ++j) {
+ if (samples[j] == sample)
+ break;
+ }
+
+ if (j < last) {
+ /* if yes, increment count */
+ ++counts[j];
+ } else {
+ /* if not, add */
+ samples[last] = sample;
+ counts[last] = 1;
+ ++last;
+ }
+ }
+
+ /* finally find the sample that was read the most */
+ max = 0;
+ max_idx = 0;
+
+ for (i = 0; i < last; ++i) {
+ if (counts[i] > max) {
+ max = counts[i];
+ max_idx = i;
+ }
+ }
+
+ return samples[max_idx];
+}
+
+static int armada38x_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+ u32 time;
+
+ time = armada38x_rtc_read(rtc, RTC_TIME);
+
+ rtc_to_tm(time, tm);
+
+ return 0;
+}
+
+static int armada38x_rtc_reset(struct udevice *dev)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+ u32 reg;
+
+ reg = armada38x_rtc_read(rtc, RTC_CONF_TEST);
+
+ if (reg & 0xff) {
+ armada38x_rtc_write(0, rtc, RTC_CONF_TEST);
+ mdelay(500);
+ armada38x_rtc_write(0, rtc, RTC_TIME);
+ armada38x_rtc_write(BIT(0) | BIT(1), 0, RTC_STATUS);
+ }
+
+ return 0;
+}
+
+static int armada38x_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+ unsigned long time;
+
+ time = rtc_mktime(tm);
+
+ if (time > U32_MAX)
+ printf("%s: requested time to set will overflow\n", dev->name);
+
+ armada38x_rtc_reset(dev);
+ armada38x_rtc_write(time, rtc, RTC_TIME);
+
+ return 0;
+}
+
+static int armada38x_probe(struct udevice *dev)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+
+ rtc->regs = dev_remap_addr_name(dev, "rtc");
+ if (!rtc->regs)
+ goto err;
+
+ rtc->regs_soc = dev_remap_addr_name(dev, "rtc-soc");
+ if (!rtc->regs_soc)
+ goto err;
+
+ update_38x_mbus_timing_params(rtc);
+
+ return 0;
+err:
+ printf("%s: io address missing\n", dev->name);
+ return -ENODEV;
+}
+
+static const struct rtc_ops armada38x_rtc_ops = {
+ .get = armada38x_rtc_get,
+ .set = armada38x_rtc_set,
+ .reset = armada38x_rtc_reset,
+};
+
+static const struct udevice_id armada38x_rtc_ids[] = {
+ { .compatible = "marvell,armada-380-rtc", .data = 0 },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_armada38x) = {
+ .name = "rtc-armada38x",
+ .id = UCLASS_RTC,
+ .of_match = armada38x_rtc_ids,
+ .probe = armada38x_probe,
+ .priv_auto = sizeof(struct armada38x_rtc),
+ .ops = &armada38x_rtc_ops,
+};
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c
index f25b976e54d..ba418c25daf 100644
--- a/drivers/rtc/i2c_rtc_emul.c
+++ b/drivers/rtc/i2c_rtc_emul.c
@@ -28,25 +28,6 @@
#define debug_buffer(x, ...)
#endif
-/**
- * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
- *
- * @base_time: Base system time when RTC device was bound
- * @offset: RTC offset from current system time
- * @use_system_time: true to use system time, false to use @base_time
- * @reg: Register values
- */
-struct sandbox_i2c_rtc_plat_data {
- long base_time;
- long offset;
- bool use_system_time;
- u8 reg[REG_COUNT];
-};
-
-struct sandbox_i2c_rtc {
- unsigned int offset_secs;
-};
-
long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
int offset)
{
@@ -223,7 +204,7 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev)
}
static const struct udevice_id sandbox_i2c_rtc_ids[] = {
- { .compatible = "sandbox,i2c-rtc" },
+ { .compatible = "sandbox,i2c-rtc-emul" },
{ }
};
diff --git a/drivers/rtc/rv3028.c b/drivers/rtc/rv3028.c
new file mode 100644
index 00000000000..9f63afc14a8
--- /dev/null
+++ b/drivers/rtc/rv3028.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Micro Crystal RV3028
+ *
+ * based on linux driver from
+ * Copyright (C) 2019 Micro Crystal SA
+ *
+ * Alexandre Belloni <alexandre.belloni@bootlin.com>
+ *
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+
+#define RV3028_SEC 0x00
+#define RV3028_MIN 0x01
+#define RV3028_HOUR 0x02
+#define RV3028_WDAY 0x03
+#define RV3028_DAY 0x04
+#define RV3028_MONTH 0x05
+#define RV3028_YEAR 0x06
+#define RV3028_ALARM_MIN 0x07
+#define RV3028_ALARM_HOUR 0x08
+#define RV3028_ALARM_DAY 0x09
+#define RV3028_STATUS 0x0E
+#define RV3028_CTRL1 0x0F
+#define RV3028_CTRL2 0x10
+#define RV3028_EVT_CTRL 0x13
+#define RV3028_TS_COUNT 0x14
+#define RV3028_TS_SEC 0x15
+#define RV3028_RAM1 0x1F
+#define RV3028_EEPROM_ADDR 0x25
+#define RV3028_EEPROM_DATA 0x26
+#define RV3028_EEPROM_CMD 0x27
+#define RV3028_CLKOUT 0x35
+#define RV3028_OFFSET 0x36
+#define RV3028_BACKUP 0x37
+
+#define RV3028_STATUS_PORF BIT(0)
+#define RV3028_STATUS_EVF BIT(1)
+#define RV3028_STATUS_AF BIT(2)
+#define RV3028_STATUS_TF BIT(3)
+#define RV3028_STATUS_UF BIT(4)
+#define RV3028_STATUS_BSF BIT(5)
+#define RV3028_STATUS_CLKF BIT(6)
+#define RV3028_STATUS_EEBUSY BIT(7)
+
+#define RV3028_CLKOUT_FD_MASK GENMASK(2, 0)
+#define RV3028_CLKOUT_PORIE BIT(3)
+#define RV3028_CLKOUT_CLKSY BIT(6)
+#define RV3028_CLKOUT_CLKOE BIT(7)
+
+#define RV3028_CTRL1_EERD BIT(3)
+#define RV3028_CTRL1_WADA BIT(5)
+
+#define RV3028_CTRL2_RESET BIT(0)
+#define RV3028_CTRL2_12_24 BIT(1)
+#define RV3028_CTRL2_EIE BIT(2)
+#define RV3028_CTRL2_AIE BIT(3)
+#define RV3028_CTRL2_TIE BIT(4)
+#define RV3028_CTRL2_UIE BIT(5)
+#define RV3028_CTRL2_TSE BIT(7)
+
+#define RV3028_EVT_CTRL_TSR BIT(2)
+
+#define RV3028_EEPROM_CMD_UPDATE 0x11
+#define RV3028_EEPROM_CMD_WRITE 0x21
+#define RV3028_EEPROM_CMD_READ 0x22
+
+#define RV3028_EEBUSY_POLL 10000
+#define RV3028_EEBUSY_TIMEOUT 100000
+
+#define RV3028_BACKUP_TCE BIT(5)
+#define RV3028_BACKUP_TCR_MASK GENMASK(1, 0)
+
+#define OFFSET_STEP_PPT 953674
+
+#define RTC_RV3028_LEN 7
+
+static int rv3028_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3028_LEN];
+ u8 status;
+ int ret;
+
+ ret = dm_i2c_read(dev, RV3028_STATUS, &status, 1);
+ if (ret < 0) {
+ printf("%s: error reading RTC status: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ if (status & RV3028_STATUS_PORF) {
+ printf("Voltage low, data is invalid.\n");
+ return -EINVAL;
+ }
+
+ ret = dm_i2c_read(dev, RV3028_SEC, regs, sizeof(regs));
+ if (ret < 0) {
+ printf("%s: error reading RTC: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(regs[RV3028_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(regs[RV3028_MIN] & 0x7f);
+ tm->tm_hour = bcd2bin(regs[RV3028_HOUR] & 0x3f);
+ tm->tm_wday = regs[RV3028_WDAY] & 0x7;
+ tm->tm_mday = bcd2bin(regs[RV3028_DAY] & 0x3f);
+ tm->tm_mon = bcd2bin(regs[RV3028_MONTH] & 0x1f);
+ tm->tm_year = bcd2bin(regs[RV3028_YEAR]) + 2000;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int rv3028_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3028_LEN];
+ u8 status;
+ int ret;
+
+ debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (tm->tm_year < 2000) {
+ printf("%s: year %d (before 2000) not supported\n",
+ __func__, tm->tm_year);
+ return -EINVAL;
+ }
+
+ regs[RV3028_SEC] = bin2bcd(tm->tm_sec);
+ regs[RV3028_MIN] = bin2bcd(tm->tm_min);
+ regs[RV3028_HOUR] = bin2bcd(tm->tm_hour);
+ regs[RV3028_WDAY] = tm->tm_wday;
+ regs[RV3028_DAY] = bin2bcd(tm->tm_mday);
+ regs[RV3028_MONTH] = bin2bcd(tm->tm_mon);
+ regs[RV3028_YEAR] = bin2bcd(tm->tm_year - 2000);
+
+ ret = dm_i2c_write(dev, RV3028_SEC, regs, sizeof(regs));
+ if (ret) {
+ printf("%s: set rtc error: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = dm_i2c_read(dev, RV3028_STATUS, &status, 1);
+ if (ret < 0) {
+ printf("%s: error reading RTC status: %x\n", __func__, ret);
+ return -EIO;
+ }
+ status |= RV3028_STATUS_PORF;
+ return dm_i2c_write(dev, RV3028_STATUS, &status, 1);
+}
+
+static int rv3028_rtc_reset(struct udevice *dev)
+{
+ return 0;
+}
+
+static int rv3028_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ u8 data;
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, &data, sizeof(data));
+ return ret < 0 ? ret : data;
+}
+
+static int rv3028_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 data = val;
+
+ return dm_i2c_write(dev, reg, &data, 1);
+}
+
+static int rv3028_probe(struct udevice *dev)
+{
+ i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+ DM_I2C_CHIP_WR_ADDRESS);
+
+ return 0;
+}
+
+static const struct rtc_ops rv3028_rtc_ops = {
+ .get = rv3028_rtc_get,
+ .set = rv3028_rtc_set,
+ .read8 = rv3028_rtc_read8,
+ .write8 = rv3028_rtc_write8,
+ .reset = rv3028_rtc_reset,
+};
+
+static const struct udevice_id rv3028_rtc_ids[] = {
+ { .compatible = "microcrystal,rv3028" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_rv3028) = {
+ .name = "rtc-rv3028",
+ .id = UCLASS_RTC,
+ .probe = rv3028_probe,
+ .of_match = rv3028_rtc_ids,
+ .ops = &rv3028_rtc_ops,
+};
diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
index d0864b1df97..657e5c7be2c 100644
--- a/drivers/rtc/sandbox_rtc.c
+++ b/drivers/rtc/sandbox_rtc.c
@@ -79,6 +79,18 @@ struct acpi_ops sandbox_rtc_acpi_ops = {
};
#endif
+static int sandbox_rtc_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(PLATDATA)
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+
+ /* Set up the emul_idx for i2c_emul_find() */
+ i2c_emul_set_idx(dev, plat->dtplat.sandbox_emul->idx);
+#endif
+
+ return 0;
+}
+
static const struct rtc_ops sandbox_rtc_ops = {
.get = sandbox_rtc_get,
.set = sandbox_rtc_set,
@@ -97,5 +109,6 @@ U_BOOT_DRIVER(sandbox_rtc) = {
.id = UCLASS_RTC,
.of_match = sandbox_rtc_ids,
.ops = &sandbox_rtc_ops,
+ .bind = sandbox_rtc_bind,
ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 24413d14f9c..af83e9673a9 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -635,7 +635,7 @@ config MCFUART
config MXC_UART
bool "IMX serial port support"
- depends on ARCH_MX25 || ARCH_MX31 || TARGET_APF27 || TARGET_FLEA3 \
+ depends on ARCH_MX25 || ARCH_MX31 || TARGET_FLEA3 \
|| MX5 || MX6 || MX7 || IMX8M
help
If you have a machine based on a Motorola IMX CPU you
diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_coreboot.c
index 88c8209c5db..de09c8681f5 100644
--- a/drivers/serial/serial_coreboot.c
+++ b/drivers/serial/serial_coreboot.c
@@ -9,7 +9,7 @@
#include <dm.h>
#include <ns16550.h>
#include <serial.h>
-#include <asm/arch/sysinfo.h>
+#include <asm/cb_sysinfo.h>
static int coreboot_of_to_plat(struct udevice *dev)
{
diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c
index 6d416021dee..4145d9fdb3d 100644
--- a/drivers/serial/serial_mtk.c
+++ b/drivers/serial/serial_mtk.c
@@ -73,74 +73,64 @@ struct mtk_serial_regs {
struct mtk_serial_priv {
struct mtk_serial_regs __iomem *regs;
u32 clock;
+ bool force_highspeed;
};
static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
{
- bool support_clk12m_baud115200;
- u32 quot, samplecount, realbaud;
+ u32 quot, realbaud, samplecount = 1;
- if ((baud <= 115200) && (priv->clock == 12000000))
- support_clk12m_baud115200 = true;
- else
- support_clk12m_baud115200 = false;
+ /* Special case for low baud clock */
+ if (baud <= 115200 && priv->clock <= 12000000) {
+ writel(3, &priv->regs->highspeed);
+
+ quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
+ if (quot == 0)
+ quot = 1;
+
+ samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+
+ realbaud = priv->clock / samplecount / quot;
+ if (realbaud > BAUD_ALLOW_MAX(baud) ||
+ realbaud < BAUD_ALLOW_MIX(baud)) {
+ pr_info("baud %d can't be handled\n", baud);
+ }
+
+ goto set_baud;
+ }
+
+ if (priv->force_highspeed)
+ goto use_hs3;
if (baud <= 115200) {
writel(0, &priv->regs->highspeed);
quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
-
- if (support_clk12m_baud115200) {
- writel(3, &priv->regs->highspeed);
- quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
- if (quot == 0)
- quot = 1;
-
- samplecount = DIV_ROUND_CLOSEST(priv->clock,
- quot * baud);
- if (samplecount != 0) {
- realbaud = priv->clock / samplecount / quot;
- if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
- (realbaud < BAUD_ALLOW_MIX(baud))) {
- pr_info("baud %d can't be handled\n",
- baud);
- }
- } else {
- pr_info("samplecount is 0\n");
- }
- }
} else if (baud <= 576000) {
writel(2, &priv->regs->highspeed);
/* Set to next lower baudrate supported */
if ((baud == 500000) || (baud == 576000))
baud = 460800;
+
quot = DIV_ROUND_UP(priv->clock, 4 * baud);
} else {
+use_hs3:
writel(3, &priv->regs->highspeed);
+
quot = DIV_ROUND_UP(priv->clock, 256 * baud);
+ samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
}
+set_baud:
/* set divisor */
writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
writel(quot & 0xff, &priv->regs->dll);
writel((quot >> 8) & 0xff, &priv->regs->dlm);
writel(UART_LCR_WLS_8, &priv->regs->lcr);
- if (baud > 460800) {
- u32 tmp;
-
- tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
- writel(tmp - 1, &priv->regs->sample_count);
- writel((tmp - 2) >> 1, &priv->regs->sample_point);
- } else {
- writel(0, &priv->regs->sample_count);
- writel(0xff, &priv->regs->sample_point);
- }
-
- if (support_clk12m_baud115200) {
- writel(samplecount - 1, &priv->regs->sample_count);
- writel((samplecount - 2) >> 1, &priv->regs->sample_point);
- }
+ /* set highspeed mode sample count & point */
+ writel(samplecount - 1, &priv->regs->sample_count);
+ writel((samplecount - 2) >> 1, &priv->regs->sample_point);
}
static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch)
@@ -248,6 +238,8 @@ static int mtk_serial_of_to_plat(struct udevice *dev)
return -EINVAL;
}
+ priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed");
+
return 0;
}
diff --git a/drivers/sound/tegra_i2s.c b/drivers/sound/tegra_i2s.c
index 5cf82250da2..932f737900e 100644
--- a/drivers/sound/tegra_i2s.c
+++ b/drivers/sound/tegra_i2s.c
@@ -4,7 +4,6 @@
* Written by Simon Glass <sjg@chromium.org>
*/
#define LOG_CATEGORY UCLASS_I2S
-#define LOG_DEBUG
#include <common.h>
#include <dm.h>
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 7155d4aebd6..ee30110b565 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -11,6 +11,7 @@
#include <log.h>
#include <malloc.h>
#include <spi.h>
+#include <spi-mem.h>
#include <dm/device_compat.h>
#include <asm/global_data.h>
#include <dm/device-internal.h>
@@ -199,6 +200,16 @@ static int spi_post_probe(struct udevice *bus)
ops->set_mode += gd->reloc_off;
if (ops->cs_info)
ops->cs_info += gd->reloc_off;
+ if (ops->mem_ops) {
+ struct spi_controller_mem_ops *mem_ops =
+ (struct spi_controller_mem_ops *)ops->mem_ops;
+ if (mem_ops->adjust_op_size)
+ mem_ops->adjust_op_size += gd->reloc_off;
+ if (mem_ops->supports_op)
+ mem_ops->supports_op += gd->reloc_off;
+ if (mem_ops->exec_op)
+ mem_ops->exec_op += gd->reloc_off;
+ }
reloc_done++;
}
#endif
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 0274afdc6e0..b892cdae9ba 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -314,8 +314,7 @@ static int xilinx_spi_set_speed(struct udevice *bus, uint speed)
priv->freq = speed;
- debug("xilinx_spi_set_speed: regs=%p, speed=%d\n", priv->regs,
- priv->freq);
+ debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
return 0;
}
@@ -324,7 +323,7 @@ static int xilinx_spi_set_mode(struct udevice *bus, uint mode)
{
struct xilinx_spi_priv *priv = dev_get_priv(bus);
struct xilinx_spi_regs *regs = priv->regs;
- uint32_t spicr;
+ u32 spicr;
spicr = readl(&regs->spicr);
if (mode & SPI_LSB_FIRST)
@@ -339,8 +338,7 @@ static int xilinx_spi_set_mode(struct udevice *bus, uint mode)
writel(spicr, &regs->spicr);
priv->mode = mode;
- debug("xilinx_spi_set_mode: regs=%p, mode=%d\n", priv->regs,
- priv->mode);
+ debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
return 0;
}
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c
index 6c9dc7a3845..9512f6881fc 100644
--- a/drivers/sysreset/sysreset-uclass.c
+++ b/drivers/sysreset/sysreset-uclass.c
@@ -113,7 +113,7 @@ void sysreset_walk_halt(enum sysreset_t type)
/**
* reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
*/
-void reset_cpu(ulong addr)
+void reset_cpu(void)
{
sysreset_walk_halt(SYSRESET_WARM);
}
diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
index 65622f30b1e..d03028070b9 100644
--- a/drivers/tee/optee/Kconfig
+++ b/drivers/tee/optee/Kconfig
@@ -31,6 +31,12 @@ config OPTEE_TA_RPC_TEST
permits to test reverse RPC calls to TEE supplicant. Should
be used only in sandbox env.
+config OPTEE_TA_SCP03
+ bool "Support SCP03 TA"
+ default y
+ help
+ Enables support for controlling (enabling, provisioning) the
+ Secure Channel Protocol 03 operation in the OP-TEE SCP03 TA.
endmenu
endif
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index b898c32edc0..73dbb22ba09 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -624,14 +624,14 @@ static int optee_probe(struct udevice *dev)
u32 sec_caps;
if (!is_optee_api(pdata->invoke_fn)) {
- debug("%s: OP-TEE api uid mismatch\n", __func__);
+ dev_err(dev, "OP-TEE api uid mismatch\n");
return -ENOENT;
}
print_os_revision(dev, pdata->invoke_fn);
if (!api_revision_is_compatible(pdata->invoke_fn)) {
- debug("%s: OP-TEE api revision mismatch\n", __func__);
+ dev_err(dev, "OP-TEE api revision mismatch\n");
return -ENOENT;
}
@@ -642,7 +642,7 @@ static int optee_probe(struct udevice *dev)
*/
if (!exchange_capabilities(pdata->invoke_fn, &sec_caps) ||
!(sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)) {
- debug("%s: OP-TEE capabilities mismatch\n", __func__);
+ dev_err(dev, "OP-TEE capabilities mismatch\n");
return -ENOENT;
}
diff --git a/drivers/tee/sandbox.c b/drivers/tee/sandbox.c
index 3a1d34d6fc0..35e8542fa37 100644
--- a/drivers/tee/sandbox.c
+++ b/drivers/tee/sandbox.c
@@ -8,6 +8,7 @@
#include <tee.h>
#include <tee/optee_ta_avb.h>
#include <tee/optee_ta_rpc_test.h>
+#include <tee/optee_ta_scp03.h>
#include "optee/optee_msg.h"
#include "optee/optee_private.h"
@@ -68,6 +69,7 @@ void *optee_alloc_and_init_page_list(void *buf, ulong len,
return NULL;
}
+#if defined(CONFIG_OPTEE_TA_SCP03) || defined(CONFIG_OPTEE_TA_AVB)
static u32 get_attr(uint n, uint num_params, struct tee_param *params)
{
if (n >= num_params)
@@ -79,7 +81,7 @@ static u32 get_attr(uint n, uint num_params, struct tee_param *params)
static u32 check_params(u8 p0, u8 p1, u8 p2, u8 p3, uint num_params,
struct tee_param *params)
{
- u8 p[] = { p0, p1, p2, p3};
+ u8 p[] = { p0, p1, p2, p3 };
uint n;
for (n = 0; n < ARRAY_SIZE(p); n++)
@@ -97,6 +99,50 @@ bad_params:
return TEE_ERROR_BAD_PARAMETERS;
}
+#endif
+
+#ifdef CONFIG_OPTEE_TA_SCP03
+static u32 pta_scp03_open_session(struct udevice *dev, uint num_params,
+ struct tee_param *params)
+{
+ /*
+ * We don't expect additional parameters when opening a session to
+ * this TA.
+ */
+ return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
+ TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
+ num_params, params);
+}
+
+static u32 pta_scp03_invoke_func(struct udevice *dev, u32 func, uint num_params,
+ struct tee_param *params)
+{
+ u32 res;
+ static bool enabled;
+
+ switch (func) {
+ case PTA_CMD_ENABLE_SCP03:
+ res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_PARAM_ATTR_TYPE_NONE,
+ TEE_PARAM_ATTR_TYPE_NONE,
+ TEE_PARAM_ATTR_TYPE_NONE,
+ num_params, params);
+ if (res)
+ return res;
+
+ if (!enabled) {
+ enabled = true;
+ } else {
+ }
+
+ if (params[0].u.value.a)
+
+ return TEE_SUCCESS;
+ default:
+ return TEE_ERROR_NOT_SUPPORTED;
+ }
+}
+#endif
#ifdef CONFIG_OPTEE_TA_AVB
static u32 ta_avb_open_session(struct udevice *dev, uint num_params,
@@ -357,6 +403,12 @@ static const struct ta_entry ta_entries[] = {
.invoke_func = ta_rpc_test_invoke_func,
},
#endif
+#ifdef CONFIG_OPTEE_TA_SCP03
+ { .uuid = PTA_SCP03_UUID,
+ .open_session = pta_scp03_open_session,
+ .invoke_func = pta_scp03_invoke_func,
+ },
+#endif
};
static void sandbox_tee_get_version(struct udevice *dev,
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index 2075cd4edda..c846bfb9f12 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -38,7 +38,8 @@ static int sandbox_timer_probe(struct udevice *dev)
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- if (dev_read_bool(dev, "sandbox,timebase-frequency-fallback"))
+ if (CONFIG_IS_ENABLED(CPU) &&
+ dev_read_bool(dev, "sandbox,timebase-frequency-fallback"))
return timer_timebase_fallback(dev);
else if (!uc_priv->clock_rate)
uc_priv->clock_rate = SANDBOX_TIMER_RATE;
diff --git a/drivers/timer/sifive_clint_timer.c b/drivers/timer/sifive_clint_timer.c
index de7b4b95c9e..939b99d937d 100644
--- a/drivers/timer/sifive_clint_timer.c
+++ b/drivers/timer/sifive_clint_timer.c
@@ -54,6 +54,7 @@ static int sifive_clint_probe(struct udevice *dev)
static const struct udevice_id sifive_clint_ids[] = {
{ .compatible = "riscv,clint0" },
+ { .compatible = "sifive,clint0" },
{ }
};
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 6f00a5d0dba..73b4a5cd27f 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -83,11 +83,7 @@ static int timer_post_probe(struct udevice *dev)
return 0;
}
-/*
- * TODO: should be CONFIG_IS_ENABLED(CPU), but the SPL config has _SUPPORT on
- * the end...
- */
-#if defined(CONFIG_CPU) || defined(CONFIG_SPL_CPU_SUPPORT)
+#if CONFIG_IS_ENABLED(CPU)
int timer_timebase_fallback(struct udevice *dev)
{
struct udevice *cpu;
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 8f075b9f45f..f64d20067f8 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o
obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
-obj-$(CONFIG_TPM2_CR50_I2C) += cr50_i2c.o
+obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o
obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o
obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o
obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index b103a6fdc39..76432bdec1f 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -309,7 +309,7 @@ static int cr50_i2c_recv(struct udevice *dev, u8 *buf, size_t buf_len)
int status;
int ret;
- log_debug("%s: len=%x\n", __func__, buf_len);
+ log_debug("%s: buf_len=%x\n", __func__, buf_len);
if (buf_len < TPM_HEADER_SIZE)
return -E2BIG;
@@ -386,7 +386,7 @@ static int cr50_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
ulong timeout;
int ret;
- log_debug("%s: len=%x\n", __func__, len);
+ log_debug("len=%x\n", len);
timeout = timer_get_us() + TIMEOUT_LONG_US;
do {
ret = cr50_i2c_status(dev);
diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
index beb0fa3f93c..35774a6289e 100644
--- a/drivers/tpm/tpm-uclass.c
+++ b/drivers/tpm/tpm-uclass.c
@@ -4,6 +4,8 @@
* Written by Simon Glass <sjg@chromium.org>
*/
+#define LOG_CATEGORY UCLASS_TPM
+
#include <common.h>
#include <dm.h>
#include <log.h>
@@ -87,15 +89,15 @@ int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
ordinal = get_unaligned_be32(sendbuf + TPM_CMD_ORDINAL_BYTE);
if (count == 0) {
- debug("no data\n");
+ log_debug("no data\n");
return -ENODATA;
}
if (count > send_size) {
- debug("invalid count value %x %zx\n", count, send_size);
+ log_debug("invalid count value %x %zx\n", count, send_size);
return -E2BIG;
}
- debug("%s: Calling send\n", __func__);
+ log_debug("%s: Calling send\n", __func__);
ret = ops->send(dev, sendbuf, send_size);
if (ret < 0)
return ret;
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index c74bacfd719..24c804a5645 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -285,7 +285,7 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
length = get_unaligned_be32(sent);
sent += sizeof(length);
if (length != send_size) {
- printf("TPM2: Unmatching length, received: %ld, expected: %d\n",
+ printf("TPM2: Unmatching length, received: %zd, expected: %d\n",
send_size, length);
rc = TPM2_RC_SIZE;
sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h
index 82793765bea..3bb0bda5a6b 100644
--- a/drivers/usb/dwc3/linux-compat.h
+++ b/drivers/usb/dwc3/linux-compat.h
@@ -13,10 +13,4 @@
#define dev_WARN(dev, format, arg...) debug(format, ##arg)
-static inline size_t strlcat(char *dest, const char *src, size_t n)
-{
- strcat(dest, src);
- return strlen(dest) + strlen(src);
-}
-
#endif
diff --git a/drivers/usb/gadget/udc/udc-uclass.c b/drivers/usb/gadget/udc/udc-uclass.c
index 3053ccf7d97..dbc354e84f9 100644
--- a/drivers/usb/gadget/udc/udc-uclass.c
+++ b/drivers/usb/gadget/udc/udc-uclass.c
@@ -45,7 +45,7 @@ int usb_gadget_release(int index)
dev_array[index] = NULL;
return ret;
#else
- return -ENOTSUPP;
+ return -ENOSYS;
#endif
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 83147d51b5c..1c11c2e7e04 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -434,9 +434,9 @@ static struct xhci_container_ctx
BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
ctx->type = type;
ctx->size = (MAX_EP_CTX_NUM + 1) *
- CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
+ CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams));
if (type == XHCI_CTX_TYPE_INPUT)
- ctx->size += CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
+ ctx->size += CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams));
ctx->bytes = xhci_malloc(ctx->size);
@@ -636,7 +636,7 @@ struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctrl *ctrl,
return (struct xhci_slot_ctx *)ctx->bytes;
return (struct xhci_slot_ctx *)
- (ctx->bytes + CTX_SIZE(readl(&ctrl->hccr->cr_hccparams)));
+ (ctx->bytes + CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams)));
}
/**
@@ -658,7 +658,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctrl *ctrl,
return (struct xhci_ep_ctx *)
(ctx->bytes +
- (ep_index * CTX_SIZE(readl(&ctrl->hccr->cr_hccparams))));
+ (ep_index * CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams))));
}
/**
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 46c137f8578..35bd5cd29e1 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -849,12 +849,9 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
}
}
- debug("req->requesttype = %d, req->request = %d,"
- "le16_to_cpu(req->value) = %d,"
- "le16_to_cpu(req->index) = %d,"
- "le16_to_cpu(req->length) = %d\n",
- req->requesttype, req->request, le16_to_cpu(req->value),
- le16_to_cpu(req->index), le16_to_cpu(req->length));
+ debug("req->requesttype = %d, req->request = %d, req->value = %d, req->index = %d, req->length = %d\n",
+ req->requesttype, req->request, le16_to_cpu(req->value),
+ le16_to_cpu(req->index), le16_to_cpu(req->length));
trb_fields[0] = req->requesttype | req->request << 8 |
le16_to_cpu(req->value) << 16;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 667157c2e97..b69ffcae4b2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -209,7 +209,7 @@ config PANEL
config SIMPLE_PANEL
bool "Enable simple panel support"
- depends on PANEL && BACKLIGHT
+ depends on PANEL && BACKLIGHT && DM_GPIO
default y
help
This turns on a simple panel driver that enables a compatible
@@ -241,7 +241,7 @@ config VIDCONSOLE_AS_NAME
config VIDEO_COREBOOT
bool "Enable coreboot framebuffer driver support"
- depends on X86 && SYS_COREBOOT
+ depends on X86
help
Turn on this option to enable a framebuffer driver when U-Boot is
loaded by coreboot where the graphics device is configured by
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 27ff7163f34..1f491a48d6a 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -82,20 +82,6 @@
#endif
/*
- * Defines for the MB862xx driver
- */
-#ifdef CONFIG_VIDEO_MB862xx
-
-#ifdef CONFIG_VIDEO_CORALP
-#define VIDEO_FB_LITTLE_ENDIAN
-#endif
-#ifdef CONFIG_VIDEO_MB862xx_ACCEL
-#define VIDEO_HW_RECTFILL
-#define VIDEO_HW_BITBLT
-#endif
-#endif
-
-/*
* Defines for the i.MX31 driver (mx3fb.c)
*/
#if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3)
diff --git a/drivers/video/coreboot.c b/drivers/video/coreboot.c
index 0a5fb08dc8a..7237542c076 100644
--- a/drivers/video/coreboot.c
+++ b/drivers/video/coreboot.c
@@ -5,9 +5,10 @@
#include <common.h>
#include <dm.h>
+#include <init.h>
#include <vbe.h>
#include <video.h>
-#include <asm/arch/sysinfo.h>
+#include <asm/cb_sysinfo.h>
static int save_vesa_mode(struct cb_framebuffer *fb,
struct vesa_mode_info *vesa)
@@ -17,7 +18,7 @@ static int save_vesa_mode(struct cb_framebuffer *fb,
* running on the serial console.
*/
if (!fb)
- return -ENXIO;
+ return log_msg_ret("save", -ENXIO);
vesa->x_resolution = fb->x_resolution;
vesa->y_resolution = fb->y_resolution;
@@ -44,16 +45,23 @@ static int coreboot_video_probe(struct udevice *dev)
struct vesa_mode_info *vesa = &mode_info.vesa;
int ret;
+ if (ll_boot_init())
+ return log_msg_ret("ll", -ENODEV);
+
printf("Video: ");
/* Initialize vesa_mode_info structure */
ret = save_vesa_mode(fb, vesa);
- if (ret)
+ if (ret) {
+ ret = log_msg_ret("save", ret);
goto err;
+ }
ret = vbe_setup_video_priv(vesa, uc_priv, plat);
- if (ret)
+ if (ret) {
+ ret = log_msg_ret("setup", ret);
goto err;
+ }
printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
vesa->bits_per_pixel);
@@ -61,7 +69,7 @@ static int coreboot_video_probe(struct udevice *dev)
return 0;
err:
- printf("No video mode configured in coreboot!\n");
+ printf("No video mode configured in coreboot (err=%d)\n", ret);
return ret;
}
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index 9e32bc47cff..4c86215bd73 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -62,10 +62,17 @@ static int set_pwm(struct pwm_backlight_priv *priv)
uint duty_cycle;
int ret;
- duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
- (priv->max_level - priv->min_level);
- ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
- duty_cycle);
+ if (priv->period_ns) {
+ duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
+ (priv->max_level - priv->min_level);
+ ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
+ duty_cycle);
+ } else {
+ /* PWM driver will internally scale these like the above. */
+ ret = pwm_set_config(priv->pwm, priv->channel,
+ priv->max_level - priv->min_level,
+ priv->cur_level - priv->min_level);
+ }
if (ret)
return log_ret(ret);
@@ -213,10 +220,11 @@ static int pwm_backlight_of_to_plat(struct udevice *dev)
log_debug("Cannot get PWM: ret=%d\n", ret);
return log_ret(ret);
}
- if (args.args_count < 2)
+ if (args.args_count < 1)
return log_msg_ret("Not enough arguments to pwm\n", -EINVAL);
priv->channel = args.args[0];
- priv->period_ns = args.args[1];
+ if (args.args_count > 1)
+ priv->period_ns = args.args[1];
if (args.args_count > 2)
priv->polarity = args.args[2];
diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c
index 0be60e169e3..0ddf5e02d69 100644
--- a/drivers/video/rockchip/rk_edp.c
+++ b/drivers/video/rockchip/rk_edp.c
@@ -8,20 +8,21 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <edid.h>
#include <log.h>
#include <malloc.h>
#include <panel.h>
#include <regmap.h>
+#include <reset.h>
#include <syscon.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/edp_rk3288.h>
#include <asm/arch-rockchip/grf_rk3288.h>
-#include <asm/arch-rockchip/hardware.h>
-#include <dt-bindings/clock/rk3288-cru.h>
-#include <linux/delay.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
#define MAX_CR_LOOP 5
#define MAX_EQ_LOOP 5
@@ -37,18 +38,42 @@ static const char * const pre_emph_names[] = {
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5
+#define RK3288_GRF_SOC_CON6 0x025c
+#define RK3288_GRF_SOC_CON12 0x0274
+#define RK3399_GRF_SOC_CON20 0x6250
+#define RK3399_GRF_SOC_CON25 0x6264
+
+enum rockchip_dp_types {
+ RK3288_DP = 0,
+ RK3399_EDP
+};
+
+struct rockchip_dp_data {
+ unsigned long reg_vop_big_little;
+ unsigned long reg_vop_big_little_sel;
+ unsigned long reg_ref_clk_sel;
+ unsigned long ref_clk_sel_bit;
+ enum rockchip_dp_types chip_type;
+};
+
struct rk_edp_priv {
struct rk3288_edp *regs;
- struct rk3288_grf *grf;
+ void *grf;
struct udevice *panel;
struct link_train link_train;
u8 train_set[4];
};
-static void rk_edp_init_refclk(struct rk3288_edp *regs)
+static void rk_edp_init_refclk(struct rk3288_edp *regs, enum rockchip_dp_types chip_type)
{
writel(SEL_24M, &regs->analog_ctl_2);
- writel(REF_CLK_24M, &regs->pll_reg_1);
+ u32 reg;
+
+ reg = REF_CLK_24M;
+ if (chip_type == RK3288_DP)
+ reg ^= REF_CLK_MASK;
+ writel(reg, &regs->pll_reg_1);
+
writel(LDO_OUTPUT_V_SEL_145 | KVCO_DEFALUT | CHG_PUMP_CUR_SEL_5US |
V2L_CUR_SEL_1MA, &regs->pll_reg_2);
@@ -1029,6 +1054,9 @@ static int rk_edp_probe(struct udevice *dev)
struct display_plat *uc_plat = dev_get_uclass_plat(dev);
struct rk_edp_priv *priv = dev_get_priv(dev);
struct rk3288_edp *regs = priv->regs;
+ struct rockchip_dp_data *edp_data = (struct rockchip_dp_data *)dev_get_driver_data(dev);
+ struct reset_ctl dp_rst;
+
struct clk clk;
int ret;
@@ -1040,19 +1068,39 @@ static int rk_edp_probe(struct udevice *dev)
return ret;
}
- int vop_id = uc_plat->source_id;
- debug("%s, uc_plat=%p, vop_id=%u\n", __func__, uc_plat, vop_id);
+ ret = reset_get_by_name(dev, "dp", &dp_rst);
+ if (ret) {
+ dev_err(dev, "failed to get dp reset (ret=%d)\n", ret);
+ return ret;
+ }
- ret = clk_get_by_index(dev, 1, &clk);
- if (ret >= 0) {
- ret = clk_set_rate(&clk, 0);
- clk_free(&clk);
+ ret = reset_assert(&dp_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert dp reset (ret=%d)\n", ret);
+ return ret;
}
+ udelay(20);
+
+ ret = reset_deassert(&dp_rst);
if (ret) {
- debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
+ dev_err(dev, "failed to deassert dp reset (ret=%d)\n", ret);
return ret;
}
+ int vop_id = uc_plat->source_id;
+ debug("%s, uc_plat=%p, vop_id=%u\n", __func__, uc_plat, vop_id);
+
+ if (edp_data->chip_type == RK3288_DP) {
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret >= 0) {
+ ret = clk_set_rate(&clk, 0);
+ clk_free(&clk);
+ }
+ if (ret) {
+ debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
+ return ret;
+ }
+ }
ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
if (ret >= 0) {
ret = clk_set_rate(&clk, 192000000);
@@ -1065,15 +1113,17 @@ static int rk_edp_probe(struct udevice *dev)
}
/* grf_edp_ref_clk_sel: from internal 24MHz or 27MHz clock */
- rk_setreg(&priv->grf->soc_con12, 1 << 4);
+ rk_setreg(priv->grf + edp_data->reg_ref_clk_sel,
+ edp_data->ref_clk_sel_bit);
/* select epd signal from vop0 or vop1 */
- rk_clrsetreg(&priv->grf->soc_con6, (1 << 5),
- (vop_id == 1) ? (1 << 5) : (0 << 5));
+ rk_clrsetreg(priv->grf + edp_data->reg_vop_big_little,
+ edp_data->reg_vop_big_little_sel,
+ (vop_id == 1) ? edp_data->reg_vop_big_little_sel : 0);
rockchip_edp_wait_hpd(priv);
- rk_edp_init_refclk(regs);
+ rk_edp_init_refclk(regs, edp_data->chip_type);
rk_edp_init_interrupt(regs);
rk_edp_enable_sw_function(regs);
ret = rk_edp_init_analog_func(regs);
@@ -1089,8 +1139,25 @@ static const struct dm_display_ops dp_rockchip_ops = {
.enable = rk_edp_enable,
};
+static const struct rockchip_dp_data rk3399_edp = {
+ .reg_vop_big_little = RK3399_GRF_SOC_CON20,
+ .reg_vop_big_little_sel = BIT(5),
+ .reg_ref_clk_sel = RK3399_GRF_SOC_CON25,
+ .ref_clk_sel_bit = BIT(11),
+ .chip_type = RK3399_EDP,
+};
+
+static const struct rockchip_dp_data rk3288_dp = {
+ .reg_vop_big_little = RK3288_GRF_SOC_CON6,
+ .reg_vop_big_little_sel = BIT(5),
+ .reg_ref_clk_sel = RK3288_GRF_SOC_CON12,
+ .ref_clk_sel_bit = BIT(4),
+ .chip_type = RK3288_DP,
+};
+
static const struct udevice_id rockchip_dp_ids[] = {
- { .compatible = "rockchip,rk3288-edp" },
+ { .compatible = "rockchip,rk3288-edp", .data = (ulong)&rk3288_dp },
+ { .compatible = "rockchip,rk3399-edp", .data = (ulong)&rk3399_edp },
{ }
};
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index 145c3330203..fe0574870f9 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -8,9 +8,11 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <edid.h>
#include <log.h>
#include <regmap.h>
+#include <reset.h>
#include <syscon.h>
#include <video.h>
#include <asm/global_data.h>
@@ -21,6 +23,8 @@
#include <asm/arch-rockchip/vop_rk3288.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+#include <efi.h>
+#include <efi_loader.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <power/regulator.h>
@@ -35,14 +39,16 @@ enum vop_pol {
DCLK_INVERT = 3
};
-static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
+static void rkvop_enable(struct udevice *dev, struct rk3288_vop *regs, ulong fbbase,
int fb_bits_per_pixel,
- const struct display_timing *edid)
+ const struct display_timing *edid,
+ struct reset_ctl *dclk_rst)
{
u32 lb_mode;
u32 rgb_mode;
u32 hactive = edid->hactive.typ;
u32 vactive = edid->vactive.typ;
+ int ret;
writel(V_ACT_WIDTH(hactive - 1) | V_ACT_HEIGHT(vactive - 1),
&regs->win0_act_info);
@@ -90,6 +96,18 @@ static void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
writel(fbbase, &regs->win0_yrgb_mst);
writel(0x01, &regs->reg_cfg_done); /* enable reg config */
+
+ ret = reset_assert(dclk_rst);
+ if (ret) {
+ dev_warn(dev, "failed to assert dclk reset (ret=%d)\n", ret);
+ return;
+ }
+ udelay(20);
+
+ ret = reset_deassert(dclk_rst);
+ if (ret)
+ dev_warn(dev, "failed to deassert dclk reset (ret=%d)\n", ret);
+
}
static void rkvop_set_pin_polarity(struct udevice *dev,
@@ -236,12 +254,12 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
struct clk clk;
enum video_log2_bpp l2bpp;
ofnode remote;
+ const char *compat;
+ struct reset_ctl dclk_rst;
- debug("%s(%s, %lu, %s)\n", __func__,
+ debug("%s(%s, 0x%lx, %s)\n", __func__,
dev_read_name(dev), fbbase, ofnode_get_name(ep_node));
- vop_id = ofnode_read_s32_default(ep_node, "reg", -1);
- debug("vop_id=%d\n", vop_id);
ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle);
if (ret)
return ret;
@@ -283,6 +301,28 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
if (disp)
break;
};
+ compat = ofnode_get_property(remote, "compatible", NULL);
+ if (!compat) {
+ debug("%s(%s): Failed to find compatible property\n",
+ __func__, dev_read_name(dev));
+ return -EINVAL;
+ }
+ if (strstr(compat, "edp")) {
+ vop_id = VOP_MODE_EDP;
+ } else if (strstr(compat, "mipi")) {
+ vop_id = VOP_MODE_MIPI;
+ } else if (strstr(compat, "hdmi")) {
+ vop_id = VOP_MODE_HDMI;
+ } else if (strstr(compat, "cdn-dp")) {
+ vop_id = VOP_MODE_DP;
+ } else if (strstr(compat, "lvds")) {
+ vop_id = VOP_MODE_LVDS;
+ } else {
+ debug("%s(%s): Failed to find vop mode for %s\n",
+ __func__, dev_read_name(dev), compat);
+ return -EINVAL;
+ }
+ debug("vop_id=%d\n", vop_id);
disp_uc_plat = dev_get_uclass_plat(disp);
debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
@@ -332,7 +372,14 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
}
rkvop_mode_set(dev, &timing, vop_id);
- rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);
+
+ ret = reset_get_by_name(dev, "dclk", &dclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to get dclk reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ rkvop_enable(dev, regs, fbbase, 1 << l2bpp, &timing, &dclk_rst);
ret = display_enable(disp, 1 << l2bpp, &timing);
if (ret)
@@ -369,11 +416,36 @@ int rk_vop_probe(struct udevice *dev)
struct rk_vop_priv *priv = dev_get_priv(dev);
int ret = 0;
ofnode port, node;
+ struct reset_ctl ahb_rst;
/* Before relocation we don't need to do anything */
if (!(gd->flags & GD_FLG_RELOC))
return 0;
+ ret = reset_get_by_name(dev, "ahb", &ahb_rst);
+ if (ret) {
+ dev_err(dev, "failed to get ahb reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&ahb_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert ahb reset (ret=%d)\n", ret);
+ return ret;
+ }
+ udelay(20);
+
+ ret = reset_deassert(&ahb_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert ahb reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+#if defined(CONFIG_EFI_LOADER)
+ debug("Adding to EFI map %d @ %lx\n", plat->size, plat->base);
+ efi_add_memory_map(plat->base, plat->size, EFI_RESERVED_MEMORY_TYPE);
+#endif
+
priv->regs = (struct rk3288_vop *)dev_read_addr(dev);
/*
diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile
index 147e1879922..4321673312b 100644
--- a/drivers/video/sunxi/Makefile
+++ b/drivers/video/sunxi/Makefile
@@ -4,4 +4,4 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o
-obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o
+obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index f52aba4d21c..4361a58cd7e 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -7,6 +7,8 @@
*/
#include <common.h>
+#include <display.h>
+#include <dm.h>
#include <cpu_func.h>
#include <efi_loader.h>
#include <init.h>
@@ -28,7 +30,9 @@
#include <fdt_support.h>
#include <i2c.h>
#include <malloc.h>
+#include <video.h>
#include <video_fb.h>
+#include <dm/uclass-internal.h>
#include "../videomodes.h"
#include "../anx9804.h"
#include "../hitachi_tx18d42vm_lcd.h"
@@ -45,6 +49,11 @@
DECLARE_GLOBAL_DATA_PTR;
+/* Maximum LCD size we support */
+#define LCD_MAX_WIDTH 3840
+#define LCD_MAX_HEIGHT 2160
+#define LCD_MAX_LOG2_BPP VIDEO_BPP32
+
enum sunxi_monitor {
sunxi_monitor_none,
sunxi_monitor_dvi,
@@ -58,13 +67,12 @@ enum sunxi_monitor {
};
#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
-struct sunxi_display {
- GraphicDevice graphic_device;
+struct sunxi_display_priv {
enum sunxi_monitor monitor;
unsigned int depth;
unsigned int fb_addr;
unsigned int fb_size;
-} sunxi_display;
+};
const struct ctfb_res_modes composite_video_modes[2] = {
/* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
@@ -214,7 +222,8 @@ static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
return r;
}
-static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
+static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
+ struct ctfb_res_modes *mode,
bool verbose_mode)
{
struct edid1_info edid1;
@@ -291,14 +300,14 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
}
/* Check for basic audio support, if found enable hdmi output */
- sunxi_display.monitor = sunxi_monitor_dvi;
+ sunxi_display->monitor = sunxi_monitor_dvi;
for (i = 0; i < ext_blocks; i++) {
if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
cea681[i].revision < 2)
continue;
if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
- sunxi_display.monitor = sunxi_monitor_hdmi;
+ sunxi_display->monitor = sunxi_monitor_hdmi;
}
return 0;
@@ -414,9 +423,9 @@ static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
static void sunxi_frontend_enable(void) {}
#endif
-static bool sunxi_is_composite(void)
+static bool sunxi_is_composite(enum sunxi_monitor monitor)
{
- switch (sunxi_display.monitor) {
+ switch (monitor) {
case sunxi_monitor_none:
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
@@ -473,7 +482,8 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
};
static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
- unsigned int address)
+ unsigned int address,
+ enum sunxi_monitor monitor)
{
struct sunxi_de_be_reg * const de_be =
(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
@@ -502,7 +512,7 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
#endif
SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
- if (sunxi_is_composite()) {
+ if (sunxi_is_composite(monitor)) {
writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
&de_be->output_color_ctrl);
for (i = 0; i < 12; i++)
@@ -616,7 +626,8 @@ static void sunxi_lcdc_backlight_enable(void)
gpio_direction_output(pin, PWM_ON);
}
-static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
+ const struct ctfb_res_modes *mode,
bool for_ext_vga_dac)
{
struct sunxi_lcdc_reg * const lcdc =
@@ -643,17 +654,18 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
}
lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
- sunxi_is_composite());
+ sunxi_is_composite(sunxi_display->monitor));
video_ctfb_mode_to_display_timing(mode, &timing);
lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
- sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
+ sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
}
#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
int *clk_div, int *clk_double,
- bool use_portd_hvsync)
+ bool use_portd_hvsync,
+ enum sunxi_monitor monitor)
{
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
@@ -663,7 +675,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
video_ctfb_mode_to_display_timing(mode, &timing);
lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
- sunxi_is_composite());
+ sunxi_is_composite(monitor));
if (use_portd_hvsync) {
sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
@@ -671,7 +683,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
}
lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
- sunxi_is_composite());
+ sunxi_is_composite(monitor));
}
#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
@@ -725,7 +737,8 @@ static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
}
static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
- int clk_div, int clk_double)
+ int clk_div, int clk_double,
+ enum sunxi_monitor monitor)
{
struct sunxi_hdmi_reg * const hdmi =
(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
@@ -734,7 +747,7 @@ static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
/* Write clear interrupt status bits */
writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
- if (sunxi_display.monitor == sunxi_monitor_hdmi)
+ if (monitor == sunxi_monitor_hdmi)
sunxi_hdmi_setup_info_frames(mode);
/* Set input sync enable */
@@ -789,7 +802,7 @@ static void sunxi_hdmi_enable(void)
#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
-static void sunxi_tvencoder_mode_set(void)
+static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -801,7 +814,7 @@ static void sunxi_tvencoder_mode_set(void)
/* Clock on */
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
- switch (sunxi_display.monitor) {
+ switch (monitor) {
case sunxi_monitor_vga:
tvencoder_mode_set(tve, tve_mode_vga);
break;
@@ -896,26 +909,28 @@ static void sunxi_engines_init(void)
sunxi_drc_init();
}
-static void sunxi_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
+ const struct ctfb_res_modes *mode,
unsigned int address)
{
+ enum sunxi_monitor monitor = sunxi_display->monitor;
int __maybe_unused clk_div, clk_double;
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
struct sunxi_tve_reg * __maybe_unused const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- switch (sunxi_display.monitor) {
+ switch (sunxi_display->monitor) {
case sunxi_monitor_none:
break;
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
#ifdef CONFIG_VIDEO_HDMI
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
- sunxi_hdmi_mode_set(mode, clk_div, clk_double);
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+ sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
sunxi_hdmi_enable();
#endif
break;
@@ -930,7 +945,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
axp_set_eldo(3, 1800);
anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
ANX9804_DATA_RATE_1620M,
- sunxi_display.depth);
+ sunxi_display->depth);
}
if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
mdelay(50); /* Wait for lcd controller power on */
@@ -942,10 +957,10 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
i2c_set_bus_num(orig_i2c_bus);
}
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon0_mode_set(mode, false);
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
#ifdef CONFIG_VIDEO_LCD_SSD2828
sunxi_ssd2828_init(mode);
#endif
@@ -953,17 +968,17 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
break;
case sunxi_monitor_vga:
#ifdef CONFIG_VIDEO_VGA
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
- sunxi_tvencoder_mode_set();
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
+ sunxi_tvencoder_mode_set(monitor);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
tvencoder_enable(tve);
#elif defined CONFIG_VIDEO_VGA_VIA_LCD
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon0_mode_set(mode, true);
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
sunxi_vga_external_dac_enable();
#endif
break;
@@ -972,11 +987,11 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
case sunxi_monitor_composite_pal_m:
case sunxi_monitor_composite_pal_nc:
#ifdef CONFIG_VIDEO_COMPOSITE
- sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
- sunxi_tvencoder_mode_set();
+ sunxi_composer_mode_set(mode, address, monitor);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+ sunxi_tvencoder_mode_set(monitor);
sunxi_composer_enable();
- lcdc_enable(lcdc, sunxi_display.depth);
+ lcdc_enable(lcdc, sunxi_display->depth);
tvencoder_enable(tve);
#endif
break;
@@ -999,11 +1014,6 @@ static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
}
}
-ulong board_get_usable_ram_top(ulong total_size)
-{
- return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
-}
-
static bool sunxi_has_hdmi(void)
{
#ifdef CONFIG_VIDEO_HDMI
@@ -1052,9 +1062,11 @@ static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
return sunxi_monitor_none;
}
-void *video_hw_init(void)
+static int sunxi_de_probe(struct udevice *dev)
{
- static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
const struct ctfb_res_modes *mode;
struct ctfb_res_modes custom;
const char *options;
@@ -1067,10 +1079,8 @@ void *video_hw_init(void)
char mon[16];
char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
- memset(&sunxi_display, 0, sizeof(struct sunxi_display));
-
video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
- &sunxi_display.depth, &options);
+ &sunxi_display->depth, &options);
#ifdef CONFIG_VIDEO_HDMI
hpd = video_get_option_int(options, "hpd", 1);
hpd_delay = video_get_option_int(options, "hpd_delay", 500);
@@ -1078,35 +1088,35 @@ void *video_hw_init(void)
#endif
overscan_x = video_get_option_int(options, "overscan_x", -1);
overscan_y = video_get_option_int(options, "overscan_y", -1);
- sunxi_display.monitor = sunxi_get_default_mon(true);
+ sunxi_display->monitor = sunxi_get_default_mon(true);
video_get_option_string(options, "monitor", mon, sizeof(mon),
- sunxi_get_mon_desc(sunxi_display.monitor));
+ sunxi_get_mon_desc(sunxi_display->monitor));
for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
- sunxi_display.monitor = i;
+ sunxi_display->monitor = i;
break;
}
}
if (i > SUNXI_MONITOR_LAST)
printf("Unknown monitor: '%s', falling back to '%s'\n",
- mon, sunxi_get_mon_desc(sunxi_display.monitor));
+ mon, sunxi_get_mon_desc(sunxi_display->monitor));
#ifdef CONFIG_VIDEO_HDMI
/* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
- if (sunxi_display.monitor == sunxi_monitor_dvi ||
- sunxi_display.monitor == sunxi_monitor_hdmi) {
+ if (sunxi_display->monitor == sunxi_monitor_dvi ||
+ sunxi_display->monitor == sunxi_monitor_hdmi) {
/* Always call hdp_detect, as it also enables clocks, etc. */
hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
if (hdmi_present && edid) {
printf("HDMI connected: ");
- if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
+ if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
mode = &custom;
else
hdmi_present = false;
}
/* Fall back to EDID in case HPD failed */
if (edid && !hdmi_present) {
- if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
+ if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
mode = &custom;
hdmi_present = true;
}
@@ -1114,38 +1124,39 @@ void *video_hw_init(void)
/* Shut down when display was not found */
if ((hpd || edid) && !hdmi_present) {
sunxi_hdmi_shutdown();
- sunxi_display.monitor = sunxi_get_default_mon(false);
+ sunxi_display->monitor = sunxi_get_default_mon(false);
} /* else continue with hdmi/dvi without a cable connected */
}
#endif
- switch (sunxi_display.monitor) {
+ switch (sunxi_display->monitor) {
case sunxi_monitor_none:
- return NULL;
+ printf("Unknown monitor\n");
+ return -EINVAL;
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
if (!sunxi_has_hdmi()) {
printf("HDMI/DVI not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
break;
case sunxi_monitor_lcd:
if (!sunxi_has_lcd()) {
printf("LCD not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
- sunxi_display.depth = video_get_params(&custom, lcd_mode);
+ sunxi_display->depth = video_get_params(&custom, lcd_mode);
mode = &custom;
break;
case sunxi_monitor_vga:
if (!sunxi_has_vga()) {
printf("VGA not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
- sunxi_display.depth = 18;
+ sunxi_display->depth = 18;
break;
case sunxi_monitor_composite_pal:
case sunxi_monitor_composite_ntsc:
@@ -1153,85 +1164,99 @@ void *video_hw_init(void)
case sunxi_monitor_composite_pal_nc:
if (!sunxi_has_composite()) {
printf("Composite video not supported on this board\n");
- sunxi_display.monitor = sunxi_monitor_none;
- return NULL;
+ sunxi_display->monitor = sunxi_monitor_none;
+ return -EINVAL;
}
- if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
- sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
+ if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
+ sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
mode = &composite_video_modes[0];
else
mode = &composite_video_modes[1];
- sunxi_display.depth = 24;
+ sunxi_display->depth = 24;
break;
}
/* Yes these defaults are quite high, overscan on composite sucks... */
if (overscan_x == -1)
- overscan_x = sunxi_is_composite() ? 32 : 0;
+ overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
if (overscan_y == -1)
- overscan_y = sunxi_is_composite() ? 20 : 0;
+ overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
- sunxi_display.fb_size =
- (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
+ sunxi_display->fb_size = plat->size;
overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
/* We want to keep the fb_base for simplefb page aligned, where as
* the sunxi dma engines will happily accept an unaligned address. */
if (overscan_offset)
- sunxi_display.fb_size += 0x1000;
-
- if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
- printf("Error need %dkB for fb, but only %dkB is reserved\n",
- sunxi_display.fb_size >> 10,
- CONFIG_SUNXI_MAX_FB_SIZE >> 10);
- return NULL;
- }
+ sunxi_display->fb_size += 0x1000;
printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
mode->xres, mode->yres,
(mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
- sunxi_get_mon_desc(sunxi_display.monitor),
+ sunxi_get_mon_desc(sunxi_display->monitor),
overscan_x, overscan_y);
- gd->fb_base = gd->bd->bi_dram[0].start +
- gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+ sunxi_display->fb_addr = plat->base;
sunxi_engines_init();
#ifdef CONFIG_EFI_LOADER
- efi_add_memory_map(gd->fb_base, sunxi_display.fb_size,
+ efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
EFI_RESERVED_MEMORY_TYPE);
#endif
- fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
- sunxi_display.fb_addr = gd->fb_base;
+ fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
if (overscan_offset) {
fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
- sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
- memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
- flush_cache(gd->fb_base, sunxi_display.fb_size);
+ sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
+ memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
+ flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
}
- sunxi_mode_set(mode, fb_dma_addr);
+ sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
- /*
- * These are the only members of this structure that are used. All the
- * others are driver specific. The pitch is stored in plnSizeX.
- */
- graphic_device->frameAdrs = sunxi_display.fb_addr;
- graphic_device->gdfIndex = GDF_32BIT_X888RGB;
- graphic_device->gdfBytesPP = 4;
- graphic_device->winSizeX = mode->xres - 2 * overscan_x;
- graphic_device->winSizeY = mode->yres - 2 * overscan_y;
- graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
-
- return graphic_device;
+ /* The members of struct video_priv to be set by the driver. */
+ uc_priv->bpix = VIDEO_BPP32;
+ uc_priv->xsize = mode->xres;
+ uc_priv->ysize = mode->yres;
+
+ video_set_flush_dcache(dev, true);
+
+ return 0;
}
+static int sunxi_de_bind(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
+
+ return 0;
+}
+
+static const struct video_ops sunxi_de_ops = {
+};
+
+U_BOOT_DRIVER(sunxi_de) = {
+ .name = "sunxi_de",
+ .id = UCLASS_VIDEO,
+ .ops = &sunxi_de_ops,
+ .bind = sunxi_de_bind,
+ .probe = sunxi_de_probe,
+ .priv_auto = sizeof(struct sunxi_display_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRVINFO(sunxi_de) = {
+ .name = "sunxi_de"
+};
+
/*
* Simplefb support.
*/
#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
int sunxi_simplefb_setup(void *blob)
{
- static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+ struct sunxi_display_priv *sunxi_display;
+ struct video_priv *uc_priv;
+ struct udevice *de;
int offset, ret;
u64 start, size;
const char *pipeline = NULL;
@@ -1242,7 +1267,19 @@ int sunxi_simplefb_setup(void *blob)
#define PIPELINE_PREFIX
#endif
- switch (sunxi_display.monitor) {
+ ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
+ if (ret) {
+ printf("DE not present\n");
+ return 0;
+ } else if (!device_active(de)) {
+ printf("DE is present but not probed\n");
+ return 0;
+ }
+
+ uc_priv = dev_get_uclass_priv(de);
+ sunxi_display = dev_get_priv(de);
+
+ switch (sunxi_display->monitor) {
case sunxi_monitor_none:
return 0;
case sunxi_monitor_dvi:
@@ -1280,16 +1317,17 @@ int sunxi_simplefb_setup(void *blob)
* linux/arch/arm/mm/ioremap.c around line 301.
*/
start = gd->bd->bi_dram[0].start;
- size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+ size = sunxi_display->fb_addr - start;
ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
if (ret) {
eprintf("Cannot setup simplefb: Error reserving memory\n");
return ret;
}
- ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
- graphic_device->winSizeX, graphic_device->winSizeY,
- graphic_device->plnSizeX, "x8r8g8b8");
+ ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
+ uc_priv->xsize, uc_priv->ysize,
+ VNBYTES(uc_priv->bpix) * uc_priv->xsize,
+ "x8r8g8b8");
if (ret)
eprintf("Cannot setup simplefb: Error setting properties\n");
diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c
index 95976ee5735..ef1a2e6dc0f 100644
--- a/drivers/video/tegra124/sor.c
+++ b/drivers/video/tegra124/sor.c
@@ -671,8 +671,8 @@ static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor,
CSTM_ROTCLK_DEFAULT_MASK |
CSTM_LVDS_EN_ENABLE,
2 << CSTM_ROTCLK_SHIFT |
- is_lvds ? CSTM_LVDS_EN_ENABLE :
- CSTM_LVDS_EN_DISABLE);
+ (is_lvds ? CSTM_LVDS_EN_ENABLE :
+ CSTM_LVDS_EN_DISABLE));
tegra_dc_sor_config_pwm(sor, 1024, 1024);
}
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
index 66de22318f2..1e6f07ff4b0 100644
--- a/drivers/video/video_bmp.c
+++ b/drivers/video/video_bmp.c
@@ -328,7 +328,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
for (j = 0; j < width; j++)
fb_put_word(&fb, &bmap);
- bmap += (padded_width - width) * 2;
+ bmap += (padded_width - width);
fb -= width * 2 + priv->line_length;
}
break;
@@ -352,7 +352,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
}
}
fb -= priv->line_length + width * (bpix / 8);
- bmap += (padded_width - width) * 3;
+ bmap += (padded_width - width);
}
break;
#endif /* CONFIG_BMP_24BPP */
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 602ccbe41c0..f0ff2612a6b 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -9,6 +9,19 @@ config WATCHDOG
this option if you want to service enabled watchdog by U-Boot. Disable
this option if you want U-Boot to start watchdog but never service it.
+config WATCHDOG_AUTOSTART
+ bool "Automatically start watchdog timer"
+ depends on WDT
+ default y
+ help
+ Automatically start watchdog timer and start servicing it during
+ init phase. Enabled by default. Disable this option if you want
+ to compile U-Boot with CONFIG_WDT support but do not want to
+ activate watchdog, like when CONFIG_WDT option is disabled. You
+ would be able to start watchdog manually by 'wdt' command. Useful
+ when you want to have support for 'wdt' command but do not want
+ to have watchdog enabled by default.
+
config WATCHDOG_TIMEOUT_MSECS
int "Watchdog timeout in msec"
default 128000 if ARCH_MX25 || ARCH_MX31 || ARCH_MX5 || ARCH_MX6
@@ -111,6 +124,13 @@ config WDT_BCM6345
The watchdog timer is stopped when initialized.
It performs full SoC reset.
+config WDT_BOOKE
+ bool "PowerPC Book-E watchdog driver"
+ depends on WDT && MPC85xx
+ help
+ Watchdog driver for PowerPC Book-E chips, such as the Freescale
+ MPC85xx SOCs and the IBM PowerPC 440.
+
config WDT_CDNS
bool "Cadence watchdog timer support"
depends on WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 6e70c7ae19c..5c7ef593fe5 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
obj-$(CONFIG_WDT_AST2600) += ast2600_wdt.o
obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
+obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o
obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
obj-$(CONFIG_WDT_ORION) += orion_wdt.o
obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
new file mode 100644
index 00000000000..50c091956e7
--- /dev/null
+++ b/drivers/watchdog/booke_wdt.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Watchdog timer for PowerPC Book-E systems
+ */
+
+#include <div64.h>
+#include <dm.h>
+#include <wdt.h>
+#include <asm/processor.h>
+
+#define WDTP_MASK TCR_WP(0x3f)
+
+/* For the specified period, determine the number of seconds
+ * corresponding to the reset time. There will be a watchdog
+ * exception at approximately 3/5 of this time.
+ *
+ * The formula to calculate this is given by:
+ * 2.5 * (2^(63-period+1)) / timebase_freq
+ *
+ * In order to simplify things, we assume that period is
+ * at least 1. This will still result in a very long timeout.
+ */
+static unsigned long long period_to_sec(unsigned int period)
+{
+ unsigned long long tmp = 1ULL << (64 - period);
+ unsigned long tmp2 = get_tbclk();
+
+ /* tmp may be a very large number and we don't want to overflow,
+ * so divide the timebase freq instead of multiplying tmp
+ */
+ tmp2 = tmp2 / 5 * 2;
+
+ do_div(tmp, tmp2);
+ return tmp;
+}
+
+/*
+ * This procedure will find the highest period which will give a timeout
+ * greater than the one required. e.g. for a bus speed of 66666666 and
+ * and a parameter of 2 secs, then this procedure will return a value of 38.
+ */
+static unsigned int sec_to_period(unsigned int secs)
+{
+ unsigned int period;
+
+ for (period = 63; period > 0; period--) {
+ if (period_to_sec(period) >= secs)
+ return period;
+ }
+ return 0;
+}
+
+static int booke_wdt_reset(struct udevice *dev)
+{
+ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS);
+
+ return 0;
+}
+
+static int booke_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+{
+ u32 val;
+ unsigned int timeout = DIV_ROUND_UP(timeout_ms, 1000);
+
+ /* clear status before enabling watchdog */
+ booke_wdt_reset(dev);
+ val = mfspr(SPRN_TCR);
+ val &= ~WDTP_MASK;
+ val |= (TCR_WIE | TCR_WRC(WRC_CHIP) | TCR_WP(sec_to_period(timeout)));
+
+ mtspr(SPRN_TCR, val);
+
+ return 0;
+}
+
+static int booke_wdt_stop(struct udevice *dev)
+{
+ u32 val;
+
+ val = mfspr(SPRN_TCR);
+ val &= ~(TCR_WIE | WDTP_MASK);
+ mtspr(SPRN_TCR, val);
+
+ /* clear status to make sure nothing is pending */
+ booke_wdt_reset(dev);
+
+ return 0;
+}
+
+static const struct wdt_ops booke_wdt_ops = {
+ .start = booke_wdt_start,
+ .stop = booke_wdt_stop,
+ .reset = booke_wdt_reset,
+};
+
+static const struct udevice_id booke_wdt_ids[] = {
+ { .compatible = "fsl,booke-wdt" },
+ {}
+};
+
+U_BOOT_DRIVER(booke_wdt) = {
+ .name = "booke_wdt",
+ .id = UCLASS_WDT,
+ .of_match = booke_wdt_ids,
+ .ops = &booke_wdt_ops,
+};
diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c
index c020324973e..9e5487168cd 100644
--- a/drivers/watchdog/designware_wdt.c
+++ b/drivers/watchdog/designware_wdt.c
@@ -9,7 +9,6 @@
#include <reset.h>
#include <wdt.h>
#include <asm/io.h>
-#include <asm/utils.h>
#include <linux/bitops.h>
#define DW_WDT_CR 0x00
@@ -35,7 +34,7 @@ static int designware_wdt_settimeout(void __iomem *base, unsigned int clk_khz,
signed int i;
/* calculate the timeout range value */
- i = log_2_n_round_up(timeout * clk_khz) - 16;
+ i = fls(timeout * clk_khz - 1) - 16;
i = clamp(i, 0, 15);
writel(i | (i << 4), base + DW_WDT_TORR);
@@ -130,27 +129,39 @@ static int designware_wdt_probe(struct udevice *dev)
if (ret)
return ret;
+ ret = clk_enable(&clk);
+ if (ret)
+ goto err;
+
priv->clk_khz = clk_get_rate(&clk) / 1000;
- if (!priv->clk_khz)
- return -EINVAL;
+ if (!priv->clk_khz) {
+ ret = -EINVAL;
+ goto err;
+ }
#else
priv->clk_khz = CONFIG_DW_WDT_CLOCK_KHZ;
#endif
-#if CONFIG_IS_ENABLED(DM_RESET)
- struct reset_ctl_bulk resets;
+ if (CONFIG_IS_ENABLED(DM_RESET)) {
+ struct reset_ctl_bulk resets;
- ret = reset_get_bulk(dev, &resets);
- if (ret)
- return ret;
+ ret = reset_get_bulk(dev, &resets);
+ if (ret)
+ goto err;
- ret = reset_deassert_bulk(&resets);
- if (ret)
- return ret;
-#endif
+ ret = reset_deassert_bulk(&resets);
+ if (ret)
+ goto err;
+ }
/* reset to disable the watchdog */
return designware_wdt_stop(dev);
+
+err:
+#if CONFIG_IS_ENABLED(CLK)
+ clk_free(&clk);
+#endif
+ return ret;
}
static const struct wdt_ops designware_wdt_ops = {
diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 5e0a096ce50..3586246fbfb 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -44,7 +44,7 @@ static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset)
#if !defined(CONFIG_IMX_WATCHDOG) || \
(defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
-void __attribute__((weak)) reset_cpu(ulong addr)
+void __attribute__((weak)) reset_cpu(void)
{
struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
diff --git a/drivers/watchdog/ulp_wdog.c b/drivers/watchdog/ulp_wdog.c
index 7533fc612c7..6f63b11b9ff 100644
--- a/drivers/watchdog/ulp_wdog.c
+++ b/drivers/watchdog/ulp_wdog.c
@@ -77,7 +77,7 @@ void hw_watchdog_init(void)
hw_watchdog_reset();
}
-void reset_cpu(ulong addr)
+void reset_cpu(void)
{
struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c
index 28f7918c467..0603ffbd36d 100644
--- a/drivers/watchdog/wdt-uclass.c
+++ b/drivers/watchdog/wdt-uclass.c
@@ -27,6 +27,7 @@ static ulong reset_period = 1000;
int initr_watchdog(void)
{
u32 timeout = WATCHDOG_TIMEOUT_SECS;
+ int ret;
/*
* Init watchdog: This will call the probe function of the
@@ -50,8 +51,17 @@ int initr_watchdog(void)
4 * reset_period) / 4;
}
- wdt_start(gd->watchdog_dev, timeout * 1000, 0);
- gd->flags |= GD_FLG_WDT_READY;
+ if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART)) {
+ printf("WDT: Not starting\n");
+ return 0;
+ }
+
+ ret = wdt_start(gd->watchdog_dev, timeout * 1000, 0);
+ if (ret != 0) {
+ printf("WDT: Failed to start\n");
+ return 0;
+ }
+
printf("WDT: Started with%s servicing (%ds timeout)\n",
IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", timeout);
@@ -61,21 +71,31 @@ int initr_watchdog(void)
int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{
const struct wdt_ops *ops = device_get_ops(dev);
+ int ret;
if (!ops->start)
return -ENOSYS;
- return ops->start(dev, timeout_ms, flags);
+ ret = ops->start(dev, timeout_ms, flags);
+ if (ret == 0)
+ gd->flags |= GD_FLG_WDT_READY;
+
+ return ret;
}
int wdt_stop(struct udevice *dev)
{
const struct wdt_ops *ops = device_get_ops(dev);
+ int ret;
if (!ops->stop)
return -ENOSYS;
- return ops->stop(dev);
+ ret = ops->stop(dev);
+ if (ret == 0)
+ gd->flags &= ~GD_FLG_WDT_READY;
+
+ return ret;
}
int wdt_reset(struct udevice *dev)