summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv/Kconfig16
-rw-r--r--arch/riscv/cpu/ax25/Kconfig2
-rw-r--r--arch/riscv/cpu/cpu.c20
-rw-r--r--arch/riscv/cpu/fu540/Kconfig2
-rw-r--r--arch/riscv/cpu/generic/Kconfig2
-rw-r--r--arch/riscv/cpu/start.S58
-rw-r--r--arch/riscv/dts/fu540-c000-u-boot.dtsi8
-rw-r--r--arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi4
-rw-r--r--arch/riscv/dts/k210.dtsi7
-rw-r--r--arch/riscv/include/asm/global_data.h3
-rw-r--r--arch/riscv/include/asm/smp.h7
-rw-r--r--arch/riscv/include/asm/syscon.h4
-rw-r--r--arch/riscv/lib/Makefile1
-rw-r--r--arch/riscv/lib/andes_plic.c58
-rw-r--r--arch/riscv/lib/andes_plmt.c44
-rw-r--r--arch/riscv/lib/interrupts.c3
-rw-r--r--arch/riscv/lib/rdtime.c38
-rw-r--r--arch/riscv/lib/sifive_clint.c62
-rw-r--r--arch/riscv/lib/smp.c16
-rw-r--r--arch/sandbox/dts/test.dts69
-rw-r--r--arch/sandbox/include/asm/cpu.h11
-rw-r--r--arch/sandbox/include/asm/reset.h3
-rw-r--r--arch/sandbox/include/asm/scmi_test.h99
-rw-r--r--cmd/Kconfig3
-rw-r--r--cmd/net.c10
-rw-r--r--configs/sandbox_defconfig5
-rw-r--r--doc/README.udp35
-rw-r--r--doc/board/sipeed/maix.rst10
-rw-r--r--doc/device-tree-bindings/arm/arm,scmi.txt197
-rw-r--r--drivers/clk/Kconfig8
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk_scmi.c99
-rw-r--r--drivers/clk/kendryte/clk.c4
-rw-r--r--drivers/core/regmap.c163
-rw-r--r--drivers/core/syscon-uclass.c2
-rw-r--r--drivers/cpu/cpu_sandbox.c39
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/scmi/Kconfig19
-rw-r--r--drivers/firmware/scmi/Makefile5
-rw-r--r--drivers/firmware/scmi/mailbox_agent.c102
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c410
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_devices.c113
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c119
-rw-r--r--drivers/firmware/scmi/smccc_agent.c89
-rw-r--r--drivers/firmware/scmi/smt.c139
-rw-r--r--drivers/firmware/scmi/smt.h86
-rw-r--r--drivers/firmware/ti_sci.c23
-rw-r--r--drivers/gpio/gpio-uclass.c71
-rw-r--r--drivers/i2c/mxc_i2c.c7
-rw-r--r--drivers/mailbox/k3-sec-proxy.c6
-rw-r--r--drivers/mmc/bcm2835_sdhost.c34
-rw-r--r--drivers/mmc/mtk-sd.c24
-rw-r--r--drivers/mtd/nand/raw/atmel_nand.c69
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c20
-rw-r--r--drivers/mtd/nand/raw/pxa3xx_nand.c30
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c45
-rw-r--r--drivers/mtd/nand/raw/vf610_nfc.c38
-rw-r--r--drivers/mtd/nand/spi/core.c8
-rw-r--r--drivers/mtd/spi/spi-nor-core.c1
-rw-r--r--drivers/mtd/spi/spi-nor-tiny.c21
-rw-r--r--drivers/net/bcm6368-eth.c3
-rw-r--r--drivers/net/dwc_eth_qos.c7
-rw-r--r--drivers/net/ftgmac100.c4
-rw-r--r--drivers/net/mvneta.c56
-rw-r--r--drivers/net/mvpp2.c87
-rw-r--r--drivers/net/phy/mscc.c129
-rw-r--r--drivers/net/smc911x.c3
-rw-r--r--drivers/net/sun8i_emac.c9
-rw-r--r--drivers/net/sunxi_emac.c5
-rw-r--r--drivers/net/ti/cpsw.c6
-rw-r--r--drivers/phy/Kconfig7
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c12
-rw-r--r--drivers/phy/marvell/comphy_core.c6
-rw-r--r--drivers/phy/phy-bcm-sr-pcie.c177
-rw-r--r--drivers/phy/phy-stm32-usbphyc.c2
-rw-r--r--drivers/phy/phy-ti-am654.c4
-rw-r--r--drivers/phy/rockchip/phy-rockchip-pcie.c14
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c6
-rw-r--r--drivers/ram/sifive/fu540_ddr.c17
-rw-r--r--drivers/remoteproc/k3_system_controller.c9
-rw-r--r--drivers/remoteproc/rproc-elf-loader.c16
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c24
-rw-r--r--drivers/reset/Kconfig8
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-scmi.c81
-rw-r--r--drivers/reset/reset-uclass.c118
-rw-r--r--drivers/reset/sandbox-reset-test.c51
-rw-r--r--drivers/reset/sandbox-reset.c19
-rw-r--r--drivers/smem/msm_smem.c2
-rw-r--r--drivers/spi/spi-sunxi.c6
-rw-r--r--drivers/spi/zynqmp_gqspi.c6
-rw-r--r--drivers/sysreset/sysreset-ti-sci.c3
-rw-r--r--drivers/timer/Kconfig4
-rw-r--r--drivers/timer/riscv_timer.c39
-rw-r--r--drivers/timer/sandbox_timer.c4
-rw-r--r--drivers/timer/timer-uclass.c31
-rw-r--r--drivers/usb/cdns3/ep0.c5
-rw-r--r--drivers/usb/cdns3/gadget.c3
-rw-r--r--drivers/usb/dwc3/core.c15
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c1
-rw-r--r--drivers/usb/dwc3/ep0.c1
-rw-r--r--drivers/usb/dwc3/gadget.c23
-rw-r--r--drivers/usb/dwc3/ti_usb_phy.c4
-rw-r--r--drivers/usb/host/dwc2.c39
-rw-r--r--drivers/usb/musb-new/sunxi.c9
-rw-r--r--drivers/video/dw_mipi_dsi.c24
-rw-r--r--include/asm-generic/gpio.h47
-rw-r--r--include/dm/device_compat.h127
-rw-r--r--include/dm/uclass-id.h1
-rw-r--r--include/dt-bindings/clock/k210-sysctl.h1
-rw-r--r--include/linux/compat.h19
-rw-r--r--include/mmc.h2
-rw-r--r--include/net.h2
-rw-r--r--include/net/sntp.h (renamed from net/sntp.h)3
-rw-r--r--include/net/udp.h41
-rw-r--r--include/regmap.h205
-rw-r--r--include/remoteproc.h13
-rw-r--r--include/reset.h135
-rw-r--r--include/scmi_agent-uclass.h24
-rw-r--r--include/scmi_agent.h68
-rw-r--r--include/scmi_protocols.h179
-rw-r--r--include/timer.h15
-rw-r--r--net/Kconfig6
-rw-r--r--net/Makefile1
-rw-r--r--net/eth-uclass.c6
-rw-r--r--net/eth_legacy.c4
-rw-r--r--net/mdio-uclass.c4
-rw-r--r--net/net.c44
-rw-r--r--net/sntp.c29
-rw-r--r--net/tftp.c9
-rw-r--r--net/udp.c46
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/bus.c2
-rw-r--r--test/dm/gpio.c102
-rw-r--r--test/dm/regmap.c198
-rw-r--r--test/dm/reset.c60
-rw-r--r--test/dm/scmi.c203
-rw-r--r--test/dm/test-fdt.c6
-rw-r--r--test/dm/timer.c27
-rw-r--r--test/py/tests/test_bind.py2
142 files changed, 4605 insertions, 723 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 009a545fcf..aaa3b833a5 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -155,10 +155,6 @@ config 64BIT
config SIFIVE_CLINT
bool
depends on RISCV_MMODE || SPL_RISCV_MMODE
- select REGMAP
- select SYSCON
- select SPL_REGMAP if SPL
- select SPL_SYSCON if SPL
help
The SiFive CLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
@@ -177,22 +173,10 @@ config ANDES_PLIC
config ANDES_PLMT
bool
depends on RISCV_MMODE || SPL_RISCV_MMODE
- select REGMAP
- select SYSCON
- select SPL_REGMAP if SPL
- select SPL_SYSCON if SPL
help
The Andes PLMT block holds memory-mapped mtime register
associated with timer tick.
-config RISCV_RDTIME
- bool
- default y if RISCV_SMODE || SPL_RISCV_SMODE
- help
- The provides the riscv_get_time() API that is implemented using the
- standard rdtime instruction. This is the case for S-mode U-Boot, and
- is useful for processors that support rdtime in M-mode too.
-
config SYS_MALLOC_F_LEN
default 0x1000
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index 8d8d71dcbf..5cb5bb51eb 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -3,7 +3,7 @@ config RISCV_NDS
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
- imply RISCV_TIMER
+ imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply ANDES_PLIC if (RISCV_MMODE || SPL_RISCV_MMODE)
imply ANDES_PLMT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply SPL_CPU_SUPPORT
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index bfa2d4a426..85592f5bee 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -72,6 +72,17 @@ static int riscv_cpu_probe(void)
return 0;
}
+/*
+ * This is called on secondary harts just after the IPI is init'd. Currently
+ * there's nothing to do, since we just need to clear any existing IPIs, and
+ * that is handled by the sending of an ipi itself.
+ */
+#if CONFIG_IS_ENABLED(SMP)
+static void dummy_pending_ipi_clear(ulong hart, ulong arg0, ulong arg1)
+{
+}
+#endif
+
int arch_cpu_init_dm(void)
{
int ret;
@@ -111,6 +122,15 @@ int arch_cpu_init_dm(void)
ret = riscv_init_ipi();
if (ret)
return ret;
+
+ /*
+ * Clear all pending IPIs on secondary harts. We don't do anything on
+ * the boot hart, since we never send an IPI to ourselves, and no
+ * interrupts are enabled
+ */
+ ret = smp_call_function((ulong)dummy_pending_ipi_clear, 0, 0, 0);
+ if (ret)
+ return ret;
#endif
return 0;
diff --git a/arch/riscv/cpu/fu540/Kconfig b/arch/riscv/cpu/fu540/Kconfig
index 53e19635c8..ac3f183342 100644
--- a/arch/riscv/cpu/fu540/Kconfig
+++ b/arch/riscv/cpu/fu540/Kconfig
@@ -10,7 +10,7 @@ config SIFIVE_FU540
select SPL_RAM if SPL
imply CPU
imply CPU_RISCV
- imply RISCV_TIMER
+ imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply CMD_CPU
imply SPL_CPU_SUPPORT
diff --git a/arch/riscv/cpu/generic/Kconfig b/arch/riscv/cpu/generic/Kconfig
index b2cb155d6d..f4c2e2643c 100644
--- a/arch/riscv/cpu/generic/Kconfig
+++ b/arch/riscv/cpu/generic/Kconfig
@@ -7,7 +7,7 @@ config GENERIC_RISCV
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
- imply RISCV_TIMER
+ imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE)
imply CMD_CPU
imply SPL_CPU_SUPPORT
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index bf9fdf369b..bbc737ed9a 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -43,14 +43,32 @@ _start:
csrr a0, CSR_MHARTID
#endif
- /* save hart id and dtb pointer */
+ /*
+ * Save hart id and dtb pointer. The thread pointer register is not
+ * modified by C code. It is used by secondary_hart_loop.
+ */
mv tp, a0
mv s1, a1
+ /*
+ * Set the global data pointer to a known value in case we get a very
+ * early trap. The global data pointer will be set its actual value only
+ * after it has been initialized.
+ */
+ mv gp, zero
+
+ /*
+ * Set the trap handler. This must happen after initializing gp because
+ * the handler may use it.
+ */
la t0, trap_entry
csrw MODE_PREFIX(tvec), t0
- /* mask all interrupts */
+ /*
+ * Mask all interrupts. Interrupts are disabled globally (in m/sstatus)
+ * for U-Boot, but we will need to read m/sip to determine if we get an
+ * IPI
+ */
csrw MODE_PREFIX(ie), zero
#if CONFIG_IS_ENABLED(SMP)
@@ -65,8 +83,6 @@ _start:
#else
li t0, SIE_SSIE
#endif
- /* Clear any pending IPIs */
- csrc MODE_PREFIX(ip), t0
csrs MODE_PREFIX(ie), t0
#endif
@@ -87,10 +103,10 @@ call_board_init_f_0:
jal board_init_f_alloc_reserve
/*
- * Set global data pointer here for all harts, uninitialized at this
- * point.
+ * Save global data pointer for later. We don't set it here because it
+ * is not initialized yet.
*/
- mv gp, a0
+ mv s0, a0
/* setup stack */
#if CONFIG_IS_ENABLED(SMP)
@@ -111,6 +127,14 @@ call_board_init_f_0:
amoswap.w s2, t1, 0(t0)
bnez s2, wait_for_gd_init
#else
+ /*
+ * FIXME: gp is set before it is initialized. If an XIP U-Boot ever
+ * encounters a pending IPI on boot it is liable to jump to whatever
+ * memory happens to be in ipi_data.addr on boot. It may also run into
+ * problems if it encounters an exception too early (because printf/puts
+ * accesses gd).
+ */
+ mv gp, s0
bnez tp, secondary_hart_loop
#endif
@@ -127,16 +151,21 @@ call_board_init_f_0:
#ifndef CONFIG_XIP
la t0, available_harts_lock
- fence rw, w
- amoswap.w zero, zero, 0(t0)
+ amoswap.w.rl zero, zero, 0(t0)
wait_for_gd_init:
la t0, available_harts_lock
li t1, 1
-1: amoswap.w t1, t1, 0(t0)
- fence r, rw
+1: amoswap.w.aq t1, t1, 0(t0)
bnez t1, 1b
+ /*
+ * Set the global data pointer only when gd_t has been initialized.
+ * This was already set by arch_setup_gd on the boot hart, but all other
+ * harts' global data pointers gets set here.
+ */
+ mv gp, s0
+
/* register available harts in the available_harts mask */
li t1, 1
sll t1, t1, tp
@@ -144,8 +173,7 @@ wait_for_gd_init:
or t2, t2, t1
SREG t2, GD_AVAILABLE_HARTS(gp)
- fence rw, w
- amoswap.w zero, zero, 0(t0)
+ amoswap.w.rl zero, zero, 0(t0)
/*
* Continue on hart lottery winner, others branch to
@@ -395,6 +423,10 @@ secondary_hart_relocate:
mv gp, a2
#endif
+/*
+ * Interrupts are disabled globally, but they can still be read from m/sip. The
+ * wfi function will wake us up if we get an IPI, even if we do not trap.
+ */
secondary_hart_loop:
wfi
diff --git a/arch/riscv/dts/fu540-c000-u-boot.dtsi b/arch/riscv/dts/fu540-c000-u-boot.dtsi
index 5302677ee4..a06e1b11c6 100644
--- a/arch/riscv/dts/fu540-c000-u-boot.dtsi
+++ b/arch/riscv/dts/fu540-c000-u-boot.dtsi
@@ -55,9 +55,13 @@
reg = <0x0 0x10070000 0x0 0x1000>;
fuse-count = <0x1000>;
};
- clint@2000000 {
+ clint: clint@2000000 {
compatible = "riscv,clint0";
- interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 &cpu1_intc 3 &cpu1_intc 7 &cpu2_intc 3 &cpu2_intc 7 &cpu3_intc 3 &cpu3_intc 7 &cpu4_intc 3 &cpu4_intc 7>;
+ interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7
+ &cpu1_intc 3 &cpu1_intc 7
+ &cpu2_intc 3 &cpu2_intc 7
+ &cpu3_intc 3 &cpu3_intc 7
+ &cpu4_intc 3 &cpu4_intc 7>;
reg = <0x0 0x2000000 0x0 0xc0000>;
u-boot,dm-spl;
};
diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
index 5d0c928b29..1996149c95 100644
--- a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
+++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
@@ -34,6 +34,10 @@
};
+&clint {
+ clocks = <&rtcclk>;
+};
+
&qspi0 {
u-boot,dm-spl;
diff --git a/arch/riscv/dts/k210.dtsi b/arch/riscv/dts/k210.dtsi
index 2546c7d4e0..84cff51c36 100644
--- a/arch/riscv/dts/k210.dtsi
+++ b/arch/riscv/dts/k210.dtsi
@@ -17,6 +17,8 @@
compatible = "kendryte,k210";
aliases {
+ cpu0 = &cpu0;
+ cpu1 = &cpu1;
dma0 = &dmac0;
gpio0 = &gpio0;
gpio1 = &gpio1_0;
@@ -126,14 +128,13 @@
read-only;
};
- clint0: interrupt-controller@2000000 {
+ clint0: clint@2000000 {
#interrupt-cells = <1>;
compatible = "kendryte,k210-clint", "riscv,clint0";
reg = <0x2000000 0xC000>;
- interrupt-controller;
interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>,
<&cpu1_intc 3>, <&cpu1_intc 7>;
- clocks = <&sysclk K210_CLK_CPU>;
+ clocks = <&sysclk K210_CLK_CLINT>;
};
plic0: interrupt-controller@C000000 {
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index b711fcc44d..d3a0b1d221 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -24,9 +24,6 @@ struct arch_global_data {
#ifdef CONFIG_ANDES_PLIC
void __iomem *plic; /* plic base address */
#endif
-#ifdef CONFIG_ANDES_PLMT
- void __iomem *plmt; /* plmt base address */
-#endif
#if CONFIG_IS_ENABLED(SMP)
struct ipi_data ipi[CONFIG_NR_CPUS];
#endif
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 1b428856b2..2dae0800ce 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -18,14 +18,21 @@
* IPI data structure. The hart ID is inserted by the hart handling the IPI and
* calling the function.
*
+ * @valid is used to determine whether a sent IPI originated from U-Boot. It is
+ * initialized to zero by board_init_f_alloc_reserve. When U-Boot sends its
+ * first IPI, it is set to 1. This prevents already-pending IPIs not sent by
+ * U-Boot from being taken.
+ *
* @addr: Address of function
* @arg0: First argument of function
* @arg1: Second argument of function
+ * @valid: Whether this IPI is valid
*/
struct ipi_data {
ulong addr;
ulong arg0;
ulong arg1;
+ unsigned int valid;
};
/**
diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
index 26a008ca59..c3629e4b53 100644
--- a/arch/riscv/include/asm/syscon.h
+++ b/arch/riscv/include/asm/syscon.h
@@ -7,13 +7,13 @@
#define _ASM_SYSCON_H
/*
- * System controllers in a RISC-V system
+ * System controllers in a RISC-V system. These should only be used for
+ * identifying IPI controllers. Other devices should use DM to probe.
*/
enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */
- RISCV_SYSCON_PLMT, /* Platform Level Machine Timer (PLMT) */
};
#endif /* _ASM_SYSCON_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 6c503ff2b2..10ac5b06d3 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
obj-$(CONFIG_ANDES_PLIC) += andes_plic.o
obj-$(CONFIG_ANDES_PLMT) += andes_plmt.o
else
-obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
obj-$(CONFIG_SBI) += sbi.o
obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
endif
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
index c2a8fe4d9e..267d6a191b 100644
--- a/arch/riscv/lib/andes_plic.c
+++ b/arch/riscv/lib/andes_plic.c
@@ -41,53 +41,45 @@ static int enable_ipi(int hart)
return 0;
}
-static int init_plic(void)
+int riscv_init_ipi(void)
{
- struct udevice *dev;
- ofnode node;
int ret;
+ long *base = syscon_get_first_range(RISCV_SYSCON_PLIC);
+ ofnode node;
+ struct udevice *dev;
u32 reg;
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ gd->arch.plic = base;
+
ret = uclass_find_first_device(UCLASS_CPU, &dev);
if (ret)
return ret;
+ else if (!dev)
+ return -ENODEV;
- if (dev) {
- ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
- const char *device_type;
-
- device_type = ofnode_read_string(node, "device_type");
- if (!device_type)
- continue;
+ ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
+ const char *device_type;
- if (strcmp(device_type, "cpu"))
- continue;
+ device_type = ofnode_read_string(node, "device_type");
+ if (!device_type)
+ continue;
- /* skip if hart is marked as not available */
- if (!ofnode_is_available(node))
- continue;
+ if (strcmp(device_type, "cpu"))
+ continue;
- /* read hart ID of CPU */
- ret = ofnode_read_u32(node, "reg", &reg);
- if (ret == 0)
- enable_ipi(reg);
- }
+ /* skip if hart is marked as not available */
+ if (!ofnode_is_available(node))
+ continue;
- return 0;
+ /* read hart ID of CPU */
+ ret = ofnode_read_u32(node, "reg", &reg);
+ if (ret == 0)
+ enable_ipi(reg);
}
- return -ENODEV;
-}
-
-int riscv_init_ipi(void)
-{
- long *ret = syscon_get_first_range(RISCV_SYSCON_PLIC);
-
- if (IS_ERR(ret))
- return PTR_ERR(ret);
- gd->arch.plic = ret;
-
- return init_plic();
+ return 0;
}
int riscv_send_ipi(int hart)
diff --git a/arch/riscv/lib/andes_plmt.c b/arch/riscv/lib/andes_plmt.c
index a7e90ca992..a28c14c1eb 100644
--- a/arch/riscv/lib/andes_plmt.c
+++ b/arch/riscv/lib/andes_plmt.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019, Rick Chen <rick@andestech.com>
+ * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
*
* U-Boot syscon driver for Andes's Platform Level Machine Timer (PLMT).
* The PLMT block holds memory-mapped mtime register
@@ -9,46 +10,43 @@
#include <common.h>
#include <dm.h>
-#include <regmap.h>
-#include <syscon.h>
+#include <timer.h>
#include <asm/io.h>
-#include <asm/syscon.h>
#include <linux/err.h>
/* mtime register */
#define MTIME_REG(base) ((ulong)(base))
-DECLARE_GLOBAL_DATA_PTR;
-
-#define PLMT_BASE_GET(void) \
- do { \
- long *ret; \
- \
- if (!gd->arch.plmt) { \
- ret = syscon_get_first_range(RISCV_SYSCON_PLMT); \
- if (IS_ERR(ret)) \
- return PTR_ERR(ret); \
- gd->arch.plmt = ret; \
- } \
- } while (0)
-
-int riscv_get_time(u64 *time)
+static int andes_plmt_get_count(struct udevice *dev, u64 *count)
{
- PLMT_BASE_GET();
-
- *time = readq((void __iomem *)MTIME_REG(gd->arch.plmt));
+ *count = readq((void __iomem *)MTIME_REG(dev->priv));
return 0;
}
+static const struct timer_ops andes_plmt_ops = {
+ .get_count = andes_plmt_get_count,
+};
+
+static int andes_plmt_probe(struct udevice *dev)
+{
+ dev->priv = dev_read_addr_ptr(dev);
+ if (!dev->priv)
+ return -EINVAL;
+
+ return timer_timebase_fallback(dev);
+}
+
static const struct udevice_id andes_plmt_ids[] = {
- { .compatible = "riscv,plmt0", .data = RISCV_SYSCON_PLMT },
+ { .compatible = "riscv,plmt0" },
{ }
};
U_BOOT_DRIVER(andes_plmt) = {
.name = "andes_plmt",
- .id = UCLASS_SYSCON,
+ .id = UCLASS_TIMER,
.of_match = andes_plmt_ids,
+ .ops = &andes_plmt_ops,
+ .probe = andes_plmt_probe,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index cd47e64487..ad870e98d8 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -78,7 +78,8 @@ static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
printf("EPC: " REG_FMT " RA: " REG_FMT " TVAL: " REG_FMT "\n",
epc, regs->ra, tval);
- if (gd->flags & GD_FLG_RELOC)
+ /* Print relocation adjustments, but only if gd is initialized */
+ if (gd && gd->flags & GD_FLG_RELOC)
printf("EPC: " REG_FMT " RA: " REG_FMT " reloc adjusted\n\n",
epc - gd->reloc_off, regs->ra - gd->reloc_off);
diff --git a/arch/riscv/lib/rdtime.c b/arch/riscv/lib/rdtime.c
deleted file mode 100644
index e128d7fce6..0000000000
--- a/arch/riscv/lib/rdtime.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
- * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
- *
- * The riscv_get_time() API implementation that is using the
- * standard rdtime instruction.
- */
-
-#include <common.h>
-
-/* Implement the API required by RISC-V timer driver */
-int riscv_get_time(u64 *time)
-{
-#ifdef CONFIG_64BIT
- u64 n;
-
- __asm__ __volatile__ (
- "rdtime %0"
- : "=r" (n));
-
- *time = n;
-#else
- u32 lo, hi, tmp;
-
- __asm__ __volatile__ (
- "1:\n"
- "rdtimeh %0\n"
- "rdtime %1\n"
- "rdtimeh %2\n"
- "bne %0, %2, 1b"
- : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
-
- *time = ((u64)hi << 32) | lo;
-#endif
-
- return 0;
-}
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
index b9a2c649cc..c9704c596f 100644
--- a/arch/riscv/lib/sifive_clint.c
+++ b/arch/riscv/lib/sifive_clint.c
@@ -8,9 +8,9 @@
*/
#include <common.h>
+#include <clk.h>
#include <dm.h>
-#include <regmap.h>
-#include <syscon.h>
+#include <timer.h>
#include <asm/io.h>
#include <asm/syscon.h>
#include <linux/err.h>
@@ -24,68 +24,74 @@
DECLARE_GLOBAL_DATA_PTR;
-int riscv_get_time(u64 *time)
+int riscv_init_ipi(void)
{
- /* ensure timer register base has a sane value */
- riscv_init_ipi();
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_driver(UCLASS_TIMER,
+ DM_GET_DRIVER(sifive_clint), &dev);
+ if (ret)
+ return ret;
- *time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
+ gd->arch.clint = dev_read_addr_ptr(dev);
+ if (!gd->arch.clint)
+ return -EINVAL;
return 0;
}
-int riscv_set_timecmp(int hart, u64 cmp)
+int riscv_send_ipi(int hart)
{
- /* ensure timer register base has a sane value */
- riscv_init_ipi();
-
- writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
+ writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
-int riscv_init_ipi(void)
+int riscv_clear_ipi(int hart)
{
- if (!gd->arch.clint) {
- long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
-
- if (IS_ERR(ret))
- return PTR_ERR(ret);
- gd->arch.clint = ret;
- }
+ writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
-int riscv_send_ipi(int hart)
+int riscv_get_ipi(int hart, int *pending)
{
- writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+ *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
-int riscv_clear_ipi(int hart)
+static int sifive_clint_get_count(struct udevice *dev, u64 *count)
{
- writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+ *count = readq((void __iomem *)MTIME_REG(dev->priv));
return 0;
}
-int riscv_get_ipi(int hart, int *pending)
+static const struct timer_ops sifive_clint_ops = {
+ .get_count = sifive_clint_get_count,
+};
+
+static int sifive_clint_probe(struct udevice *dev)
{
- *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
+ dev->priv = dev_read_addr_ptr(dev);
+ if (!dev->priv)
+ return -EINVAL;
- return 0;
+ return timer_timebase_fallback(dev);
}
static const struct udevice_id sifive_clint_ids[] = {
- { .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
+ { .compatible = "riscv,clint0" },
{ }
};
U_BOOT_DRIVER(sifive_clint) = {
.name = "sifive_clint",
- .id = UCLASS_SYSCON,
+ .id = UCLASS_TIMER,
.of_match = sifive_clint_ids,
+ .probe = sifive_clint_probe,
+ .ops = &sifive_clint_ops,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
index ac22136314..8f33ce1fe3 100644
--- a/arch/riscv/lib/smp.c
+++ b/arch/riscv/lib/smp.c
@@ -54,6 +54,14 @@ static int send_ipi_many(struct ipi_data *ipi, int wait)
gd->arch.ipi[reg].arg0 = ipi->arg0;
gd->arch.ipi[reg].arg1 = ipi->arg1;
+ /*
+ * Ensure valid only becomes set when the IPI parameters are
+ * set. An IPI may already be pending on other harts, so we
+ * need a way to signal that the IPI device has been
+ * initialized, and that it is ok to call the function.
+ */
+ __smp_store_release(&gd->arch.ipi[reg].valid, 1);
+
ret = riscv_send_ipi(reg);
if (ret) {
pr_err("Cannot send IPI to hart %d\n", reg);
@@ -81,7 +89,13 @@ void handle_ipi(ulong hart)
if (hart >= CONFIG_NR_CPUS)
return;
- __smp_mb();
+ /*
+ * If valid is not set, then U-Boot has not requested the IPI. The
+ * IPI device may not be initialized, so all we can do is wait for
+ * U-Boot to initialize it and send an IPI
+ */
+ if (!__smp_load_acquire(&gd->arch.ipi[hart].valid))
+ return;
smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
invalidate_icache_all();
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 9f45c48e4e..e6da47d592 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -121,6 +121,9 @@
<&gpio_c 5 GPIO_IN>,
<&gpio_c 6 (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN)>,
<&gpio_c 7 (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE)>;
+ test4-gpios = <&gpio_a 14>, <&gpio_b 4 1 3 2 1>;
+ test5-gpios = <&gpio_a 19>;
+
int-value = <1234>;
uint-value = <(-1234)>;
int64-value = /bits/ 64 <0x1111222233334444>;
@@ -270,6 +273,13 @@
compatible = "denx,u-boot-devres-test";
};
+ another-test {
+ reg = <0 2>;
+ compatible = "denx,u-boot-fdt-test";
+ test4-gpios = <&gpio_a 14>, <&gpio_b 4 1 3 2 1>;
+ test5-gpios = <&gpio_a 19>;
+ };
+
acpi_test1: acpi-test {
compatible = "denx,u-boot-acpi-test";
acpi-ssdt-test-data = "ab";
@@ -356,6 +366,37 @@
sandbox_firmware: sandbox-firmware {
compatible = "sandbox,firmware";
};
+
+ sandbox-scmi-agent@0 {
+ compatible = "sandbox,scmi-agent";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ clk_scmi0: protocol@14 {
+ reg = <0x14>;
+ #clock-cells = <1>;
+ };
+
+ reset_scmi0: protocol@16 {
+ reg = <0x16>;
+ #reset-cells = <1>;
+ };
+ };
+
+ sandbox-scmi-agent@1 {
+ compatible = "sandbox,scmi-agent";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ clk_scmi1: protocol@14 {
+ reg = <0x14>;
+ #clock-cells = <1>;
+ };
+
+ protocol@10 {
+ reg = <0x10>;
+ };
+ };
};
pinctrl-gpio {
@@ -533,7 +574,9 @@
};
cpus {
+ timebase-frequency = <2000000>;
cpu-test1 {
+ timebase-frequency = <3000000>;
compatible = "sandbox,cpu_sandbox";
u-boot,dm-pre-reloc;
};
@@ -839,11 +882,16 @@
0x58 8>;
};
- timer {
+ timer@0 {
compatible = "sandbox,timer";
clock-frequency = <1000000>;
};
+ timer@1 {
+ compatible = "sandbox,timer";
+ sandbox,timebase-frequency-fallback;
+ };
+
tpm2 {
compatible = "sandbox,tpm2";
};
@@ -1036,6 +1084,12 @@
compatible = "sandbox,virtio2";
};
+ sandbox_scmi {
+ compatible = "sandbox,scmi-devices";
+ clocks = <&clk_scmi0 7>, <&clk_scmi0 3>, <&clk_scmi1 1>;
+ resets = <&reset_scmi0 3>;
+ };
+
pinctrl {
compatible = "sandbox,pinctrl";
@@ -1122,6 +1176,19 @@
resets = <&resetc2 15>, <&resetc2 30>, <&resetc2 60>;
reset-names = "valid", "no_mask", "out_of_range";
};
+
+ some_regmapped-bus {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+
+ ranges = <0x0 0x0 0x10>;
+ compatible = "simple-bus";
+
+ regmap-test_0 {
+ reg = <0 0x10>;
+ compatible = "sandbox,regmap_test";
+ };
+ };
};
#include "sandbox_pmic.dtsi"
diff --git a/arch/sandbox/include/asm/cpu.h b/arch/sandbox/include/asm/cpu.h
new file mode 100644
index 0000000000..c97ac7ba95
--- /dev/null
+++ b/arch/sandbox/include/asm/cpu.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#ifndef __SANDBOX_CPU_H
+#define __SANDBOX_CPU_H
+
+void cpu_sandbox_set_current(const char *name);
+
+#endif /* __SANDBOX_CPU_H */
diff --git a/arch/sandbox/include/asm/reset.h b/arch/sandbox/include/asm/reset.h
index c4205eabef..40d3e61c11 100644
--- a/arch/sandbox/include/asm/reset.h
+++ b/arch/sandbox/include/asm/reset.h
@@ -11,9 +11,12 @@
struct udevice;
int sandbox_reset_query(struct udevice *dev, unsigned long id);
+int sandbox_reset_is_requested(struct udevice *dev, unsigned long id);
int sandbox_reset_test_get(struct udevice *dev);
+int sandbox_reset_test_get_devm(struct udevice *dev);
int sandbox_reset_test_get_bulk(struct udevice *dev);
+int sandbox_reset_test_get_bulk_devm(struct udevice *dev);
int sandbox_reset_test_assert(struct udevice *dev);
int sandbox_reset_test_assert_bulk(struct udevice *dev);
int sandbox_reset_test_deassert(struct udevice *dev);
diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h
new file mode 100644
index 0000000000..3e8b0068fd
--- /dev/null
+++ b/arch/sandbox/include/asm/scmi_test.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020, Linaro Limited
+ */
+
+#ifndef __SANDBOX_SCMI_TEST_H
+#define __SANDBOX_SCMI_TEST_H
+
+struct udevice;
+struct sandbox_scmi_agent;
+struct sandbox_scmi_service;
+
+/**
+ * struct sandbox_scmi_clk - Simulated clock exposed by SCMI
+ * @id: Identifier of the clock used in the SCMI protocol
+ * @enabled: Clock state: true if enabled, false if disabled
+ * @rate: Clock rate in Hertz
+ */
+struct sandbox_scmi_clk {
+ uint id;
+ bool enabled;
+ ulong rate;
+};
+
+/**
+ * struct sandbox_scmi_reset - Simulated reset controller exposed by SCMI
+ * @asserted: Reset control state: true if asserted, false if desasserted
+ */
+struct sandbox_scmi_reset {
+ uint id;
+ bool asserted;
+};
+
+/**
+ * struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent
+ * @idx: Identifier for the SCMI agent, its index
+ * @clk: Simulated clocks
+ * @clk_count: Simulated clocks array size
+ * @clk: Simulated reset domains
+ * @clk_count: Simulated reset domains array size
+ */
+struct sandbox_scmi_agent {
+ uint idx;
+ struct sandbox_scmi_clk *clk;
+ size_t clk_count;
+ struct sandbox_scmi_reset *reset;
+ size_t reset_count;
+};
+
+/**
+ * struct sandbox_scmi_service - Reference to simutaed SCMI agents/services
+ * @agent: Pointer to SCMI sandbox agent pointers array
+ * @agent_count: Number of emulated agents exposed in array @agent.
+ */
+struct sandbox_scmi_service {
+ struct sandbox_scmi_agent **agent;
+ size_t agent_count;
+};
+
+/**
+ * struct sandbox_scmi_devices - Reference to devices probed through SCMI
+ * @clk: Array the clock devices
+ * @clk_count: Number of clock devices probed
+ * @reset: Array the reset controller devices
+ * @reset_count: Number of reset controller devices probed
+ */
+struct sandbox_scmi_devices {
+ struct clk *clk;
+ size_t clk_count;
+ struct reset_ctl *reset;
+ size_t reset_count;
+};
+
+#ifdef CONFIG_SCMI_FIRMWARE
+/**
+ * sandbox_scmi_service_context - Get the simulated SCMI services context
+ * @return: Reference to backend simulated resources state
+ */
+struct sandbox_scmi_service *sandbox_scmi_service_ctx(void);
+
+/**
+ * sandbox_scmi_devices_get_ref - Get references to devices accessed through SCMI
+ * @dev: Reference to the test device used get test resources
+ * @return: Reference to the devices probed by the SCMI test
+ */
+struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev);
+#else
+static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
+{
+ return NULL;
+}
+
+static inline
+struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev)
+{
+ return NULL;
+}
+#endif /* CONFIG_SCMI_FIRMWARE */
+#endif /* __SANDBOX_SCMI_TEST_H */
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0c984d735d..999b6cf239 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1645,6 +1645,7 @@ config CMD_CDP
config CMD_SNTP
bool "sntp"
+ select PROT_UDP
help
Synchronize RTC via network
@@ -2235,7 +2236,7 @@ config CMD_DIAG
config CMD_IRQ
bool "irq - Show information about interrupts"
- depends on !ARM && !MIPS && !SH
+ depends on !ARM && !MIPS && !RISCV && !SH
help
This enables two commands:
diff --git a/cmd/net.c b/cmd/net.c
index 9bbcdbcfe0..beb2877dfd 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -13,6 +13,8 @@
#include <env.h>
#include <image.h>
#include <net.h>
+#include <net/udp.h>
+#include <net/sntp.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -356,6 +358,12 @@ U_BOOT_CMD(
#endif
#if defined(CONFIG_CMD_SNTP)
+static struct udp_ops sntp_ops = {
+ .prereq = sntp_prereq,
+ .start = sntp_start,
+ .data = NULL,
+};
+
int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *toff;
@@ -380,7 +388,7 @@ int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
else
net_ntp_time_offset = simple_strtol(toff, NULL, 10);
- if (net_loop(SNTP) < 0) {
+ if (udp_loop(&sntp_ops) < 0) {
printf("SNTP failed: host %pI4 not responding\n",
&net_ntp_server);
return CMD_RET_FAILURE;
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 6e9f029cc9..c72e0e2900 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -102,6 +102,7 @@ CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_EXT4=y
CONFIG_ENV_EXT4_INTERFACE="host"
CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
+CONFIG_PROT_UDP=y
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
@@ -122,6 +123,7 @@ CONFIG_BUTTON=y
CONFIG_BUTTON_GPIO=y
CONFIG_CLK=y
CONFIG_CLK_COMPOSITE_CCF=y
+CONFIG_CLK_SCMI=y
CONFIG_SANDBOX_CLK_CCF=y
CONFIG_CPU=y
CONFIG_DM_DEMO=y
@@ -132,6 +134,8 @@ CONFIG_BOARD_SANDBOX=y
CONFIG_DMA=y
CONFIG_DMA_CHANNELS=y
CONFIG_SANDBOX_DMA=y
+CONFIG_FIRMWARE=y
+CONFIG_SCMI_FIRMWARE=y
CONFIG_GPIO_HOG=y
CONFIG_DM_GPIO_LOOKUP_LABEL=y
CONFIG_PM8916_GPIO=y
@@ -217,6 +221,7 @@ CONFIG_REMOTEPROC_SANDBOX=y
CONFIG_DM_RESET=y
CONFIG_SANDBOX_RESET=y
CONFIG_RESET_SYSCON=y
+CONFIG_RESET_SCMI=y
CONFIG_DM_RNG=y
CONFIG_DM_RTC=y
CONFIG_RTC_RV8803=y
diff --git a/doc/README.udp b/doc/README.udp
new file mode 100644
index 0000000000..da0725719d
--- /dev/null
+++ b/doc/README.udp
@@ -0,0 +1,35 @@
+Udp framework
+
+The udp framework is build on top of network framework and is designed
+to define new protocol or new command based on udp without modifying
+the network framework.
+
+The udp framework define a function udp_loop that take as argument
+a structure udp_ops (defined in include/net/udp.h) :
+
+struct udp_ops {
+ int (*prereq)(void *data);
+ int (*start)(void *data);
+ void *data;
+};
+
+The callback prereq define if all the requirements are
+valid before running the network/udp loop.
+
+The callback start define the first step in the network/udp loop,
+and it may also be used to configure a timemout and udp handler.
+
+The pointer data is used to store private data that
+could be used by both callback.
+
+A simple example to use this framework:
+
+static struct udp_ops udp_ops = {
+ .prereq = wmp_prereq,
+ .start = wmp_start,
+ .data = NULL,
+};
+
+...
+
+err = udp_loop(&udp_ops);
diff --git a/doc/board/sipeed/maix.rst b/doc/board/sipeed/maix.rst
index efcde9aebf..3f791b42fa 100644
--- a/doc/board/sipeed/maix.rst
+++ b/doc/board/sipeed/maix.rst
@@ -59,7 +59,7 @@ Sipeed MAIX BiT sipeed_maix_bitm_defconfig bit first
Sipeed MAIX BiT with Mic sipeed_maix_bitm_defconfig bit_mic first
Sipeed MAIXDUINO sipeed_maix_bitm_defconfig maixduino first
Sipeed MAIX GO goE second
-Sipeed MAIX ONE DOCK goD first
+Sipeed MAIX ONE DOCK dan first
======================== ========================== ========== ==========
Flashing causes a reboot of the device. Parameter -t specifies that the serial
@@ -285,11 +285,15 @@ Technical Details
Boot Sequence
^^^^^^^^^^^^^
-1. ``RESET`` pin is deasserted.
+1. ``RESET`` pin is deasserted. The pin is connected to the ``RESET`` button. It
+ can also be set to low via either the ``DTR`` or the ``RTS`` line of the
+ serial interface (depending on the board).
2. Both harts begin executing at ``0x00001000``.
3. Both harts jump to firmware at ``0x88000000``.
4. One hart is chosen as a boot hart.
-5. Firmware reads value of pin ``IO_16`` (ISP).
+5. Firmware reads the value of pin ``IO_16`` (ISP). This pin is connected to the
+ ``BOOT`` button. The pin can equally be set to low via either the ``DTR`` or
+ ``RTS`` line of the serial interface (depending on the board).
* If the pin is low, enter ISP mode. This mode allows loading data to ram,
writing it to flash, and booting from specific addresses.
diff --git a/doc/device-tree-bindings/arm/arm,scmi.txt b/doc/device-tree-bindings/arm/arm,scmi.txt
new file mode 100644
index 0000000000..1f293ea24c
--- /dev/null
+++ b/doc/device-tree-bindings/arm/arm,scmi.txt
@@ -0,0 +1,197 @@
+System Control and Management Interface (SCMI) Message Protocol
+----------------------------------------------------------
+
+The SCMI is intended to allow agents such as OSPM to manage various functions
+that are provided by the hardware platform it is running on, including power
+and performance functions.
+
+This binding is intended to define the interface the firmware implementing
+the SCMI as described in ARM document number ARM DEN 0056A ("ARM System Control
+and Management Interface Platform Design Document")[0] provide for OSPM in
+the device tree.
+
+Required properties:
+
+The scmi node with the following properties shall be under the /firmware/ node.
+
+- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports
+- mboxes: List of phandle and mailbox channel specifiers. It should contain
+ exactly one or two mailboxes, one for transmitting messages("tx")
+ and another optional for receiving the notifications("rx") if
+ supported.
+- shmem : List of phandle pointing to the shared memory(SHM) area as per
+ generic mailbox client binding.
+- #address-cells : should be '1' if the device has sub-nodes, maps to
+ protocol identifier for a given sub-node.
+- #size-cells : should be '0' as 'reg' property doesn't have any size
+ associated with it.
+- arm,smc-id : SMC id required when using smc or hvc transports
+
+Optional properties:
+
+- mbox-names: shall be "tx" or "rx" depending on mboxes entries.
+
+See Documentation/devicetree/bindings/mailbox/mailbox.txt for more details
+about the generic mailbox controller and client driver bindings.
+
+The mailbox is the only permitted method of calling the SCMI firmware.
+Mailbox doorbell is used as a mechanism to alert the presence of a
+messages and/or notification.
+
+Each protocol supported shall have a sub-node with corresponding compatible
+as described in the following sections. If the platform supports dedicated
+communication channel for a particular protocol, the 3 properties namely:
+mboxes, mbox-names and shmem shall be present in the sub-node corresponding
+to that protocol.
+
+Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol
+------------------------------------------------------------
+
+This binding uses the common clock binding[1].
+
+Required properties:
+- #clock-cells : Should be 1. Contains the Clock ID value used by SCMI commands.
+
+Power domain bindings for the power domains based on SCMI Message Protocol
+------------------------------------------------------------
+
+This binding for the SCMI power domain providers uses the generic power
+domain binding[2].
+
+Required properties:
+ - #power-domain-cells : Should be 1. Contains the device or the power
+ domain ID value used by SCMI commands.
+
+Sensor bindings for the sensors based on SCMI Message Protocol
+--------------------------------------------------------------
+SCMI provides an API to access the various sensors on the SoC.
+
+Required properties:
+- #thermal-sensor-cells: should be set to 1. This property follows the
+ thermal device tree bindings[3].
+
+ Valid cell values are raw identifiers (Sensor ID)
+ as used by the firmware. Refer to platform details
+ for your implementation for the IDs to use.
+
+Reset signal bindings for the reset domains based on SCMI Message Protocol
+------------------------------------------------------------
+
+This binding for the SCMI reset domain providers uses the generic reset
+signal binding[5].
+
+Required properties:
+ - #reset-cells : Should be 1. Contains the reset domain ID value used
+ by SCMI commands.
+
+SRAM and Shared Memory for SCMI
+-------------------------------
+
+A small area of SRAM is reserved for SCMI communication between application
+processors and SCP.
+
+The properties should follow the generic mmio-sram description found in [4]
+
+Each sub-node represents the reserved area for SCMI.
+
+Required sub-node properties:
+- reg : The base offset and size of the reserved area with the SRAM
+- compatible : should be "arm,scmi-shmem" for Non-secure SRAM based
+ shared memory
+
+[0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/power/power-domain.yaml
+[3] Documentation/devicetree/bindings/thermal/thermal.txt
+[4] Documentation/devicetree/bindings/sram/sram.yaml
+[5] Documentation/devicetree/bindings/reset/reset.txt
+
+Example:
+
+sram@50000000 {
+ compatible = "mmio-sram";
+ reg = <0x0 0x50000000 0x0 0x10000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x50000000 0x10000>;
+
+ cpu_scp_lpri: scp-shmem@0 {
+ compatible = "arm,scmi-shmem";
+ reg = <0x0 0x200>;
+ };
+
+ cpu_scp_hpri: scp-shmem@200 {
+ compatible = "arm,scmi-shmem";
+ reg = <0x200 0x200>;
+ };
+};
+
+mailbox@40000000 {
+ ....
+ #mbox-cells = <1>;
+ reg = <0x0 0x40000000 0x0 0x10000>;
+};
+
+firmware {
+
+ ...
+
+ scmi {
+ compatible = "arm,scmi";
+ mboxes = <&mailbox 0 &mailbox 1>;
+ mbox-names = "tx", "rx";
+ shmem = <&cpu_scp_lpri &cpu_scp_hpri>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ scmi_devpd: protocol@11 {
+ reg = <0x11>;
+ #power-domain-cells = <1>;
+ };
+
+ scmi_dvfs: protocol@13 {
+ reg = <0x13>;
+ #clock-cells = <1>;
+ };
+
+ scmi_clk: protocol@14 {
+ reg = <0x14>;
+ #clock-cells = <1>;
+ };
+
+ scmi_sensors0: protocol@15 {
+ reg = <0x15>;
+ #thermal-sensor-cells = <1>;
+ };
+
+ scmi_reset: protocol@16 {
+ reg = <0x16>;
+ #reset-cells = <1>;
+ };
+ };
+};
+
+cpu@0 {
+ ...
+ reg = <0 0>;
+ clocks = <&scmi_dvfs 0>;
+};
+
+hdlcd@7ff60000 {
+ ...
+ reg = <0 0x7ff60000 0 0x1000>;
+ clocks = <&scmi_clk 4>;
+ power-domains = <&scmi_devpd 1>;
+ resets = <&scmi_reset 10>;
+};
+
+thermal-zones {
+ soc_thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <1000>;
+ /* sensor ID */
+ thermal-sensors = <&scmi_sensors0 3>;
+ ...
+ };
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 6003e140b5..4dfbad7986 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -159,6 +159,14 @@ config CLK_CDCE9XX
Enable the clock synthesizer driver for CDCE913/925/937/949
series of chips.
+config CLK_SCMI
+ bool "Enable SCMI clock driver"
+ depends on SCMI_FIRMWARE
+ help
+ Enable this option if you want to support clock devices exposed
+ by a SCMI agent based on SCMI clock protocol communication
+ with a SCMI server.
+
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/at91/Kconfig"
source "drivers/clk/exynos/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cda4b4b605..d1e295ac7c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
obj-$(CONFIG_CLK_OWL) += owl/
obj-$(CONFIG_CLK_RENESAS) += renesas/
+obj-$(CONFIG_CLK_SCMI) += clk_scmi.o
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
new file mode 100644
index 0000000000..93a4819501
--- /dev/null
+++ b/drivers/clk/clk_scmi.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2020 Linaro Limited
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+
+static int scmi_clk_gate(struct clk *clk, int enable)
+{
+ struct scmi_clk_state_in in = {
+ .clock_id = clk->id,
+ .attributes = enable,
+ };
+ struct scmi_clk_state_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_CONFIG_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_clk_enable(struct clk *clk)
+{
+ return scmi_clk_gate(clk, 1);
+}
+
+static int scmi_clk_disable(struct clk *clk)
+{
+ return scmi_clk_gate(clk, 0);
+}
+
+static ulong scmi_clk_get_rate(struct clk *clk)
+{
+ struct scmi_clk_rate_get_in in = {
+ .clock_id = clk->id,
+ };
+ struct scmi_clk_rate_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_RATE_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
+}
+
+static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct scmi_clk_rate_set_in in = {
+ .clock_id = clk->id,
+ .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
+ .rate_lsb = (u32)rate,
+ .rate_msb = (u32)((u64)rate >> 32),
+ };
+ struct scmi_clk_rate_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_RATE_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return scmi_clk_get_rate(clk);
+}
+
+static const struct clk_ops scmi_clk_ops = {
+ .enable = scmi_clk_enable,
+ .disable = scmi_clk_disable,
+ .get_rate = scmi_clk_get_rate,
+ .set_rate = scmi_clk_set_rate,
+};
+
+U_BOOT_DRIVER(scmi_clock) = {
+ .name = "scmi_clk",
+ .id = UCLASS_CLK,
+ .ops = &scmi_clk_ops,
+};
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index 981b3b7699..bb196961af 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -646,6 +646,10 @@ static int k210_clk_probe(struct udevice *dev)
REGISTER_GATE(K210_CLK_RTC, "rtc", in0);
#undef REGISTER_GATE
+ /* The MTIME register in CLINT runs at one 50th the CPU clock speed */
+ clk_dm(K210_CLK_CLINT,
+ clk_register_fixed_factor(NULL, "clint", "cpu", 0, 1, 50));
+
return 0;
}
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index a67a237b88..c2bed88eac 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -14,7 +14,24 @@
#include <regmap.h>
#include <asm/io.h>
#include <dm/of_addr.h>
+#include <dm/devres.h>
#include <linux/ioport.h>
+#include <linux/compat.h>
+#include <linux/err.h>
+#include <linux/bitops.h>
+
+/*
+ * Internal representation of a regmap field. Instead of storing the MSB and
+ * LSB, store the shift and mask. This makes the code a bit cleaner and faster
+ * because the shift and mask don't have to be calculated every time.
+ */
+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+};
DECLARE_GLOBAL_DATA_PTR;
@@ -22,16 +39,22 @@ DECLARE_GLOBAL_DATA_PTR;
* regmap_alloc() - Allocate a regmap with a given number of ranges.
*
* @count: Number of ranges to be allocated for the regmap.
+ *
+ * The default regmap width is set to REGMAP_SIZE_32. Callers can override it
+ * if they need.
+ *
* Return: A pointer to the newly allocated regmap, or NULL on error.
*/
static struct regmap *regmap_alloc(int count)
{
struct regmap *map;
+ size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count;
- map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
+ map = calloc(1, size);
if (!map)
return NULL;
map->range_count = count;
+ map->width = REGMAP_SIZE_32;
return map;
}
@@ -155,6 +178,33 @@ err:
return ret;
}
+int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size,
+ struct regmap **mapp)
+{
+ struct regmap *map;
+ struct regmap_range *range;
+
+ map = regmap_alloc(1);
+ if (!map)
+ return -ENOMEM;
+
+ range = &map->ranges[0];
+ range->start = r_start;
+ range->size = r_size;
+
+ if (ofnode_read_bool(node, "little-endian"))
+ map->endianness = REGMAP_LITTLE_ENDIAN;
+ else if (ofnode_read_bool(node, "big-endian"))
+ map->endianness = REGMAP_BIG_ENDIAN;
+ else if (ofnode_read_bool(node, "native-endian"))
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+ else /* Default: native endianness */
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+
+ *mapp = map;
+ return 0;
+}
+
int regmap_init_mem(ofnode node, struct regmap **mapp)
{
struct regmap_range *range;
@@ -228,6 +278,42 @@ err:
return ret;
}
+
+static void devm_regmap_release(struct udevice *dev, void *res)
+{
+ regmap_uninit(*(struct regmap **)res);
+}
+
+struct regmap *devm_regmap_init(struct udevice *dev,
+ const struct regmap_bus *bus,
+ void *bus_context,
+ const struct regmap_config *config)
+{
+ int rc;
+ struct regmap **mapp, *map;
+
+ mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
+ __GFP_ZERO);
+ if (unlikely(!mapp))
+ return ERR_PTR(-ENOMEM);
+
+ if (config && config->r_size != 0)
+ rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start,
+ config->r_size, mapp);
+ else
+ rc = regmap_init_mem(dev_ofnode(dev), mapp);
+ if (rc)
+ return ERR_PTR(rc);
+
+ map = *mapp;
+ if (config) {
+ map->width = config->width;
+ map->reg_offset_shift = config->reg_offset_shift;
+ }
+
+ devres_add(dev, mapp);
+ return *mapp;
+}
#endif
void *regmap_get_range(struct regmap *map, unsigned int range_num)
@@ -310,6 +396,7 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
}
range = &map->ranges[range_num];
+ offset <<= map->reg_offset_shift;
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
@@ -347,7 +434,7 @@ int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
int regmap_read(struct regmap *map, uint offset, uint *valp)
{
- return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
+ return regmap_raw_read(map, offset, valp, map->width);
}
static inline void __write_8(u8 *addr, const u8 *val,
@@ -419,6 +506,7 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
}
range = &map->ranges[range_num];
+ offset <<= map->reg_offset_shift;
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
@@ -457,7 +545,7 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val,
int regmap_write(struct regmap *map, uint offset, uint val)
{
- return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
+ return regmap_raw_write(map, offset, &val, map->width);
}
int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
@@ -473,3 +561,72 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
return regmap_write(map, offset, reg | (val & mask));
}
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+ int ret;
+ unsigned int reg_val;
+
+ ret = regmap_read(field->regmap, field->reg, &reg_val);
+ if (ret != 0)
+ return ret;
+
+ reg_val &= field->mask;
+ reg_val >>= field->shift;
+ *val = reg_val;
+
+ return ret;
+}
+
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+ return regmap_update_bits(field->regmap, field->reg, field->mask,
+ val << field->shift);
+}
+
+static void regmap_field_init(struct regmap_field *rm_field,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ rm_field->regmap = regmap;
+ rm_field->reg = reg_field.reg;
+ rm_field->shift = reg_field.lsb;
+ rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
+}
+
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
+ GFP_KERNEL);
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
+{
+ devm_kfree(dev, field);
+}
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void regmap_field_free(struct regmap_field *field)
+{
+ kfree(field);
+}
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index 9cbda4ebda..5be1d527a0 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -70,7 +70,7 @@ static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp)
/* found node with "syscon" compatible, not bounded to SYSCON UCLASS */
if (!ofnode_device_is_compatible(node, "syscon")) {
- dev_dbg(dev, "invalid compatible for syscon device\n");
+ log_debug("invalid compatible for syscon device\n");
return -EINVAL;
}
diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c
index caa26e50f2..4ba0d1b99e 100644
--- a/drivers/cpu/cpu_sandbox.c
+++ b/drivers/cpu/cpu_sandbox.c
@@ -8,14 +8,15 @@
#include <dm.h>
#include <cpu.h>
-int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size)
+static int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size)
{
snprintf(buf, size, "LEG Inc. SuperMegaUltraTurbo CPU No. 1");
return 0;
}
-int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info)
+static int cpu_sandbox_get_info(const struct udevice *dev,
+ struct cpu_info *info)
{
info->cpu_freq = 42 * 42 * 42 * 42 * 42;
info->features = 0x42424242;
@@ -24,21 +25,29 @@ int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info)
return 0;
}
-int cpu_sandbox_get_count(const struct udevice *dev)
+static int cpu_sandbox_get_count(const struct udevice *dev)
{
return 42;
}
-int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf, int size)
+static int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf,
+ int size)
{
snprintf(buf, size, "Languid Example Garbage Inc.");
return 0;
}
-int cpu_sandbox_is_current(struct udevice *dev)
+static const char *cpu_current = "cpu-test1";
+
+void cpu_sandbox_set_current(const char *name)
{
- if (!strcmp(dev->name, "cpu-test1"))
+ cpu_current = name;
+}
+
+static int cpu_sandbox_is_current(struct udevice *dev)
+{
+ if (!strcmp(dev->name, cpu_current))
return 1;
return 0;
@@ -52,7 +61,22 @@ static const struct cpu_ops cpu_sandbox_ops = {
.is_current = cpu_sandbox_is_current,
};
-int cpu_sandbox_probe(struct udevice *dev)
+static int cpu_sandbox_bind(struct udevice *dev)
+{
+ int ret;
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+ /* first examine the property in current cpu node */
+ ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
+ /* if not found, then look at the parent /cpus node */
+ if (ret)
+ ret = dev_read_u32(dev->parent, "timebase-frequency",
+ &plat->timebase_freq);
+
+ return ret;
+}
+
+static int cpu_sandbox_probe(struct udevice *dev)
{
return 0;
}
@@ -67,5 +91,6 @@ U_BOOT_DRIVER(cpu_sandbox) = {
.id = UCLASS_CPU,
.ops = &cpu_sandbox_ops,
.of_match = cpu_sandbox_ids,
+ .bind = cpu_sandbox_bind,
.probe = cpu_sandbox_probe,
};
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index b70a206355..ef958b3a7a 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -36,3 +36,5 @@ config ZYNQMP_FIRMWARE
various platform management services.
Say yes to enable ZynqMP firmware interface driver.
If in doubt, say N.
+
+source "drivers/firmware/scmi/Kconfig"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index a0c250a473..7ce83d72bd 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_$(SPL_)ARM_PSCI_FW) += psci.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_SANDBOX) += firmware-sandbox.o
obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o
+obj-$(CONFIG_SCMI_FIRMWARE) += scmi/
diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
new file mode 100644
index 0000000000..c3a109beac
--- /dev/null
+++ b/drivers/firmware/scmi/Kconfig
@@ -0,0 +1,19 @@
+config SCMI_FIRMWARE
+ bool "Enable SCMI support"
+ select FIRMWARE
+ select OF_TRANSLATE
+ depends on SANDBOX || DM_MAILBOX || ARM_SMCCC
+ help
+ System Control and Management Interface (SCMI) is a communication
+ protocol that defines standard interfaces for power, performance
+ and system management. The SCMI specification is available at
+ https://developer.arm.com/architectures/system-architectures/software-standards/scmi
+
+ An SCMI agent communicates with a related SCMI server firmware
+ located in another sub-system, as a companion micro controller
+ or a companion host in the CPU system.
+
+ Communications between agent (client) and the SCMI server are
+ based on message exchange. Messages can be exchange over tranport
+ channels as a mailbox device or an Arm SMCCC service with some
+ piece of identified shared memory.
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
new file mode 100644
index 0000000000..e1e0224066
--- /dev/null
+++ b/drivers/firmware/scmi/Makefile
@@ -0,0 +1,5 @@
+obj-y += scmi_agent-uclass.o
+obj-y += smt.o
+obj-$(CONFIG_ARM_SMCCC) += smccc_agent.o
+obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o
+obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
new file mode 100644
index 0000000000..7d9fb3622e
--- /dev/null
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mailbox.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <dm/devres.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define TIMEOUT_US_10MS 10000
+
+/**
+ * struct scmi_mbox_channel - Description of an SCMI mailbox transport
+ * @smt: Shared memory buffer
+ * @mbox: Mailbox channel description
+ * @timeout_us: Timeout in microseconds for the mailbox transfer
+ */
+struct scmi_mbox_channel {
+ struct scmi_smt smt;
+ struct mbox_chan mbox;
+ ulong timeout_us;
+};
+
+static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_mbox_channel *chan = dev_get_priv(dev);
+ int ret;
+
+ ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
+ if (ret)
+ return ret;
+
+ /* Give shm addr to mbox in case it is meaningful */
+ ret = mbox_send(&chan->mbox, chan->smt.buf);
+ if (ret) {
+ dev_err(dev, "Message send failed: %d\n", ret);
+ goto out;
+ }
+
+ /* Receive the response */
+ ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us);
+ if (ret) {
+ dev_err(dev, "Response failed: %d, abort\n", ret);
+ goto out;
+ }
+
+ ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+
+out:
+ scmi_clear_smt_channel(&chan->smt);
+
+ return ret;
+}
+
+int scmi_mbox_probe(struct udevice *dev)
+{
+ struct scmi_mbox_channel *chan = dev_get_priv(dev);
+ int ret;
+
+ chan->timeout_us = TIMEOUT_US_10MS;
+
+ ret = mbox_get_by_index(dev, 0, &chan->mbox);
+ if (ret) {
+ dev_err(dev, "Failed to find mailbox: %d\n", ret);
+ goto out;
+ }
+
+ ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+ if (ret)
+ dev_err(dev, "Failed to get shm resources: %d\n", ret);
+
+out:
+ if (ret)
+ devm_kfree(dev, chan);
+
+ return ret;
+}
+
+static const struct udevice_id scmi_mbox_ids[] = {
+ { .compatible = "arm,scmi" },
+ { }
+};
+
+static const struct scmi_agent_ops scmi_mbox_ops = {
+ .process_msg = scmi_mbox_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_mbox) = {
+ .name = "scmi-over-mailbox",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = scmi_mbox_ids,
+ .priv_auto_alloc_size = sizeof(struct scmi_mbox_channel),
+ .probe = scmi_mbox_probe,
+ .ops = &scmi_mbox_ops,
+};
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
new file mode 100644
index 0000000000..5b6a4232af
--- /dev/null
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
+#include <asm/io.h>
+#include <asm/scmi_test.h>
+#include <dm/device_compat.h>
+
+/*
+ * The sandbox SCMI agent driver simulates to some extend a SCMI message
+ * 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
+ *
+ * Agent #0 simulates 2 clocks and 1 reset 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.
+ *
+ * This Driver exports sandbox_scmi_service_ct() 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.
+ */
+
+#define SANDBOX_SCMI_AGENT_COUNT 2
+
+static struct sandbox_scmi_clk scmi0_clk[] = {
+ { .id = 7, .rate = 1000 },
+ { .id = 3, .rate = 333 },
+};
+
+static struct sandbox_scmi_reset scmi0_reset[] = {
+ { .id = 3 },
+};
+
+static struct sandbox_scmi_clk scmi1_clk[] = {
+ { .id = 1, .rate = 44 },
+};
+
+/* The list saves to simulted end devices references for test purpose */
+struct sandbox_scmi_agent *sandbox_scmi_agent_list[SANDBOX_SCMI_AGENT_COUNT];
+
+static struct sandbox_scmi_service sandbox_scmi_service_state = {
+ .agent = sandbox_scmi_agent_list,
+ .agent_count = SANDBOX_SCMI_AGENT_COUNT,
+};
+
+struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
+{
+ return &sandbox_scmi_service_state;
+}
+
+static void debug_print_agent_state(struct udevice *dev, char *str)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+
+ dev_dbg(dev, "Dump sandbox_scmi_agent %u: %s\n", agent->idx, str);
+ dev_dbg(dev, " scmi%u_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
+ agent->idx,
+ agent->clk_count,
+ agent->clk_count ? agent->clk[0].enabled : -1,
+ agent->clk_count ? agent->clk[0].rate : -1,
+ agent->clk_count > 1 ? agent->clk[1].enabled : -1,
+ agent->clk_count > 1 ? agent->clk[1].rate : -1,
+ agent->clk_count > 2 ? agent->clk[2].enabled : -1,
+ agent->clk_count > 2 ? agent->clk[2].rate : -1);
+ dev_dbg(dev, " scmi%u_reset (%zu): %d, %d, ...\n",
+ agent->idx,
+ agent->reset_count,
+ agent->reset_count ? agent->reset[0].asserted : -1,
+ agent->reset_count > 1 ? agent->reset[1].asserted : -1);
+};
+
+static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id)
+{
+ struct sandbox_scmi_clk *target = NULL;
+ size_t target_count = 0;
+ size_t n;
+
+ switch (agent_id) {
+ case 0:
+ target = scmi0_clk;
+ target_count = ARRAY_SIZE(scmi0_clk);
+ break;
+ case 1:
+ target = scmi1_clk;
+ target_count = ARRAY_SIZE(scmi1_clk);
+ break;
+ default:
+ return NULL;
+ }
+
+ for (n = 0; n < target_count; n++)
+ if (target[n].id == clock_id)
+ return target + n;
+
+ return NULL;
+}
+
+static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id,
+ uint reset_id)
+{
+ size_t n;
+
+ if (agent_id == 0) {
+ for (n = 0; n < ARRAY_SIZE(scmi0_reset); n++)
+ if (scmi0_reset[n].id == reset_id)
+ return scmi0_reset + n;
+ }
+
+ return NULL;
+}
+
+/*
+ * Sandbox SCMI agent ops
+ */
+
+static int sandbox_scmi_clock_rate_set(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_clk_rate_set_in *in = NULL;
+ struct scmi_clk_rate_set_out *out = NULL;
+ struct sandbox_scmi_clk *clk_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_clk_rate_set_in *)msg->in_msg;
+ out = (struct scmi_clk_rate_set_out *)msg->out_msg;
+
+ clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
+ if (!clk_state) {
+ dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
+
+ clk_state->rate = (ulong)rate;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_clock_rate_get(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_clk_rate_get_in *in = NULL;
+ struct scmi_clk_rate_get_out *out = NULL;
+ struct sandbox_scmi_clk *clk_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_clk_rate_get_in *)msg->in_msg;
+ out = (struct scmi_clk_rate_get_out *)msg->out_msg;
+
+ clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
+ if (!clk_state) {
+ dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ out->rate_msb = (u32)((u64)clk_state->rate >> 32);
+ out->rate_lsb = (u32)clk_state->rate;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_clk_state_in *in = NULL;
+ struct scmi_clk_state_out *out = NULL;
+ struct sandbox_scmi_clk *clk_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_clk_state_in *)msg->in_msg;
+ out = (struct scmi_clk_state_out *)msg->out_msg;
+
+ clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
+ if (!clk_state) {
+ dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else if (in->attributes > 1) {
+ out->status = SCMI_PROTOCOL_ERROR;
+ } else {
+ clk_state->enabled = in->attributes;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_rd_attr_in *in = NULL;
+ struct scmi_rd_attr_out *out = NULL;
+ struct sandbox_scmi_reset *reset_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_rd_attr_in *)msg->in_msg;
+ out = (struct scmi_rd_attr_out *)msg->out_msg;
+
+ reset_state = get_scmi_reset_state(agent->idx, in->domain_id);
+ if (!reset_state) {
+ dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ memset(out, 0, sizeof(*out));
+ snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_rd_reset_in *in = NULL;
+ struct scmi_rd_reset_out *out = NULL;
+ struct sandbox_scmi_reset *reset_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_rd_reset_in *)msg->in_msg;
+ out = (struct scmi_rd_reset_out *)msg->out_msg;
+
+ reset_state = get_scmi_reset_state(agent->idx, in->domain_id);
+ if (!reset_state) {
+ dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else if (in->reset_state > 1) {
+ dev_err(dev, "Invalid reset domain input attribute value\n");
+
+ out->status = SCMI_INVALID_PARAMETERS;
+ } else {
+ if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
+ if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
+ out->status = SCMI_NOT_SUPPORTED;
+ } else {
+ /* Ends deasserted whatever current state */
+ reset_state->asserted = false;
+ out->status = SCMI_SUCCESS;
+ }
+ } else {
+ reset_state->asserted = in->flags &
+ SCMI_RD_RESET_FLAG_ASSERT;
+
+ out->status = SCMI_SUCCESS;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_test_process_msg(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ switch (msg->protocol_id) {
+ case SCMI_PROTOCOL_ID_CLOCK:
+ switch (msg->message_id) {
+ case SCMI_CLOCK_RATE_SET:
+ return sandbox_scmi_clock_rate_set(dev, msg);
+ case SCMI_CLOCK_RATE_GET:
+ return sandbox_scmi_clock_rate_get(dev, msg);
+ case SCMI_CLOCK_CONFIG_SET:
+ return sandbox_scmi_clock_gate(dev, msg);
+ default:
+ break;
+ }
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ switch (msg->message_id) {
+ case SCMI_RESET_DOMAIN_ATTRIBUTES:
+ return sandbox_scmi_rd_attribs(dev, msg);
+ case SCMI_RESET_DOMAIN_RESET:
+ return sandbox_scmi_rd_reset(dev, msg);
+ default:
+ break;
+ }
+ break;
+ case SCMI_PROTOCOL_ID_BASE:
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ case SCMI_PROTOCOL_ID_SYSTEM:
+ case SCMI_PROTOCOL_ID_PERF:
+ case SCMI_PROTOCOL_ID_SENSOR:
+ *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
+ return 0;
+ default:
+ break;
+ }
+
+ dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
+ __func__, dev->name, msg->protocol_id, msg->message_id);
+
+ if (msg->out_msg_sz < sizeof(u32))
+ return -EINVAL;
+
+ /* Intentionnaly report unhandled IDs through the SCMI return code */
+ *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
+ return 0;
+}
+
+static int sandbox_scmi_test_remove(struct udevice *dev)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+
+ debug_print_agent_state(dev, "removed");
+
+ /* We only need to dereference the agent in the context */
+ sandbox_scmi_service_ctx()->agent[agent->idx] = NULL;
+
+ return 0;
+}
+
+static int sandbox_scmi_test_probe(struct udevice *dev)
+{
+ static const char basename[] = "sandbox-scmi-agent@";
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ const size_t basename_size = sizeof(basename) - 1;
+
+ if (strncmp(basename, dev->name, basename_size))
+ return -ENOENT;
+
+ switch (dev->name[basename_size]) {
+ case '0':
+ *agent = (struct sandbox_scmi_agent){
+ .idx = 0,
+ .clk = scmi0_clk,
+ .clk_count = ARRAY_SIZE(scmi0_clk),
+ .reset = scmi0_reset,
+ .reset_count = ARRAY_SIZE(scmi0_reset),
+ };
+ break;
+ case '1':
+ *agent = (struct sandbox_scmi_agent){
+ .idx = 1,
+ .clk = scmi1_clk,
+ .clk_count = ARRAY_SIZE(scmi1_clk),
+ };
+ break;
+ default:
+ dev_err(dev, "%s(): Unexpected agent ID %s\n",
+ __func__, dev->name + basename_size);
+ return -ENOENT;
+ }
+
+ debug_print_agent_state(dev, "probed");
+
+ /* Save reference for tests purpose */
+ sandbox_scmi_service_ctx()->agent[agent->idx] = agent;
+
+ return 0;
+};
+
+static const struct udevice_id sandbox_scmi_test_ids[] = {
+ { .compatible = "sandbox,scmi-agent" },
+ { }
+};
+
+struct scmi_agent_ops sandbox_scmi_test_ops = {
+ .process_msg = sandbox_scmi_test_process_msg,
+};
+
+U_BOOT_DRIVER(sandbox_scmi_agent) = {
+ .name = "sandbox-scmi_agent",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = sandbox_scmi_test_ids,
+ .priv_auto_alloc_size = sizeof(struct sandbox_scmi_agent),
+ .probe = sandbox_scmi_test_probe,
+ .remove = sandbox_scmi_test_remove,
+ .ops = &sandbox_scmi_test_ops,
+};
diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c
new file mode 100644
index 0000000000..c69967bf69
--- /dev/null
+++ b/drivers/firmware/scmi/sandbox-scmi_devices.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020, Linaro Limited
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <asm/scmi_test.h>
+#include <dm/device_compat.h>
+
+/*
+ * Simulate to some extent a SCMI exchange.
+ * This drivers gets SCMI resources and offers API function to the
+ * SCMI test sequence manipulate the resources, currently clock
+ * and reset controllers.
+ */
+
+#define SCMI_TEST_DEVICES_CLK_COUNT 3
+#define SCMI_TEST_DEVICES_RD_COUNT 1
+
+/*
+ * 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
+ * @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 sandbox_scmi_devices devices;
+};
+
+struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev)
+{
+ struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
+
+ if (priv)
+ return &priv->devices;
+
+ return NULL;
+}
+
+static int sandbox_scmi_devices_remove(struct udevice *dev)
+{
+ struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev);
+ int ret = 0;
+ size_t n;
+
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
+ int ret2 = reset_free(devices->reset + n);
+
+ if (ret2 && !ret)
+ ret = ret2;
+ }
+
+ return ret;
+}
+
+static int sandbox_scmi_devices_probe(struct udevice *dev)
+{
+ struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
+ int ret;
+ size_t n;
+
+ priv->devices = (struct sandbox_scmi_devices){
+ .clk = priv->clk,
+ .clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
+ .reset = priv->reset_ctl,
+ .reset_count = SCMI_TEST_DEVICES_RD_COUNT,
+ };
+
+ for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
+ ret = clk_get_by_index(dev, n, priv->devices.clk + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on clk %zu\n", __func__, n);
+ return ret;
+ }
+ }
+
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
+ ret = reset_get_by_index(dev, n, priv->devices.reset + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on reset %zu\n", __func__, n);
+ goto err_reset;
+ }
+ }
+
+ return 0;
+
+err_reset:
+ for (; n > 0; n--)
+ reset_free(priv->devices.reset + n - 1);
+
+ return ret;
+}
+
+static const struct udevice_id sandbox_scmi_devices_ids[] = {
+ { .compatible = "sandbox,scmi-devices" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_scmi_devices) = {
+ .name = "sandbox-scmi_devices",
+ .id = UCLASS_MISC,
+ .of_match = sandbox_scmi_devices_ids,
+ .priv_auto_alloc_size = sizeof(struct sandbox_scmi_device_priv),
+ .remove = sandbox_scmi_devices_remove,
+ .probe = sandbox_scmi_devices_probe,
+};
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
new file mode 100644
index 0000000000..77160b1999
--- /dev/null
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
+
+#include <dm/device-internal.h>
+#include <linux/compat.h>
+
+/**
+ * struct error_code - Helper structure for SCMI error code conversion
+ * @scmi: SCMI error code
+ * @errno: Related standard error number
+ */
+struct error_code {
+ int scmi;
+ int errno;
+};
+
+static const struct error_code scmi_linux_errmap[] = {
+ { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
+ { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
+ { .scmi = SCMI_DENIED, .errno = -EACCES, },
+ { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
+ { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
+ { .scmi = SCMI_BUSY, .errno = -EBUSY, },
+ { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
+ { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
+ { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
+ { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
+};
+
+int scmi_to_linux_errno(s32 scmi_code)
+{
+ int n;
+
+ if (!scmi_code)
+ return 0;
+
+ for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
+ if (scmi_code == scmi_linux_errmap[n].scmi)
+ return scmi_linux_errmap[1].errno;
+
+ return -EPROTO;
+}
+
+/*
+ * SCMI agent devices binds devices of various uclasses depeding on
+ * the FDT description. scmi_bind_protocol() is a generic bind sequence
+ * called by the uclass at bind stage, that is uclass post_bind.
+ */
+static int scmi_bind_protocols(struct udevice *dev)
+{
+ int ret = 0;
+ ofnode node;
+
+ dev_for_each_subnode(node, dev) {
+ struct driver *drv = NULL;
+ u32 protocol_id;
+
+ if (!ofnode_is_available(node))
+ continue;
+
+ if (ofnode_read_u32(node, "reg", &protocol_id))
+ continue;
+
+ switch (protocol_id) {
+ case SCMI_PROTOCOL_ID_CLOCK:
+ if (IS_ENABLED(CONFIG_CLK_SCMI))
+ drv = DM_GET_DRIVER(scmi_clock);
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ if (IS_ENABLED(CONFIG_RESET_SCMI))
+ drv = DM_GET_DRIVER(scmi_reset_domain);
+ break;
+ default:
+ break;
+ }
+
+ if (!drv) {
+ dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
+ protocol_id);
+ continue;
+ }
+
+ ret = device_bind_ofnode(dev, drv, ofnode_get_name(node),
+ NULL, node, NULL);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
+{
+ return (const struct scmi_agent_ops *)dev->driver->ops;
+}
+
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ const struct scmi_agent_ops *ops = transport_dev_ops(dev);
+
+ if (ops->process_msg)
+ return ops->process_msg(dev, msg);
+
+ return -EPROTONOSUPPORT;
+}
+
+UCLASS_DRIVER(scmi_agent) = {
+ .id = UCLASS_SCMI_AGENT,
+ .name = "scmi_agent",
+ .post_bind = scmi_bind_protocols,
+};
diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
new file mode 100644
index 0000000000..85dbf9195e
--- /dev/null
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <dm/devres.h>
+#include <dm/device-internal.h>
+#include <linux/arm-smccc.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define SMCCC_RET_NOT_SUPPORTED ((unsigned long)-1)
+
+/**
+ * struct scmi_smccc_channel - Description of an SCMI SMCCC transport
+ * @func_id: SMCCC function ID used by the SCMI transport
+ * @smt: Shared memory buffer
+ */
+struct scmi_smccc_channel {
+ ulong func_id;
+ struct scmi_smt smt;
+};
+
+static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_smccc_channel *chan = dev_get_priv(dev);
+ struct arm_smccc_res res;
+ int ret;
+
+ ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
+ if (ret)
+ return ret;
+
+ arm_smccc_smc(chan->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+ ret = -ENXIO;
+ else
+ ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+
+ scmi_clear_smt_channel(&chan->smt);
+
+ return ret;
+}
+
+static int scmi_smccc_probe(struct udevice *dev)
+{
+ struct scmi_smccc_channel *chan = dev_get_priv(dev);
+ u32 func_id;
+ int ret;
+
+ if (dev_read_u32(dev, "arm,smc-id", &func_id)) {
+ dev_err(dev, "Missing property func-id\n");
+ return -EINVAL;
+ }
+
+ chan->func_id = func_id;
+
+ ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+ if (ret) {
+ dev_err(dev, "Failed to get smt resources: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id scmi_smccc_ids[] = {
+ { .compatible = "arm,scmi-smc" },
+ { }
+};
+
+static const struct scmi_agent_ops scmi_smccc_ops = {
+ .process_msg = scmi_smccc_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_smccc) = {
+ .name = "scmi-over-smccc",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = scmi_smccc_ids,
+ .priv_auto_alloc_size = sizeof(struct scmi_smccc_channel),
+ .probe = scmi_smccc_probe,
+ .ops = &scmi_smccc_ops,
+};
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
new file mode 100644
index 0000000000..ce8fe49939
--- /dev/null
+++ b/drivers/firmware/scmi/smt.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <asm/cache.h>
+#include <asm/system.h>
+#include <dm/ofnode.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#include "smt.h"
+
+/**
+ * Get shared memory configuration defined by the referred DT phandle
+ * Return with a errno compliant value.
+ */
+int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
+{
+ int ret;
+ struct ofnode_phandle_args args;
+ struct resource resource;
+ fdt32_t faddr;
+ phys_addr_t paddr;
+
+ ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);
+ if (ret)
+ return ret;
+
+ ret = ofnode_read_resource(args.node, 0, &resource);
+ if (ret)
+ return ret;
+
+ 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)) {
+ dev_err(dev, "Shared memory buffer too small\n");
+ return -EINVAL;
+ }
+
+ smt->buf = devm_ioremap(dev, paddr, smt->size);
+ if (!smt->buf)
+ return -ENOMEM;
+
+#ifdef CONFIG_ARM
+ if (dcache_status())
+ mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,
+ smt->size, DCACHE_OFF);
+#endif
+
+ return 0;
+}
+
+/**
+ * Write SCMI message @msg into a SMT shared buffer @smt.
+ * Return 0 on success and with a negative errno in case of error.
+ */
+int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ if ((!msg->in_msg && msg->in_msg_sz) ||
+ (!msg->out_msg && msg->out_msg_sz))
+ return -EINVAL;
+
+ if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+ dev_dbg(dev, "Channel busy\n");
+ return -EBUSY;
+ }
+
+ if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
+ smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
+ dev_dbg(dev, "Buffer too small\n");
+ return -ETOOSMALL;
+ }
+
+ /* Load message in shared memory */
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header);
+ hdr->msg_header = SMT_HEADER_TOKEN(0) |
+ SMT_HEADER_MESSAGE_TYPE(0) |
+ SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
+ SMT_HEADER_MESSAGE_ID(msg->message_id);
+
+ memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
+
+ return 0;
+}
+
+/**
+ * Read SCMI message from a SMT shared buffer @smt and copy it into @msg.
+ * Return 0 on success and with a negative errno in case of error.
+ */
+int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+ dev_err(dev, "Channel unexpectedly busy\n");
+ return -EBUSY;
+ }
+
+ if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
+ dev_err(dev, "Channel error reported, reset channel\n");
+ return -ECOMM;
+ }
+
+ if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) {
+ dev_err(dev, "Buffer to small\n");
+ return -ETOOSMALL;
+ }
+
+ /* Get the data */
+ msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header);
+ memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
+
+ return 0;
+}
+
+/**
+ * Clear SMT flags in shared buffer to allow further message exchange
+ */
+void scmi_clear_smt_channel(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
diff --git a/drivers/firmware/scmi/smt.h b/drivers/firmware/scmi/smt.h
new file mode 100644
index 0000000000..a8c0987bd3
--- /dev/null
+++ b/drivers/firmware/scmi/smt.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+#ifndef SCMI_SMT_H
+#define SCMI_SMT_H
+
+#include <asm/types.h>
+
+/**
+ * struct scmi_smt_header - Description of the shared memory message buffer
+ *
+ * SMT stands for Shared Memory based Transport.
+ * SMT uses 28 byte header prior message payload to handle the state of
+ * the communication channel realized by the shared memory area and
+ * to define SCMI protocol information the payload relates to.
+ */
+struct scmi_smt_header {
+ __le32 reserved;
+ __le32 channel_status;
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1)
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0)
+ __le32 reserved1[2];
+ __le32 flags;
+#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0)
+ __le32 length;
+ __le32 msg_header;
+ u8 msg_payload[0];
+};
+
+#define SMT_HEADER_TOKEN(token) (((token) << 18) & GENMASK(31, 18))
+#define SMT_HEADER_PROTOCOL_ID(proto) (((proto) << 10) & GENMASK(17, 10))
+#define SMT_HEADER_MESSAGE_TYPE(type) (((type) << 18) & GENMASK(9, 8))
+#define SMT_HEADER_MESSAGE_ID(id) ((id) & GENMASK(7, 0))
+
+/**
+ * struct scmi_smt - Description of a SMT memory buffer
+ * @buf: Shared memory base address
+ * @size: Shared memory byte size
+ */
+struct scmi_smt {
+ u8 *buf;
+ size_t size;
+};
+
+static inline bool scmi_smt_channel_is_free(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+}
+
+static inline bool scmi_smt_channel_reports_error(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
+
+static inline void scmi_smt_get_channel(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+}
+
+static inline void scmi_smt_put_channel(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ hdr->channel_status |= SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
+
+int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt);
+
+int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg);
+
+int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg);
+
+void scmi_clear_smt_channel(struct scmi_smt *smt);
+
+#endif /* SCMI_SMT_H */
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index e311f55ef8..a2beb0079d 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -619,7 +619,7 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
return ret;
}
@@ -1591,7 +1591,7 @@ static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
return ret;
}
@@ -1639,7 +1639,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
(u32 *)&req, sizeof(req), sizeof(*resp));
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
- dev_err(dev, "Message alloc failed(%d)\n", ret);
+ dev_err(info->dev, "Message alloc failed(%d)\n", ret);
return ret;
}
@@ -1649,7 +1649,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
goto fail;
}
@@ -1745,7 +1745,7 @@ static int ti_sci_cmd_query_msmc(const struct ti_sci_handle *handle,
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
return ret;
}
@@ -2229,6 +2229,14 @@ static int ti_sci_cmd_proc_shutdown_no_wait(const struct ti_sci_handle *handle,
u8 proc_id)
{
int ret;
+ struct ti_sci_info *info;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ info = handle_to_ti_sci_info(handle);
/*
* Send the core boot status wait message waiting for either WFE or
@@ -2554,7 +2562,8 @@ static int ti_sci_cmd_rm_udmap_rx_flow_cfg(
(u32 *)&req, sizeof(req), sizeof(*resp));
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
- dev_err(dev, "RX_FL_CFG: Message alloc failed(%d)\n", ret);
+ dev_err(info->dev, "RX_FL_CFG: Message alloc failed(%d)\n",
+ ret);
return ret;
}
@@ -2583,7 +2592,7 @@ static int ti_sci_cmd_rm_udmap_rx_flow_cfg(
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "RX_FL_CFG: Mbox send fail %d\n", ret);
+ dev_err(info->dev, "RX_FL_CFG: Mbox send fail %d\n", ret);
goto fail;
}
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 9c53299b6a..0c01413b58 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -6,6 +6,8 @@
#include <common.h>
#include <dm.h>
#include <log.h>
+#include <dm/devres.h>
+#include <dm/device_compat.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/uclass-internal.h>
@@ -1209,6 +1211,75 @@ int gpio_dev_request_index(struct udevice *dev, const char *nodename,
flags, 0, dev);
}
+static void devm_gpiod_release(struct udevice *dev, void *res)
+{
+ dm_gpio_free(dev, res);
+}
+
+static int devm_gpiod_match(struct udevice *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id,
+ unsigned int index, int flags)
+{
+ int rc;
+ struct gpio_desc *desc;
+ char *propname;
+ static const char suffix[] = "-gpios";
+
+ propname = malloc(strlen(id) + sizeof(suffix));
+ if (!propname) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ strcpy(propname, id);
+ strcat(propname, suffix);
+
+ desc = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc),
+ __GFP_ZERO);
+ if (unlikely(!desc)) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = gpio_request_by_name(dev, propname, index, desc, flags);
+
+end:
+ if (propname)
+ free(propname);
+
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, desc);
+
+ return desc;
+}
+
+struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev,
+ const char *id,
+ unsigned int index,
+ int flags)
+{
+ struct gpio_desc *desc = devm_gpiod_get_index(dev, id, index, flags);
+
+ if (IS_ERR(desc))
+ return NULL;
+
+ return desc;
+}
+
+void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_gpiod_release, devm_gpiod_match, desc);
+ WARN_ON(rc);
+}
+
static int gpio_post_bind(struct udevice *dev)
{
struct udevice *child;
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index e3d980a9df..7609594bd0 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -941,7 +941,8 @@ static int mxc_i2c_probe(struct udevice *bus)
*/
ret = fdt_stringlist_search(fdt, node, "pinctrl-names", "gpio");
if (ret < 0) {
- debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n", bus->seq, i2c_bus->base);
+ debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n",
+ bus->seq, i2c_bus->base);
} else {
ret = gpio_request_by_name_nodev(offset_to_ofnode(node),
"scl-gpios", 0, &i2c_bus->scl_gpio,
@@ -952,7 +953,9 @@ static int mxc_i2c_probe(struct udevice *bus)
if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) ||
!dm_gpio_is_valid(&i2c_bus->scl_gpio) ||
ret || ret2) {
- dev_err(dev, "i2c bus %d at %lu, fail to request scl/sda gpio\n", bus->seq, i2c_bus->base);
+ dev_err(bus,
+ "i2c bus %d at %lu, fail to request scl/sda gpio\n",
+ bus->seq, i2c_bus->base);
return -EINVAL;
}
}
diff --git a/drivers/mailbox/k3-sec-proxy.c b/drivers/mailbox/k3-sec-proxy.c
index 3f9afaed32..27ccc6eab0 100644
--- a/drivers/mailbox/k3-sec-proxy.c
+++ b/drivers/mailbox/k3-sec-proxy.c
@@ -212,14 +212,16 @@ static int k3_sec_proxy_send(struct mbox_chan *chan, const void *data)
ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
if (ret) {
- dev_err(dev, "%s: Thread%d verification failed. ret = %d\n",
+ dev_err(chan->dev,
+ "%s: Thread%d verification failed. ret = %d\n",
__func__, spt->id, ret);
return ret;
}
/* Check the message size. */
if (msg->len > spm->desc->max_msg_size) {
- printf("%s: Thread %ld message length %zu > max msg size %d\n",
+ dev_err(chan->dev,
+ "%s: Thread %ld message length %zu > max msg size %d\n",
__func__, chan->id, msg->len, spm->desc->max_msg_size);
return -EINVAL;
}
diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c
index b793028ab5..ea8b385d7e 100644
--- a/drivers/mmc/bcm2835_sdhost.c
+++ b/drivers/mmc/bcm2835_sdhost.c
@@ -185,22 +185,22 @@ struct bcm2835_host {
static void bcm2835_dumpregs(struct bcm2835_host *host)
{
- dev_dbg(dev, "=========== REGISTER DUMP ===========\n");
- dev_dbg(dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD));
- dev_dbg(dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG));
- dev_dbg(dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT));
- dev_dbg(dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV));
- dev_dbg(dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0));
- dev_dbg(dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1));
- dev_dbg(dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2));
- dev_dbg(dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3));
- dev_dbg(dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS));
- dev_dbg(dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD));
- dev_dbg(dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM));
- dev_dbg(dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG));
- dev_dbg(dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT));
- dev_dbg(dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC));
- dev_dbg(dev, "===========================================\n");
+ dev_dbg(host->dev, "=========== REGISTER DUMP ===========\n");
+ dev_dbg(host->dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD));
+ dev_dbg(host->dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG));
+ dev_dbg(host->dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT));
+ dev_dbg(host->dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV));
+ dev_dbg(host->dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0));
+ dev_dbg(host->dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1));
+ dev_dbg(host->dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2));
+ dev_dbg(host->dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3));
+ dev_dbg(host->dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS));
+ dev_dbg(host->dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD));
+ dev_dbg(host->dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM));
+ dev_dbg(host->dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG));
+ dev_dbg(host->dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT));
+ dev_dbg(host->dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC));
+ dev_dbg(host->dev, "===========================================\n");
}
static void bcm2835_reset_internal(struct bcm2835_host *host)
@@ -738,7 +738,7 @@ static void bcm2835_add_host(struct bcm2835_host *host)
cfg->f_min = host->max_clk / SDCDIV_MAX_CDIV;
cfg->b_max = 65535;
- dev_dbg(dev, "f_max %d, f_min %d\n",
+ dev_dbg(host->dev, "f_max %d, f_min %d\n",
cfg->f_max, cfg->f_min);
/* host controller capabilities */
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index bd1fb09d1c..30fe7a0aa2 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -774,7 +774,8 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width)
writel(val, &host->base->sdc_cfg);
}
-static void msdc_set_mclk(struct msdc_host *host, enum bus_mode timing, u32 hz)
+static void msdc_set_mclk(struct udevice *dev,
+ struct msdc_host *host, enum bus_mode timing, u32 hz)
{
u32 mode;
u32 div;
@@ -897,7 +898,7 @@ static int msdc_ops_set_ios(struct udevice *dev)
clock = mmc->cfg->f_min;
if (host->mclk != clock || host->timing != mmc->selected_mode)
- msdc_set_mclk(host, mmc->selected_mode, clock);
+ msdc_set_mclk(dev, host, mmc->selected_mode, clock);
return 0;
}
@@ -957,7 +958,8 @@ static int get_delay_len(u32 delay, u32 start_bit)
return PAD_DELAY_MAX - start_bit;
}
-static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+static struct msdc_delay_phase get_best_delay(struct udevice *dev,
+ struct msdc_host *host, u32 delay)
{
int start = 0, len = 0;
int start_final = 0, len_final = 0;
@@ -1067,7 +1069,7 @@ static int hs400_tune_response(struct udevice *dev, u32 opcode)
}
}
- final_cmd_delay = get_best_delay(host, cmd_delay);
+ final_cmd_delay = get_best_delay(dev, host, cmd_delay);
clrsetbits_le32(tune_reg, PAD_CMD_TUNE_RX_DLY3,
final_cmd_delay.final_phase <<
PAD_CMD_TUNE_RX_DLY3_S);
@@ -1117,7 +1119,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode)
}
}
- final_rise_delay = get_best_delay(host, rise_delay);
+ final_rise_delay = get_best_delay(dev, host, rise_delay);
/* if rising edge has enough margin, do not scan falling edge */
if (final_rise_delay.maxlen >= 12 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
@@ -1139,7 +1141,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode)
}
}
- final_fall_delay = get_best_delay(host, fall_delay);
+ final_fall_delay = get_best_delay(dev, host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
@@ -1171,7 +1173,7 @@ skip_fall:
dev_err(dev, "Final internal delay: 0x%x\n", internal_delay);
- internal_delay_phase = get_best_delay(host, internal_delay);
+ internal_delay_phase = get_best_delay(dev, host, internal_delay);
clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
internal_delay_phase.final_phase <<
MSDC_PAD_TUNE_CMDRRDLY_S);
@@ -1214,7 +1216,7 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
}
}
- final_rise_delay = get_best_delay(host, rise_delay);
+ final_rise_delay = get_best_delay(dev, host, rise_delay);
if (final_rise_delay.maxlen >= 12 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
@@ -1237,7 +1239,7 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
}
}
- final_fall_delay = get_best_delay(host, fall_delay);
+ final_fall_delay = get_best_delay(dev, host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
@@ -1293,7 +1295,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode)
rise_delay |= (1 << i);
}
- final_rise_delay = get_best_delay(host, rise_delay);
+ final_rise_delay = get_best_delay(dev, host, rise_delay);
if (final_rise_delay.maxlen >= 12 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
@@ -1309,7 +1311,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode)
fall_delay |= (1 << i);
}
- final_fall_delay = get_best_delay(host, fall_delay);
+ final_fall_delay = get_best_delay(dev, host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
index 5e95901e27..abc432c862 100644
--- a/drivers/mtd/nand/raw/atmel_nand.c
+++ b/drivers/mtd/nand/raw/atmel_nand.c
@@ -424,7 +424,8 @@ static int pmecc_err_location(struct mtd_info *mtd)
}
if (!timeout) {
- dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n");
+ dev_err(mtd->dev,
+ "Timeout to calculate PMECC error location\n");
return -1;
}
@@ -464,7 +465,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
*(buf + byte_pos) ^= (1 << bit_pos);
pos = sector_num * host->pmecc_sector_size + byte_pos;
- dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+ dev_dbg(mtd->dev,
+ "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, *(buf + byte_pos));
} else {
/* Bit flip in OOB area */
@@ -474,7 +476,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
ecc[tmp] ^= (1 << bit_pos);
pos = tmp + nand_chip->ecc.layout->eccpos[0];
- dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+ dev_dbg(mtd->dev,
+ "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, ecc[tmp]);
}
@@ -516,7 +519,7 @@ normal_check:
err_nbr = pmecc_err_location(mtd);
if (err_nbr == -1) {
- dev_err(host->dev, "PMECC: Too many errors\n");
+ dev_err(mtd->dev, "PMECC: Too many errors\n");
mtd->ecc_stats.failed++;
return -EBADMSG;
} else {
@@ -560,7 +563,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
}
if (!timeout) {
- dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n");
+ dev_err(mtd->dev, "Timeout to read PMECC page\n");
return -1;
}
@@ -600,7 +603,8 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
}
if (!timeout) {
- dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
+ dev_err(mtd->dev,
+ "Timeout to read PMECC status, fail to write PMECC in oob\n");
goto out;
}
@@ -713,7 +717,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
if (*cap == 0 && *sector_size == 0) {
/* Non-ONFI compliant */
- dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n");
+ dev_info(chip->mtd.dev,
+ "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n");
*cap = 2;
*sector_size = 512;
}
@@ -835,17 +840,20 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
* from ONFI.
*/
if (pmecc_choose_ecc(host, nand, &cap, &sector_size)) {
- dev_err(host->dev, "Required ECC %d bits in %d bytes not supported!\n",
+ dev_err(mtd->dev,
+ "Required ECC %d bits in %d bytes not supported!\n",
cap, sector_size);
return -EINVAL;
}
if (cap > host->pmecc_corr_cap)
- dev_info(host->dev, "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n",
- host->pmecc_corr_cap, cap);
+ dev_info(mtd->dev,
+ "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n",
+ host->pmecc_corr_cap, cap);
if (sector_size < host->pmecc_sector_size)
- dev_info(host->dev, "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n",
- host->pmecc_sector_size, sector_size);
+ dev_info(mtd->dev,
+ "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n",
+ host->pmecc_sector_size, sector_size);
#else /* CONFIG_SYS_NAND_ONFI_DETECTION */
host->pmecc_corr_cap = CONFIG_PMECC_CAP;
host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE;
@@ -877,7 +885,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
#if defined(NO_GALOIS_TABLE_IN_ROM)
pmecc_galois_table = create_lookup_table(host->pmecc_sector_size);
if (!pmecc_galois_table) {
- dev_err(host->dev, "out of memory\n");
+ dev_err(mtd->dev, "out of memory\n");
return -ENOMEM;
}
@@ -909,13 +917,14 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
host->pmecc_sector_number;
if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) {
- dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n",
- MTD_MAX_ECCPOS_ENTRIES_LARGE);
+ dev_err(mtd->dev,
+ "too large eccpos entries. max support ecc.bytes is %d\n",
+ MTD_MAX_ECCPOS_ENTRIES_LARGE);
return -EINVAL;
}
if (nand->ecc.bytes > mtd->oobsize - PMECC_OOB_RESERVED_BYTES) {
- dev_err(host->dev, "No room for ECC bytes\n");
+ dev_err(mtd->dev, "No room for ECC bytes\n");
return -EINVAL;
}
pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
@@ -926,7 +935,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
case 512:
case 1024:
/* TODO */
- dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n");
+ dev_err(mtd->dev,
+ "Unsupported page size for PMECC, use Software ECC\n");
default:
/* page size not handled by HW ECC */
/* switching back to soft ECC */
@@ -940,7 +950,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
/* Allocate data for PMECC computation */
if (pmecc_data_alloc(host)) {
- dev_err(host->dev, "Cannot allocate memory for PMECC computation!\n");
+ dev_err(mtd->dev,
+ "Cannot allocate memory for PMECC computation!\n");
return -ENOMEM;
}
@@ -951,7 +962,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
/* Check the PMECC ip version */
host->pmecc_version = pmecc_readl(host->pmerrloc, version);
- dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version);
+ dev_dbg(mtd->dev, "PMECC IP version is: %x\n", host->pmecc_version);
atmel_pmecc_core_init(mtd);
@@ -1114,8 +1125,8 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
/* it doesn't seems to be a freshly
* erased block.
* We can't correct so many errors */
- dev_warn(host->dev, "atmel_nand : multiple errors detected."
- " Unable to correct.\n");
+ dev_warn(mtd->dev,
+ "multiple errors detected. Unable to correct.\n");
return -EBADMSG;
}
@@ -1124,15 +1135,14 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
/* there's nothing much to do here.
* the bit error is on the ECC itself.
*/
- dev_warn(host->dev, "atmel_nand : one bit error on ECC code."
- " Nothing to correct\n");
+ dev_warn(mtd->dev,
+ "one bit error on ECC code. Nothing to correct\n");
return 0;
}
- dev_warn(host->dev, "atmel_nand : one bit error on data."
- " (word offset in the page :"
- " 0x%x bit offset : 0x%x)\n",
- ecc_word, ecc_bit);
+ dev_warn(mtd->dev,
+ "one bit error on data. (word offset in the page : 0x%x bit offset : 0x%x)\n",
+ ecc_word, ecc_bit);
/* correct the error */
if (nand_chip->options & NAND_BUSWIDTH_16) {
/* 16 bits words */
@@ -1141,7 +1151,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
/* 8 bits words */
dat[ecc_word] ^= (1 << ecc_bit);
}
- dev_warn(host->dev, "atmel_nand : error corrected\n");
+ dev_warn(mtd->dev, "error corrected\n");
return 1;
}
@@ -1511,7 +1521,6 @@ void board_nand_init(void)
int i;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
if (atmel_nand_chip_init(i, base_addr[i]))
- dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip",
- i);
+ log_err("atmel_nand: Fail to initialize #%d chip", i);
}
#endif /* CONFIG_SPL_BUILD */
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 48c0ca69de..7349a9bc99 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -956,7 +956,7 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
*/
req = DIV_ROUND_UP(ecc_level * 14, 8);
if (req >= sas) {
- dev_err(&host->pdev->dev,
+ dev_err(host->pdev,
"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
req, sas);
return NULL;
@@ -1012,8 +1012,8 @@ static struct nand_ecclayout *brcmstb_choose_ecc_layout(
layout = brcmnand_create_layout(ecc_level, host);
if (!layout) {
- dev_err(&host->pdev->dev,
- "no proper ecc_layout for this NAND cfg\n");
+ dev_err(host->pdev,
+ "no proper ecc_layout for this NAND cfg\n");
return NULL;
}
@@ -1056,17 +1056,9 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
NAND_CTRL_RDY |
NAND_STATUS_READY |
(wp ? 0 : NAND_STATUS_WP), 0);
-#ifndef __UBOOT__
- if (ret)
- dev_err_ratelimited(&host->pdev->dev,
- "nand #WP expected %s\n",
- wp ? "on" : "off");
-#else
if (ret)
- dev_err(&host->pdev->dev,
- "nand #WP expected %s\n",
- wp ? "on" : "off");
-#endif /* __UBOOT__ */
+ dev_err(host->pdev, "nand #WP expected %s\n",
+ wp ? "on" : "off");
}
}
@@ -2257,7 +2249,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, ofnode dn)
ret = ofnode_read_s32(dn, "reg", &host->cs);
#endif
if (ret) {
- dev_err(&pdev->dev, "can't get chip-select\n");
+ dev_err(pdev, "can't get chip-select\n");
return -ENXIO;
}
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index a30e82166b..5fb3081c83 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -512,7 +512,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
}
if (i == ntypes) {
- dev_err(&info->pdev->dev, "Error: timings not found\n");
+ dev_err(mtd->dev, "Error: timings not found\n");
return -EINVAL;
}
@@ -603,7 +603,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
ts = get_timer(0);
while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) {
if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) {
- dev_err(&info->pdev->dev,
+ dev_err(info->controller.active->mtd.dev,
"Timeout on RDDREQ while draining the FIFO\n");
return;
}
@@ -656,8 +656,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
DIV_ROUND_UP(info->step_spare_size, 4));
break;
default:
- dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
- info->state);
+ dev_err(info->controller.active->mtd.dev,
+ "%s: invalid state %d\n", __func__, info->state);
BUG();
}
@@ -1027,7 +1027,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
default:
exec_cmd = 0;
- dev_err(&info->pdev->dev, "non-supported command %x\n",
+ dev_err(mtd->dev, "non-supported command %x\n",
command);
break;
}
@@ -1087,7 +1087,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
break;
if (get_timer(ts) > CHIP_DELAY_TIMEOUT) {
- dev_err(&info->pdev->dev, "Wait timeout!!!\n");
+ dev_err(mtd->dev, "Wait timeout!!!\n");
return;
}
}
@@ -1180,7 +1180,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
break;
if (get_timer(ts) > CHIP_DELAY_TIMEOUT) {
- dev_err(&info->pdev->dev, "Wait timeout!!!\n");
+ dev_err(mtd->dev, "Wait timeout!!!\n");
return;
}
}
@@ -1426,7 +1426,7 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
break;
if (get_timer(ts) > CHIP_DELAY_TIMEOUT) {
- dev_err(&info->pdev->dev, "Ready timeout!!!\n");
+ dev_err(mtd->dev, "Ready timeout!!!\n");
return NAND_STATUS_FAIL;
}
}
@@ -1633,7 +1633,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
ecc->strength = 16;
} else {
- dev_err(&info->pdev->dev,
+ dev_err(info->controller.active->mtd.dev,
"ECC strength %d at page size %d is not supported\n",
strength, page_size);
return -ENODEV;
@@ -1659,8 +1659,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
return ret;
ret = pxa3xx_nand_sensing(host);
if (ret) {
- dev_info(&info->pdev->dev,
- "There is no chip on cs %d!\n",
+ dev_info(mtd->dev, "There is no chip on cs %d!\n",
info->cs);
return ret;
}
@@ -1676,7 +1675,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
if (!pdata->keep_config) {
ret = pxa3xx_nand_init_timings(host);
if (ret) {
- dev_err(&info->pdev->dev,
+ dev_err(mtd->dev,
"Failed to set timings: %d\n", ret);
return ret;
}
@@ -1720,7 +1719,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
chip->cmdfunc = nand_cmdfunc_extended;
} else {
- dev_err(&info->pdev->dev,
+ dev_err(mtd->dev,
"unsupported page size on this variant\n");
return -ENODEV;
}
@@ -1873,6 +1872,7 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info)
static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
{
+ struct mtd_info *mtd = &info->controller.active->mtd;
struct pxa3xx_nand_platform_data *pdata;
int ret, cs, probe_success;
@@ -1884,7 +1884,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
ret = alloc_nand_resource(info);
if (ret) {
- dev_err(&pdev->dev, "alloc nand resource failed\n");
+ dev_err(mtd->dev, "alloc nand resource failed\n");
return ret;
}
@@ -1901,7 +1901,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
info->cs = cs;
ret = pxa3xx_nand_scan(mtd);
if (ret) {
- dev_info(&pdev->dev, "failed to scan nand at cs %d\n",
+ dev_info(mtd->dev, "failed to scan nand at cs %d\n",
cs);
continue;
}
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 004b6f17a5..12fc065b32 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1226,7 +1226,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
+static int sunxi_nand_chip_set_timings(struct sunxi_nfc *nfc,
+ struct sunxi_nand_chip *chip,
const struct nand_sdr_timings *timings)
{
u32 min_clk_period = 0;
@@ -1349,7 +1350,8 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return 0;
}
-static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip)
+static int sunxi_nand_chip_init_timings(struct sunxi_nfc *nfc,
+ struct sunxi_nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(&chip->nand);
const struct nand_sdr_timings *timings;
@@ -1384,7 +1386,7 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip)
if (IS_ERR(timings))
return PTR_ERR(timings);
- return sunxi_nand_chip_set_timings(chip, timings);
+ return sunxi_nand_chip_set_timings(nfc, chip, timings);
}
static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
@@ -1423,7 +1425,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
}
if (i >= ARRAY_SIZE(strengths)) {
- dev_err(nfc->dev, "unsupported strength\n");
+ dev_err(mtd->dev, "unsupported strength\n");
ret = -ENOTSUPP;
goto err;
}
@@ -1619,7 +1621,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
nsels /= sizeof(u32);
if (!nsels || nsels > 8) {
- dev_err(dev, "invalid reg property size\n");
+ dev_err(nfc->dev, "invalid reg property size\n");
return -EINVAL;
}
@@ -1627,7 +1629,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
(nsels * sizeof(struct sunxi_nand_chip_sel)),
GFP_KERNEL);
if (!chip) {
- dev_err(dev, "could not allocate chip\n");
+ dev_err(nfc->dev, "could not allocate chip\n");
return -ENOMEM;
}
@@ -1641,14 +1643,14 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels);
if (ret) {
- dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret);
return ret;
}
ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb,
nsels);
if (ret) {
- dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret);
return ret;
}
@@ -1656,14 +1658,13 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
int tmp = cs[i];
if (tmp > NFC_MAX_CS) {
- dev_err(dev,
- "invalid reg value: %u (max CS = 7)\n",
- tmp);
+ dev_err(nfc->dev,
+ "invalid reg value: %u (max CS = 7)\n", tmp);
return -EINVAL;
}
if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
- dev_err(dev, "CS %d already assigned\n", tmp);
+ dev_err(nfc->dev, "CS %d already assigned\n", tmp);
return -EINVAL;
}
@@ -1688,15 +1689,15 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
timings = onfi_async_timing_mode_to_sdr_timings(0);
if (IS_ERR(timings)) {
ret = PTR_ERR(timings);
- dev_err(dev,
+ dev_err(nfc->dev,
"could not retrieve timings for ONFI mode 0: %d\n",
ret);
return ret;
}
- ret = sunxi_nand_chip_set_timings(chip, timings);
+ ret = sunxi_nand_chip_set_timings(nfc, chip, timings);
if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
+ dev_err(nfc->dev, "could not configure chip timings: %d\n", ret);
return ret;
}
@@ -1729,27 +1730,27 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
nand->options |= NAND_SUBPAGE_READ;
- ret = sunxi_nand_chip_init_timings(chip);
+ ret = sunxi_nand_chip_init_timings(nfc, chip);
if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
+ dev_err(nfc->dev, "could not configure chip timings: %d\n", ret);
return ret;
}
ret = sunxi_nand_ecc_init(mtd, &nand->ecc);
if (ret) {
- dev_err(dev, "ECC init failed: %d\n", ret);
+ dev_err(nfc->dev, "ECC init failed: %d\n", ret);
return ret;
}
ret = nand_scan_tail(mtd);
if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ dev_err(nfc->dev, "nand_scan_tail failed: %d\n", ret);
return ret;
}
ret = nand_register(devnum, mtd);
if (ret) {
- dev_err(dev, "failed to register mtd device: %d\n", ret);
+ dev_err(nfc->dev, "failed to register mtd device: %d\n", ret);
return ret;
}
@@ -1769,7 +1770,7 @@ static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc)
i++;
if (i > 8) {
- dev_err(dev, "too many NAND chips: %d (max = 8)\n", i);
+ dev_err(nfc->dev, "too many NAND chips: %d (max = 8)\n", i);
return -EINVAL;
}
@@ -1841,7 +1842,7 @@ void sunxi_nand_init(void)
ret = sunxi_nand_chips_init(node, nfc);
if (ret) {
- dev_err(dev, "failed to init nand chips\n");
+ dev_err(nfc->dev, "failed to init nand chips\n");
goto err;
}
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index 52c8a94778..4e6fdc607f 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -152,6 +152,8 @@ enum vf610_nfc_alt_buf {
struct vf610_nfc {
struct nand_chip chip;
+ /* NULL without CONFIG_NAND_VF610_NFC_DT */
+ struct udevice *dev;
void __iomem *regs;
uint buf_offset;
int write_sz;
@@ -631,11 +633,10 @@ struct vf610_nfc_config {
int flash_bbt;
};
-static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
+static int vf610_nfc_nand_init(struct vf610_nfc *nfc, int devnum)
{
- struct mtd_info *mtd;
- struct nand_chip *chip;
- struct vf610_nfc *nfc;
+ struct nand_chip *chip = &nfc->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
int err = 0;
struct vf610_nfc_config cfg = {
.hardware_ecc = 1,
@@ -647,16 +648,6 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
.flash_bbt = 1,
};
- nfc = calloc(1, sizeof(*nfc));
- if (!nfc) {
- printf(KERN_ERR "%s: Memory exhausted!\n", __func__);
- return -ENOMEM;
- }
-
- chip = &nfc->chip;
- nfc->regs = addr;
-
- mtd = nand_to_mtd(chip);
nand_set_controller_data(chip, nfc);
if (cfg.width == 16)
@@ -777,20 +768,23 @@ static const struct udevice_id vf610_nfc_dt_ids[] = {
static int vf610_nfc_dt_probe(struct udevice *dev)
{
struct resource res;
+ struct vf610_nfc *nfc = dev_get_priv(dev);
int ret;
ret = dev_read_resource(dev, 0, &res);
if (ret)
return ret;
- return vf610_nfc_nand_init(0, devm_ioremap(dev, res.start,
- resource_size(&res)));
+ nfc->regs = devm_ioremap(dev, res.start, resource_size(&res));
+ nfc->dev = dev;
+ return vf610_nfc_nand_init(nfc, 0);
}
U_BOOT_DRIVER(vf610_nfc_dt) = {
.name = "vf610-nfc-dt",
.id = UCLASS_MTD,
.of_match = vf610_nfc_dt_ids,
+ .priv_auto_alloc_size = sizeof(struct vf610_nfc),
.probe = vf610_nfc_dt_probe,
};
@@ -809,7 +803,17 @@ void board_nand_init(void)
#else
void board_nand_init(void)
{
- int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE);
+ int err;
+ struct vf610_nfc *nfc;
+
+ nfc = calloc(1, sizeof(*nfc));
+ if (!nfc) {
+ printf("%s: Out of memory\n", __func__);
+ return;
+ }
+
+ nfc->regs = (void __iomem *)CONFIG_SYS_NAND_BASE;
+ err = vf610_nfc_nand_init(nfc, 0);
if (err)
printf("VF610 NAND init failed (err %d)\n", err);
}
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 93371fdde0..8c7e07d463 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -984,13 +984,13 @@ static int spinand_detect(struct spinand_device *spinand)
ret = spinand_manufacturer_detect(spinand);
if (ret) {
- dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
- spinand->id.data);
+ dev_err(spinand->slave->dev, "unknown raw ID %*phN\n",
+ SPINAND_MAX_ID_LEN, spinand->id.data);
return ret;
}
if (nand->memorg.ntargets > 1 && !spinand->select_target) {
- dev_err(dev,
+ dev_err(spinand->slave->dev,
"SPI NANDs with more than one die must implement ->select_target()\n");
return -EINVAL;
}
@@ -1076,7 +1076,7 @@ static int spinand_init(struct spinand_device *spinand)
ret = spinand_manufacturer_init(spinand);
if (ret) {
- dev_err(dev,
+ dev_err(spinand->slave->dev,
"Failed to initialize the SPI NAND chip (err = %d)\n",
ret);
goto err_free_bufs;
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 0113e70037..e16b0e1462 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <log.h>
+#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <linux/bitops.h>
diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index fa26ea33c8..07c8c7b82b 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -55,9 +55,19 @@ static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
int ret;
ret = spi_nor_read_write_reg(nor, &op, val);
- if (ret < 0)
- dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
+ if (ret < 0) {
+ /*
+ * spi_slave does not have a struct udevice member without DM,
+ * so use the bus and cs instead.
+ */
+#if CONFIG_IS_ENABLED(DM_SPI)
+ dev_dbg(nor->spi->dev, "error %d reading %x\n", ret,
code);
+#else
+ log_debug("spi%u.%u: error %d reading %x\n",
+ nor->spi->bus, nor->spi->cs, ret, code);
+#endif
+ }
return ret;
}
@@ -512,7 +522,8 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
/* Check current Quad Enable bit value. */
ret = read_cr(nor);
if (ret < 0) {
- dev_dbg(dev, "error while reading configuration register\n");
+ dev_dbg(nor->dev,
+ "error while reading configuration register\n");
return -EINVAL;
}
@@ -524,7 +535,7 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
/* Keep the current value of the Status Register. */
ret = read_sr(nor);
if (ret < 0) {
- dev_dbg(dev, "error while reading status register\n");
+ dev_dbg(nor->dev, "error while reading status register\n");
return -EINVAL;
}
sr_cr[0] = ret;
@@ -785,7 +796,7 @@ int spi_nor_scan(struct spi_nor *nor)
}
if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
- dev_dbg(dev, "address width is too large: %u\n",
+ dev_dbg(nor->dev, "address width is too large: %u\n",
nor->addr_width);
return -EINVAL;
}
diff --git a/drivers/net/bcm6368-eth.c b/drivers/net/bcm6368-eth.c
index 648fafd3e0..38a2a30fe6 100644
--- a/drivers/net/bcm6368-eth.c
+++ b/drivers/net/bcm6368-eth.c
@@ -249,8 +249,7 @@ static int bcm6368_eth_adjust_link(struct udevice *dev)
/* link changed */
if (!up) {
- dev_info(&priv->pdev->dev, "link DOWN on %s\n",
- port->name);
+ dev_info(dev, "link DOWN on %s\n", port->name);
writeb_be(ETH_PORTOV_ENABLE_MASK,
priv->base + ETH_PORTOV_REG(i));
writeb_be(ETH_PTCTRL_RXDIS_MASK |
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 810a2b95b1..db1102562f 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -26,6 +26,7 @@
* supports a single RGMII PHY. This configuration also has SW control over
* all clock and reset signals to the HW block.
*/
+
#include <common.h>
#include <clk.h>
#include <cpu_func.h>
@@ -1893,8 +1894,7 @@ static phy_interface_t eqos_get_interface_stm32(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev);
- phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
- NULL);
+ phy_mode = dev_read_prop(dev, "phy-mode", NULL);
if (phy_mode)
interface = phy_get_interface_by_name(phy_mode);
@@ -1931,8 +1931,7 @@ static phy_interface_t eqos_get_interface_imx(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev);
- phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
- NULL);
+ phy_mode = dev_read_prop(dev, "phy-mode", NULL);
if (phy_mode)
interface = phy_get_interface_by_name(phy_mode);
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 5676a5b3ba..00bda24f1f 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -551,6 +551,10 @@ static int ftgmac100_probe(struct udevice *dev)
priv->max_speed = pdata->max_speed;
priv->phy_addr = 0;
+#ifdef CONFIG_PHY_ADDR
+ priv->phy_addr = CONFIG_PHY_ADDR;
+#endif
+
ret = clk_enable_bulk(&priv->clks);
if (ret)
goto out;
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index 4c7d06ca40..83f99e5d8a 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -625,9 +625,9 @@ static void mvneta_port_down(struct mvneta_port *pp)
count = 0;
do {
if (count++ >= MVNETA_RX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(pp->dev,
- "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n",
- val);
+ dev_warn(pp->phydev->dev,
+ "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n",
+ val);
break;
}
mdelay(1);
@@ -648,9 +648,9 @@ static void mvneta_port_down(struct mvneta_port *pp)
count = 0;
do {
if (count++ >= MVNETA_TX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(pp->dev,
- "TIMEOUT for TX stopped status=0x%08x\n",
- val);
+ dev_warn(pp->phydev->dev,
+ "TIMEOUT for TX stopped status=0x%08x\n",
+ val);
break;
}
mdelay(1);
@@ -664,9 +664,9 @@ static void mvneta_port_down(struct mvneta_port *pp)
count = 0;
do {
if (count++ >= MVNETA_TX_FIFO_EMPTY_TIMEOUT) {
- netdev_warn(pp->dev,
- "TX FIFO empty timeout status=0x08%x\n",
- val);
+ dev_warn(pp->phydev->dev,
+ "TX FIFO empty timeout status=0x08%x\n",
+ val);
break;
}
mdelay(1);
@@ -949,28 +949,32 @@ static void mvneta_rx_error(struct mvneta_port *pp,
u32 status = rx_desc->status;
if (!mvneta_rxq_desc_is_first_last(status)) {
- netdev_err(pp->dev,
- "bad rx status %08x (buffer oversize), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (buffer oversize), size=%d\n",
+ status, rx_desc->data_size);
return;
}
switch (status & MVNETA_RXD_ERR_CODE_MASK) {
case MVNETA_RXD_ERR_CRC:
- netdev_err(pp->dev, "bad rx status %08x (crc error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (crc error), size=%d\n", status,
+ rx_desc->data_size);
break;
case MVNETA_RXD_ERR_OVERRUN:
- netdev_err(pp->dev, "bad rx status %08x (overrun error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (overrun error), size=%d\n", status,
+ rx_desc->data_size);
break;
case MVNETA_RXD_ERR_LEN:
- netdev_err(pp->dev, "bad rx status %08x (max frame length error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (max frame length error), size=%d\n",
+ status, rx_desc->data_size);
break;
case MVNETA_RXD_ERR_RESOURCE:
- netdev_err(pp->dev, "bad rx status %08x (resource error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (resource error), size=%d\n",
+ status, rx_desc->data_size);
break;
}
}
@@ -1127,8 +1131,8 @@ static int mvneta_setup_rxqs(struct mvneta_port *pp)
for (queue = 0; queue < rxq_number; queue++) {
int err = mvneta_rxq_init(pp, &pp->rxqs[queue]);
if (err) {
- netdev_err(pp->dev, "%s: can't create rxq=%d\n",
- __func__, queue);
+ dev_err(pp->phydev->dev, "%s: can't create rxq=%d\n",
+ __func__, queue);
mvneta_cleanup_rxqs(pp);
return err;
}
@@ -1145,8 +1149,8 @@ static int mvneta_setup_txqs(struct mvneta_port *pp)
for (queue = 0; queue < txq_number; queue++) {
int err = mvneta_txq_init(pp, &pp->txqs[queue]);
if (err) {
- netdev_err(pp->dev, "%s: can't create txq=%d\n",
- __func__, queue);
+ dev_err(pp->phydev->dev, "%s: can't create txq=%d\n",
+ __func__, queue);
mvneta_cleanup_txqs(pp);
return err;
}
@@ -1402,7 +1406,7 @@ static int mvneta_init(struct udevice *dev)
err = mvneta_init2(pp);
if (err < 0) {
- dev_err(&pdev->dev, "can't init eth hal\n");
+ dev_err(dev, "can't init eth hal\n");
return err;
}
@@ -1410,7 +1414,7 @@ static int mvneta_init(struct udevice *dev)
err = mvneta_port_power_up(pp, pp->phy_interface);
if (err < 0) {
- dev_err(&pdev->dev, "can't power up port\n");
+ dev_err(dev, "can't power up port\n");
return err;
}
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index a5747a25ab..8f790a8b44 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -2568,7 +2568,7 @@ static int mvpp2_bm_pool_create(struct udevice *dev,
if (!IS_ALIGNED((unsigned long)bm_pool->virt_addr,
MVPP2_BM_POOL_PTR_ALIGN)) {
- dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n",
+ dev_err(dev, "BM pool %d is not %d bytes aligned\n",
bm_pool->id, MVPP2_BM_POOL_PTR_ALIGN);
return -ENOMEM;
}
@@ -2659,7 +2659,7 @@ static int mvpp2_bm_pools_init(struct udevice *dev,
return 0;
err_unroll_pools:
- dev_err(&pdev->dev, "failed to create BM pool %d, size %d\n", i, size);
+ dev_err(dev, "failed to create BM pool %d, size %d\n", i, size);
for (i = i - 1; i >= 0; i--)
mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]);
return err;
@@ -2773,9 +2773,9 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port,
if (buf_num < 0 ||
(buf_num + bm_pool->buf_num > bm_pool->size)) {
- netdev_err(port->dev,
- "cannot allocate %d buffers for pool %d\n",
- buf_num, bm_pool->id);
+ dev_err(port->phy_dev->dev,
+ "cannot allocate %d buffers for pool %d\n", buf_num,
+ bm_pool->id);
return 0;
}
@@ -2803,7 +2803,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
int num;
if (new_pool->type != MVPP2_BM_FREE && new_pool->type != type) {
- netdev_err(port->dev, "mixing pool types is forbidden\n");
+ dev_err(port->phy_dev->dev, "mixing pool types is forbidden\n");
return NULL;
}
@@ -2834,8 +2834,9 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
/* Allocate buffers for this pool */
num = mvpp2_bm_bufs_add(port, new_pool, pkts_num);
if (num != pkts_num) {
- dev_err(dev, "pool %d: %d of %d allocated\n",
- new_pool->id, num, pkts_num);
+ dev_err(port->phy_dev->dev,
+ "pool %d: %d of %d allocated\n", new_pool->id,
+ num, pkts_num);
return NULL;
}
}
@@ -3344,8 +3345,7 @@ static int gop_port_init(struct mvpp2_port *port)
int num_of_act_lanes;
if (mac_num >= MVPP22_GOP_MAC_NUM) {
- netdev_err(NULL, "%s: illegal port number %d", __func__,
- mac_num);
+ log_err("illegal port number %d", mac_num);
return -1;
}
@@ -3399,8 +3399,8 @@ static int gop_port_init(struct mvpp2_port *port)
break;
default:
- netdev_err(NULL, "%s: Requested port mode (%d) not supported\n",
- __func__, port->phy_interface);
+ log_err("Requested port mode (%d) not supported\n",
+ port->phy_interface);
return -1;
}
@@ -3440,8 +3440,8 @@ static void gop_port_enable(struct mvpp2_port *port, int enable)
break;
default:
- netdev_err(NULL, "%s: Wrong port mode (%d)\n", __func__,
- port->phy_interface);
+ log_err("%s: Wrong port mode (%d)\n", __func__,
+ port->phy_interface);
return;
}
}
@@ -3811,9 +3811,9 @@ static void mvpp2_egress_disable(struct mvpp2_port *port)
delay = 0;
do {
if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(port->dev,
- "Tx stop timed out, status=0x%08x\n",
- reg_data);
+ dev_warn(port->phy_dev->dev,
+ "Tx stop timed out, status=0x%08x\n",
+ reg_data);
break;
}
mdelay(1);
@@ -4261,9 +4261,9 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq)
delay = 0;
do {
if (delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) {
- netdev_warn(port->dev,
- "port %d: cleaning queue %d timed out\n",
- port->id, txq->log_id);
+ dev_warn(port->phy_dev->dev,
+ "port %d: cleaning queue %d timed out\n",
+ port->id, txq->log_id);
break;
}
mdelay(1);
@@ -4430,16 +4430,19 @@ static void mvpp2_rx_error(struct mvpp2_port *port,
switch (status & MVPP2_RXD_ERR_CODE_MASK) {
case MVPP2_RXD_ERR_CRC:
- netdev_err(port->dev, "bad rx status %08x (crc error), size=%zu\n",
- status, sz);
+ dev_err(port->phy_dev->dev,
+ "bad rx status %08x (crc error), size=%zu\n", status,
+ sz);
break;
case MVPP2_RXD_ERR_OVERRUN:
- netdev_err(port->dev, "bad rx status %08x (overrun error), size=%zu\n",
- status, sz);
+ dev_err(port->phy_dev->dev,
+ "bad rx status %08x (overrun error), size=%zu\n",
+ status, sz);
break;
case MVPP2_RXD_ERR_RESOURCE:
- netdev_err(port->dev, "bad rx status %08x (resource error), size=%zu\n",
- status, sz);
+ dev_err(port->phy_dev->dev,
+ "bad rx status %08x (resource error), size=%zu\n",
+ status, sz);
break;
}
}
@@ -4507,8 +4510,8 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
*/
if (phy_dev &&
phy_dev->drv->uid == 0xffffffff) {/* Generic phy */
- netdev_warn(port->dev,
- "Marking phy as invalid, link will not be checked\n");
+ dev_warn(port->phy_dev->dev,
+ "Marking phy as invalid, link will not be checked\n");
/* set phy_addr to invalid value */
port->phyaddr = PHY_MAX_ADDR;
mvpp2_egress_enable(port);
@@ -4519,7 +4522,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
port->phy_dev = phy_dev;
if (!phy_dev) {
- netdev_err(port->dev, "cannot connect to phy\n");
+ dev_err(port->phy_dev->dev, "cannot connect to phy\n");
return;
}
phy_dev->supported &= PHY_GBIT_FEATURES;
@@ -4550,31 +4553,31 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port)
err = mvpp2_prs_mac_da_accept(port->priv, port->id, mac_bcast, true);
if (err) {
- netdev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n");
+ dev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n");
return err;
}
err = mvpp2_prs_mac_da_accept(port->priv, port->id,
port->dev_addr, true);
if (err) {
- netdev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n");
+ dev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n");
return err;
}
err = mvpp2_prs_def_flow(port);
if (err) {
- netdev_err(dev, "mvpp2_prs_def_flow failed\n");
+ dev_err(dev, "mvpp2_prs_def_flow failed\n");
return err;
}
/* Allocate the Rx/Tx queues */
err = mvpp2_setup_rxqs(port);
if (err) {
- netdev_err(port->dev, "cannot allocate Rx queues\n");
+ dev_err(port->phy_dev->dev, "cannot allocate Rx queues\n");
return err;
}
err = mvpp2_setup_txqs(port);
if (err) {
- netdev_err(port->dev, "cannot allocate Tx queues\n");
+ dev_err(port->phy_dev->dev, "cannot allocate Tx queues\n");
return err;
}
@@ -4725,7 +4728,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
int parent;
phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0);
if (phyaddr < 0) {
- dev_err(&pdev->dev, "could not find phy address\n");
+ dev_err(dev, "could not find phy address\n");
return -1;
}
parent = fdt_parent_offset(gd->fdt_blob, phy_node);
@@ -4742,13 +4745,13 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
if (phy_mode_str)
phy_mode = phy_get_interface_by_name(phy_mode_str);
if (phy_mode == -1) {
- dev_err(&pdev->dev, "incorrect phy mode\n");
+ dev_err(dev, "incorrect phy mode\n");
return -EINVAL;
}
id = fdtdec_get_int(gd->fdt_blob, port_node, "port-id", -1);
if (id == -1) {
- dev_err(&pdev->dev, "missing port-id value\n");
+ dev_err(dev, "missing port-id value\n");
return -EINVAL;
}
@@ -4807,7 +4810,7 @@ static int mvpp2_port_probe(struct udevice *dev,
err = mvpp2_port_init(dev, port);
if (err < 0) {
- dev_err(&pdev->dev, "failed to init port %d\n", port->id);
+ dev_err(dev, "failed to init port %d\n", port->id);
return err;
}
mvpp2_port_power_up(port);
@@ -4978,7 +4981,7 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv)
/* Checks for hardware constraints (U-Boot uses only one rxq) */
if ((rxq_number > priv->max_port_rxqs) ||
(txq_number > MVPP2_MAX_TXQ)) {
- dev_err(&pdev->dev, "invalid queue size parameter\n");
+ dev_err(dev, "invalid queue size parameter\n");
return -EINVAL;
}
@@ -5099,7 +5102,7 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp)
err = mvpp2_rx_refill(port, bm_pool, bm, dma_addr);
if (err) {
- netdev_err(port->dev, "failed to refill BM pools\n");
+ dev_err(port->phy_dev->dev, "failed to refill BM pools\n");
return 0;
}
@@ -5345,7 +5348,7 @@ static int mvpp2_probe(struct udevice *dev)
port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"gop-port-id", -1);
if (port->id == -1) {
- dev_err(&pdev->dev, "missing gop-port-id value\n");
+ dev_err(dev, "missing gop-port-id value\n");
return -EINVAL;
}
@@ -5364,7 +5367,7 @@ static int mvpp2_probe(struct udevice *dev)
/* Initialize network controller */
err = mvpp2_init(dev, priv);
if (err < 0) {
- dev_err(&pdev->dev, "failed to initialize controller\n");
+ dev_err(dev, "failed to initialize controller\n");
return err;
}
priv->num_ports = 0;
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 709979f48c..d1a643cf5a 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -157,6 +157,14 @@
#define INT_MEM_DATA_M GENMASK(7, 0)
#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
+/* Extended page GPIO register 13G */
+#define MSCC_CLKOUT_CNTL 13
+#define CLKOUT_ENABLE BIT(15)
+#define CLKOUT_FREQ_MASK GENMASK(14, 13)
+#define CLKOUT_FREQ_25M (0x0 << 13)
+#define CLKOUT_FREQ_50M (0x1 << 13)
+#define CLKOUT_FREQ_125M (0x2 << 13)
+
/* Extended page GPIO register 18G */
#define MSCC_PHY_PROC_CMD 18
#define PROC_CMD_NCOMPLETED BIT(15)
@@ -1168,6 +1176,9 @@ static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
rx_clk_out = RX_CLK_OUT_NORMAL;
break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
/* Set Reg23.12:11=2 */
mac_if = MAC_IF_SELECTION_RGMII;
@@ -1210,13 +1221,84 @@ static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
return 0;
}
+static int vsc8531_vsc8541_clkout_config(struct phy_device *phydev)
+{
+ struct ofnode_phandle_args phandle_args;
+ u32 clkout_rate = 0;
+ u16 reg_val;
+ int retval;
+
+ retval = dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL,
+ 0, 0, &phandle_args);
+ if (!retval)
+ clkout_rate = ofnode_read_u32_default(phandle_args.node,
+ "vsc8531,clk-out-frequency", 0);
+
+ switch (clkout_rate) {
+ case 0:
+ reg_val = 0;
+ break;
+ case 25000000:
+ reg_val = CLKOUT_FREQ_25M | CLKOUT_ENABLE;
+ break;
+ case 50000000:
+ reg_val = CLKOUT_FREQ_50M | CLKOUT_ENABLE;
+ break;
+ case 125000000:
+ reg_val = CLKOUT_FREQ_125M | CLKOUT_ENABLE;
+ break;
+ default:
+ printf("PHY 8530/31 invalid clkout rate %u\n",
+ clkout_rate);
+ return -EINVAL;
+ }
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_GPIO);
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_CLKOUT_CNTL, reg_val);
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_STD);
+
+ return 0;
+}
+
+static int vsc8531_vsc8541_clk_skew_config(struct phy_device *phydev)
+{
+ enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS;
+ enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS;
+ u16 reg_val;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ rx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ tx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXT2);
+ reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
+
+ /* Reg20E2 - Update RGMII RX_Clk Skews. */
+ reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
+ RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
+ /* Reg20E2 - Update RGMII TX_Clk Skews. */
+ reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
+ RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_STD);
+
+ return 0;
+}
+
static int vsc8531_config(struct phy_device *phydev)
{
int retval = -EINVAL;
u16 reg_val;
u16 rmii_clk_out;
- enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
- enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
/* For VSC8530/31 and VSC8540/41 the init scripts are the same */
@@ -1226,6 +1308,9 @@ static int vsc8531_config(struct phy_device *phydev)
switch (phydev->interface) {
case PHY_INTERFACE_MODE_RMII:
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
retval = vsc8531_vsc8541_mac_config(phydev);
if (retval != 0)
return retval;
@@ -1242,19 +1327,12 @@ static int vsc8531_config(struct phy_device *phydev)
/* Default RMII Clk Output to 0=OFF/1=ON */
rmii_clk_out = 0;
+ retval = vsc8531_vsc8541_clk_skew_config(phydev);
+ if (retval != 0)
+ return retval;
+
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_EXT2);
- reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
-
- /* Reg20E2 - Update RGMII RX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
- RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
- /* Reg20E2 - Update RGMII TX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
- RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
-
- phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
-
reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
/* Reg27E2 - Update Clk Slew Rate. */
reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
@@ -1267,6 +1345,11 @@ static int vsc8531_config(struct phy_device *phydev)
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_STD);
+ /* Configure the clk output */
+ retval = vsc8531_vsc8541_clkout_config(phydev);
+ if (retval != 0)
+ return retval;
+
return genphy_config_aneg(phydev);
}
@@ -1275,8 +1358,6 @@ static int vsc8541_config(struct phy_device *phydev)
int retval = -EINVAL;
u16 reg_val;
u16 rmii_clk_out;
- enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
- enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
/* For VSC8530/31 and VSC8540/41 the init scripts are the same */
@@ -1304,17 +1385,12 @@ static int vsc8541_config(struct phy_device *phydev)
/* Default RMII Clk Output to 0=OFF/1=ON */
rmii_clk_out = 0;
+ retval = vsc8531_vsc8541_clk_skew_config(phydev);
+ if (retval != 0)
+ return retval;
+
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_EXT2);
- reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
- /* Reg20E2 - Update RGMII RX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
- RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
- /* Reg20E2 - Update RGMII TX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
- RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
- phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
-
reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
/* Reg27E2 - Update Clk Slew Rate. */
reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
@@ -1327,6 +1403,11 @@ static int vsc8541_config(struct phy_device *phydev)
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_STD);
+ /* Configure the clk output */
+ retval = vsc8531_vsc8541_clkout_config(phydev);
+ if (retval != 0)
+ return retval;
+
return genphy_config_aneg(phydev);
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 09372d7f6b..1fa3667b77 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
+#include <env.h>
#include <command.h>
#include <malloc.h>
#include <net.h>
@@ -185,6 +186,8 @@ static void smc911x_handle_mac_address(struct smc911x_priv *priv)
smc911x_set_mac_csr(priv, ADDRH, addrh);
printf(DRIVERNAME ": MAC %pM\n", m);
+ if (!env_get("ethaddr"))
+ env_set("ethaddr", (const char *)m);
}
static bool smc911x_read_mac_address(struct smc911x_priv *priv)
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 546cc6ccb6..1dae81c7bf 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -663,7 +663,8 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev)
return _sun8i_write_hwaddr(priv, pdata->enetaddr);
}
-static int sun8i_emac_board_setup(struct emac_eth_dev *priv)
+static int sun8i_emac_board_setup(struct udevice *dev,
+ struct emac_eth_dev *priv)
{
int ret;
@@ -833,7 +834,7 @@ static int sun8i_emac_eth_probe(struct udevice *dev)
priv->mac_reg = (void *)pdata->iobase;
- ret = sun8i_emac_board_setup(priv);
+ ret = sun8i_emac_board_setup(dev, priv);
if (ret)
return ret;
@@ -854,7 +855,7 @@ static const struct eth_ops sun8i_emac_eth_ops = {
.stop = sun8i_emac_eth_stop,
};
-static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv)
+static int sun8i_get_ephy_nodes(struct udevice *dev, struct emac_eth_dev *priv)
{
int emac_node, ephy_node, ret, ephy_handle;
@@ -986,7 +987,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
}
if (priv->variant == H3_EMAC) {
- ret = sun8i_get_ephy_nodes(priv);
+ ret = sun8i_get_ephy_nodes(dev, priv);
if (ret)
return ret;
}
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index df18ecc064..8e66ce2461 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -505,7 +505,8 @@ static int _sunxi_emac_eth_send(struct emac_eth_dev *priv, void *packet,
return 0;
}
-static int sunxi_emac_board_setup(struct emac_eth_dev *priv)
+static int sunxi_emac_board_setup(struct udevice *dev,
+ struct emac_eth_dev *priv)
{
struct sunxi_sramc_regs *sram =
(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
@@ -576,7 +577,7 @@ static int sunxi_emac_eth_probe(struct udevice *dev)
return ret;
}
- ret = sunxi_emac_board_setup(priv);
+ ret = sunxi_emac_board_setup(dev, priv);
if (ret)
return ret;
diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c
index d6fefe5306..1c11257839 100644
--- a/drivers/net/ti/cpsw.c
+++ b/drivers/net/ti/cpsw.c
@@ -856,8 +856,14 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave)
ret = phy_set_supported(phydev, slave->data->max_speed);
if (ret)
return ret;
+#if CONFIG_IS_ENABLED(DM_ETH)
dev_dbg(priv->dev, "Port %u speed forced to %uMbit\n",
slave->slave_num + 1, slave->data->max_speed);
+#else
+ log_debug("%s: Port %u speed forced to %uMbit\n",
+ priv->dev->name, slave->slave_num + 1,
+ slave->data->max_speed);
+#endif
}
phydev->advertising = phydev->supported;
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 8da00a259d..d66aa07392 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -84,6 +84,13 @@ config BCM6368_USBH_PHY
help
Support for the Broadcom MIPS BCM6368 USBH PHY.
+config BCM_SR_PCIE_PHY
+ bool "Broadcom Stingray PCIe PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Broadcom Stingray PCIe PHY
+ If unsure, say N.
+
config PHY_DA8XX_USB
tristate "TI DA8xx USB PHY Driver"
depends on PHY && ARCH_DAVINCI
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 009f353baf..8dabefd776 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o
+obj-$(CONFIG_BCM_SR_PCIE_PHY) += phy-bcm-sr-pcie.o
obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o
obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o
obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index f050645044..7b9d3eefc5 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -272,13 +272,15 @@ static int sun4i_usb_phy_init(struct phy *phy)
ret = clk_enable(&usb_phy->clocks);
if (ret) {
- dev_err(dev, "failed to enable usb_%ldphy clock\n", phy->id);
+ dev_err(phy->dev, "failed to enable usb_%ldphy clock\n",
+ phy->id);
return ret;
}
ret = reset_deassert(&usb_phy->resets);
if (ret) {
- dev_err(dev, "failed to deassert usb_%ldreset reset\n", phy->id);
+ dev_err(phy->dev, "failed to deassert usb_%ldreset reset\n",
+ phy->id);
return ret;
}
@@ -338,13 +340,15 @@ static int sun4i_usb_phy_exit(struct phy *phy)
ret = clk_disable(&usb_phy->clocks);
if (ret) {
- dev_err(dev, "failed to disable usb_%ldphy clock\n", phy->id);
+ dev_err(phy->dev, "failed to disable usb_%ldphy clock\n",
+ phy->id);
return ret;
}
ret = reset_assert(&usb_phy->resets);
if (ret) {
- dev_err(dev, "failed to assert usb_%ldreset reset\n", phy->id);
+ dev_err(phy->dev, "failed to assert usb_%ldreset reset\n",
+ phy->id);
return ret;
}
diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c
index 27bff27ff7..5e8ce740cd 100644
--- a/drivers/phy/marvell/comphy_core.c
+++ b/drivers/phy/marvell/comphy_core.c
@@ -98,14 +98,14 @@ static int comphy_probe(struct udevice *dev)
chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node,
"max-lanes", 0);
if (chip_cfg->comphy_lanes_count <= 0) {
- dev_err(&dev->dev, "comphy max lanes is wrong\n");
+ dev_err(dev, "comphy max lanes is wrong\n");
return -EINVAL;
}
chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node,
"mux-bitcount", 0);
if (chip_cfg->comphy_mux_bitcount <= 0) {
- dev_err(&dev->dev, "comphy mux bit count is wrong\n");
+ dev_err(dev, "comphy mux bit count is wrong\n");
return -EINVAL;
}
@@ -124,7 +124,7 @@ static int comphy_probe(struct udevice *dev)
* compatible node is found
*/
if (!chip_cfg->ptr_comphy_chip_init) {
- dev_err(&dev->dev, "comphy: No compatible DT node found\n");
+ dev_err(dev, "comphy: No compatible DT node found\n");
return -ENODEV;
}
diff --git a/drivers/phy/phy-bcm-sr-pcie.c b/drivers/phy/phy-bcm-sr-pcie.c
new file mode 100644
index 0000000000..36c77c4b63
--- /dev/null
+++ b/drivers/phy/phy-bcm-sr-pcie.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Broadcom
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+/* we have up to 8 PAXB based RC. The 9th one is always PAXC */
+#define SR_NR_PCIE_PHYS 8
+
+#define PCIE_PIPEMUX_CFG_OFFSET 0x10c
+#define PCIE_PIPEMUX_SELECT_STRAP GENMASK(3, 0)
+
+#define CDRU_STRAP_DATA_LSW_OFFSET 0x5c
+#define PCIE_PIPEMUX_SHIFT 19
+#define PCIE_PIPEMUX_MASK GENMASK(3, 0)
+
+/**
+ * struct sr_pcie_phy_core - Stingray PCIe PHY core control
+ *
+ * @dev: pointer to device
+ * @base: base register of PCIe SS
+ * @cdru: CDRU base address
+ * @pipemux: pipemuex strap
+ */
+struct sr_pcie_phy_core {
+ struct udevice *dev;
+ void __iomem *base;
+ void __iomem *cdru;
+ u32 pipemux;
+};
+
+/*
+ * PCIe PIPEMUX lookup table
+ *
+ * Each array index represents a PIPEMUX strap setting
+ * The array element represents a bitmap where a set bit means the PCIe
+ * core and associated serdes has been enabled as RC and is available for use
+ */
+static const u8 pipemux_table[] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ 0x00,
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ 0x80,
+ /* PIPEMUX = 2, EP 4x4 */
+ 0x00,
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ 0x81,
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ 0xc3,
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ 0xff,
+ /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+ 0xcd,
+ /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+ 0xfd,
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+ 0xf0,
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+ 0xc0,
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+ 0x42,
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+ 0x3c,
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+ 0xfc,
+ /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+ 0x4c,
+};
+
+/*
+ * Return true if the strap setting is valid
+ */
+static bool pipemux_strap_is_valid(u32 pipemux)
+{
+ return !!(pipemux < ARRAY_SIZE(pipemux_table));
+}
+
+/*
+ * Read the PCIe PIPEMUX from strap
+ */
+static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
+{
+ u32 pipemux;
+
+ /*
+ * Read PIPEMUX configuration register to determine the pipemux setting
+ *
+ * In the case when the value indicates using HW strap, fall back to
+ * use HW strap
+ */
+ pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
+ pipemux &= PCIE_PIPEMUX_MASK;
+ if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
+ pipemux = readl(core->cdru + CDRU_STRAP_DATA_LSW_OFFSET);
+ pipemux >>= PCIE_PIPEMUX_SHIFT;
+ pipemux &= PCIE_PIPEMUX_MASK;
+ }
+
+ return pipemux;
+}
+
+static int sr_pcie_phy_init(struct phy *phy)
+{
+ struct sr_pcie_phy_core *core = dev_get_priv(phy->dev);
+ unsigned int core_idx = phy->id;
+
+ debug("%s %lx\n", __func__, phy->id);
+ /*
+ * Check whether this PHY is for root complex or not. If yes, return
+ * zero so the host driver can proceed to enumeration. If not, return
+ * an error and that will force the host driver to bail out
+ */
+ if (!!((pipemux_table[core->pipemux] >> core_idx) & 0x1))
+ return 0;
+
+ return -ENODEV;
+}
+
+static int sr_pcie_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ debug("%s %d\n", __func__, args->args[0]);
+ if (args->args_count && args->args[0] < SR_NR_PCIE_PHYS)
+ phy->id = args->args[0];
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct phy_ops sr_pcie_phy_ops = {
+ .of_xlate = sr_pcie_phy_xlate,
+ .init = sr_pcie_phy_init,
+};
+
+static int sr_pcie_phy_probe(struct udevice *dev)
+{
+ struct sr_pcie_phy_core *core = dev_get_priv(dev);
+
+ core->dev = dev;
+
+ core->base = (void __iomem *)devfdt_get_addr_name(dev, "reg_base");
+ core->cdru = (void __iomem *)devfdt_get_addr_name(dev, "cdru_base");
+ debug("ip base %p\n", core->base);
+ debug("cdru base %p\n", core->cdru);
+
+ /* read the PCIe PIPEMUX strap setting */
+ core->pipemux = pipemux_strap_read(core);
+ if (!pipemux_strap_is_valid(core->pipemux)) {
+ pr_err("invalid PCIe PIPEMUX strap %u\n", core->pipemux);
+ return -EIO;
+ }
+ debug("%s %#x\n", __func__, core->pipemux);
+
+ pr_info("Stingray PCIe PHY driver initialized\n");
+
+ return 0;
+}
+
+static const struct udevice_id sr_pcie_phy_match_table[] = {
+ { .compatible = "brcm,sr-pcie-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(sr_pcie_phy) = {
+ .name = "sr-pcie-phy",
+ .id = UCLASS_PHY,
+ .probe = sr_pcie_phy_probe,
+ .of_match = sr_pcie_phy_match_table,
+ .ops = &sr_pcie_phy_ops,
+ .platdata_auto_alloc_size = sizeof(struct sr_pcie_phy_core),
+ .priv_auto_alloc_size = sizeof(struct sr_pcie_phy_core),
+};
diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c
index c6d3048602..9d4296d649 100644
--- a/drivers/phy/phy-stm32-usbphyc.c
+++ b/drivers/phy/phy-stm32-usbphyc.c
@@ -311,7 +311,7 @@ static int stm32_usbphyc_of_xlate(struct phy *phy,
if ((phy->id == 0 && args->args_count != 1) ||
(phy->id == 1 && args->args_count != 2)) {
- dev_err(dev, "invalid number of cells for phy port%ld\n",
+ dev_err(phy->dev, "invalid number of cells for phy port%ld\n",
phy->id);
return -EINVAL;
}
diff --git a/drivers/phy/phy-ti-am654.c b/drivers/phy/phy-ti-am654.c
index 6907c1afb3..cc73760c8b 100644
--- a/drivers/phy/phy-ti-am654.c
+++ b/drivers/phy/phy-ti-am654.c
@@ -318,13 +318,13 @@ static int serdes_am654_of_xlate(struct phy *x,
struct serdes_am654 *phy = dev_get_priv(x->dev);
if (args->args_count != 2) {
- dev_err(phy->dev, "Invalid DT PHY argument count: %d\n",
+ dev_err(x->dev, "Invalid DT PHY argument count: %d\n",
args->args_count);
return -EINVAL;
}
if (args->args[0] != PHY_TYPE_PCIE) {
- dev_err(phy->dev, "Unrecognized PHY type: %d\n",
+ dev_err(x->dev, "Unrecognized PHY type: %d\n",
args->args[0]);
return -EINVAL;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c
index 83928cffe0..617943fd82 100644
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -98,7 +98,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
ret = reset_deassert(&priv->phy_rst);
if (ret) {
- dev_err(dev, "failed to assert phy reset\n");
+ dev_err(phy->dev, "failed to assert phy reset\n");
return ret;
}
@@ -119,7 +119,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
20 * 1000,
50);
if (ret) {
- dev_err(&priv->dev, "pll lock timeout!\n");
+ dev_err(phy->dev, "pll lock timeout!\n");
goto err_pll_lock;
}
@@ -133,7 +133,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
20 * 1000,
50);
if (ret) {
- dev_err(&priv->dev, "pll output enable timeout!\n");
+ dev_err(phy->dev, "pll output enable timeout!\n");
goto err_pll_lock;
}
@@ -149,7 +149,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
20 * 1000,
50);
if (ret) {
- dev_err(&priv->dev, "pll relock timeout!\n");
+ dev_err(phy->dev, "pll relock timeout!\n");
goto err_pll_lock;
}
@@ -173,7 +173,7 @@ static int rockchip_pcie_phy_power_off(struct phy *phy)
ret = reset_assert(&priv->phy_rst);
if (ret) {
- dev_err(dev, "failed to assert phy reset\n");
+ dev_err(phy->dev, "failed to assert phy reset\n");
return ret;
}
@@ -187,13 +187,13 @@ static int rockchip_pcie_phy_init(struct phy *phy)
ret = clk_enable(&priv->refclk);
if (ret) {
- dev_err(dev, "failed to enable refclk clock\n");
+ dev_err(phy->dev, "failed to enable refclk clock\n");
return ret;
}
ret = reset_assert(&priv->phy_rst);
if (ret) {
- dev_err(dev, "failed to assert phy reset\n");
+ dev_err(phy->dev, "failed to assert phy reset\n");
goto err_reset;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index c9c8e1c542..da00daa447 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -448,7 +448,7 @@ static void rockchip_tcphy_rx_usb3_cfg_lane(struct rockchip_tcphy *priv,
writel(0xfb, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane));
}
-static int rockchip_tcphy_init(struct rockchip_tcphy *priv)
+static int rockchip_tcphy_init(struct phy *phy, struct rockchip_tcphy *priv)
{
const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs;
u32 val;
@@ -559,9 +559,9 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
return 0;
if (priv->mode == MODE_DISCONNECT) {
- ret = rockchip_tcphy_init(priv);
+ ret = rockchip_tcphy_init(phy, priv);
if (ret) {
- dev_err(dev, "failed to init tcphy (ret=%d)\n", ret);
+ dev_err(phy->dev, "failed to init tcphy (ret=%d)\n", ret);
return ret;
}
}
diff --git a/drivers/ram/sifive/fu540_ddr.c b/drivers/ram/sifive/fu540_ddr.c
index 5ff88692a8..60d4945f84 100644
--- a/drivers/ram/sifive/fu540_ddr.c
+++ b/drivers/ram/sifive/fu540_ddr.c
@@ -11,7 +11,6 @@
#include <fdtdec.h>
#include <init.h>
#include <ram.h>
-#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <clk.h>
@@ -339,17 +338,12 @@ static int fu540_ddr_probe(struct udevice *dev)
priv->info.size = gd->ram_size;
#if defined(CONFIG_SPL_BUILD)
- struct regmap *map;
int ret;
u32 clock = 0;
debug("FU540 DDR probe\n");
priv->dev = dev;
- ret = regmap_init_mem(dev_ofnode(dev), &map);
- if (ret)
- return ret;
-
ret = clk_get_by_index(dev, 0, &priv->ddr_clk);
if (ret) {
debug("clk get failed %d\n", ret);
@@ -369,9 +363,14 @@ static int fu540_ddr_probe(struct udevice *dev)
}
ret = clk_enable(&priv->ddr_clk);
- priv->ctl = regmap_get_range(map, 0);
- priv->phy = regmap_get_range(map, 1);
- priv->physical_filter_ctrl = regmap_get_range(map, 2);
+ if (ret < 0) {
+ debug("Could not enable DDR clock\n");
+ return ret;
+ }
+
+ priv->ctl = (struct fu540_ddrctl *)dev_read_addr_index(dev, 0);
+ priv->phy = (struct fu540_ddrphy *)dev_read_addr_index(dev, 1);
+ priv->physical_filter_ctrl = (u32 *)dev_read_addr_index(dev, 2);
return fu540_ddr_setup(dev);
#endif
diff --git a/drivers/remoteproc/k3_system_controller.c b/drivers/remoteproc/k3_system_controller.c
index 54209fccb3..702d98d1a8 100644
--- a/drivers/remoteproc/k3_system_controller.c
+++ b/drivers/remoteproc/k3_system_controller.c
@@ -100,7 +100,7 @@ void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw,
fw->buffer_size = size;
}
-static int k3_sysctrler_load_response(u32 *buf)
+static int k3_sysctrler_load_response(struct udevice *dev, u32 *buf)
{
struct k3_sysctrler_load_msg *fw;
@@ -129,7 +129,8 @@ static int k3_sysctrler_load_response(u32 *buf)
return 0;
}
-static int k3_sysctrler_boot_notification_response(u32 *buf)
+static int k3_sysctrler_boot_notification_response(struct udevice *dev,
+ u32 *buf)
{
struct k3_sysctrler_boot_notification_msg *boot;
@@ -193,7 +194,7 @@ static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size)
}
/* Process the response */
- ret = k3_sysctrler_load_response(msg.buf);
+ ret = k3_sysctrler_load_response(dev, msg.buf);
if (ret)
return ret;
@@ -230,7 +231,7 @@ static int k3_sysctrler_start(struct udevice *dev)
}
/* Process the response */
- ret = k3_sysctrler_boot_notification_response(msg.buf);
+ ret = k3_sysctrler_boot_notification_response(dev, msg.buf);
if (ret)
return ret;
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
index c464ecebb7..b185a6cafb 100644
--- a/drivers/remoteproc/rproc-elf-loader.c
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -158,22 +158,6 @@ int rproc_elf64_sanity_check(ulong addr, ulong size)
return 0;
}
-/* Basic function to verify ELF image format */
-int rproc_elf_sanity_check(ulong addr, ulong size)
-{
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
-
- if (!addr) {
- dev_err(dev, "Invalid firmware address\n");
- return -EFAULT;
- }
-
- if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
- return rproc_elf64_sanity_check(addr, size);
- else
- return rproc_elf32_sanity_check(addr, size);
-}
-
int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index 8e21a38be7..9332a63d21 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -165,7 +165,7 @@ static int k3_r5f_lockstep_release(struct k3_r5f_cluster *cluster)
{
int ret, c;
- dev_dbg(dev, "%s\n", __func__);
+ debug("%s\n", __func__);
for (c = NR_CORES - 1; c >= 0; c--) {
ret = ti_sci_proc_power_domain_on(&cluster->cores[c]->tsp);
@@ -201,7 +201,7 @@ static int k3_r5f_split_release(struct k3_r5f_core *core)
{
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
ret = ti_sci_proc_power_domain_on(&core->tsp);
if (ret) {
@@ -246,25 +246,29 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core)
struct k3_r5f_cluster *cluster = core->cluster;
if (core->in_use) {
- dev_err(dev, "Invalid op: Trying to load/start on already running core %d\n",
+ dev_err(core->dev,
+ "Invalid op: Trying to load/start on already running core %d\n",
core->tsp.proc_id);
return -EINVAL;
}
if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !cluster->cores[1]) {
- printf("Secondary core is not probed in this cluster\n");
+ dev_err(core->dev,
+ "Secondary core is not probed in this cluster\n");
return -EAGAIN;
}
if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !is_primary_core(core)) {
- dev_err(dev, "Invalid op: Trying to start secondary core %d in lockstep mode\n",
+ dev_err(core->dev,
+ "Invalid op: Trying to start secondary core %d in lockstep mode\n",
core->tsp.proc_id);
return -EINVAL;
}
if (cluster->mode == CLUSTER_MODE_SPLIT && !is_primary_core(core)) {
if (!core->cluster->cores[0]->in_use) {
- dev_err(dev, "Invalid seq: Enable primary core before loading secondary core\n");
+ dev_err(core->dev,
+ "Invalid seq: Enable primary core before loading secondary core\n");
return -EINVAL;
}
}
@@ -432,7 +436,7 @@ static int k3_r5f_split_reset(struct k3_r5f_core *core)
{
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
if (reset_assert(&core->reset))
ret = -EINVAL;
@@ -447,7 +451,7 @@ static int k3_r5f_lockstep_reset(struct k3_r5f_cluster *cluster)
{
int ret = 0, c;
- dev_dbg(dev, "%s\n", __func__);
+ debug("%s\n", __func__);
for (c = 0; c < NR_CORES; c++)
if (reset_assert(&cluster->cores[c]->reset))
@@ -579,7 +583,7 @@ static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
u64 boot_vec = 0;
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
ret = ti_sci_proc_request(&core->tsp);
if (ret < 0)
@@ -672,7 +676,7 @@ static int k3_r5f_of_to_priv(struct k3_r5f_core *core)
{
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
core->atcm_enable = dev_read_u32_default(core->dev, "atcm-enable", 0);
core->btcm_enable = dev_read_u32_default(core->dev, "btcm-enable", 1);
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 3fdfe4a6cb..b60e11f98b 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -181,4 +181,12 @@ config RESET_RASPBERRYPI
relevant. This driver provides a reset controller capable of
interfacing with RPi4's co-processor and model these firmware
initialization routines as reset lines.
+
+config RESET_SCMI
+ bool "Enable SCMI reset domain driver"
+ select SCMI_FIRMWARE
+ help
+ Enable this option if you want to support reset controller
+ devices exposed by a SCMI agent based on SCMI reset domain
+ protocol communication with a SCMI server.
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 5176da5885..10a7973f82 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_RESET_IPQ419) += reset-ipq4019.o
obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o
obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o
obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
+obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
new file mode 100644
index 0000000000..1bff8075ee
--- /dev/null
+++ b/drivers/reset/reset-scmi.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2020 Linaro Limited
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset-uclass.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+
+static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
+{
+ struct scmi_rd_reset_in in = {
+ .domain_id = rst->id,
+ .flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0,
+ .reset_state = 0,
+ };
+ struct scmi_rd_reset_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ SCMI_RESET_DOMAIN_RESET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(rst->dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_reset_assert(struct reset_ctl *rst)
+{
+ return scmi_reset_set_level(rst, true);
+}
+
+static int scmi_reset_deassert(struct reset_ctl *rst)
+{
+ return scmi_reset_set_level(rst, false);
+}
+
+static int scmi_reset_request(struct reset_ctl *rst)
+{
+ struct scmi_rd_attr_in in = {
+ .domain_id = rst->id,
+ };
+ struct scmi_rd_attr_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ SCMI_RESET_DOMAIN_ATTRIBUTES,
+ in, out);
+ int ret;
+
+ /*
+ * We don't really care about the attribute, just check
+ * the reset domain exists.
+ */
+ ret = devm_scmi_process_msg(rst->dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_reset_rfree(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static const struct reset_ops scmi_reset_domain_ops = {
+ .request = scmi_reset_request,
+ .rfree = scmi_reset_rfree,
+ .rst_assert = scmi_reset_assert,
+ .rst_deassert = scmi_reset_deassert,
+};
+
+U_BOOT_DRIVER(scmi_reset_domain) = {
+ .name = "scmi_reset_domain",
+ .id = UCLASS_RESET,
+ .ops = &scmi_reset_domain_ops,
+};
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index 5e38ce5c06..e7e407ca35 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -11,6 +11,7 @@
#include <reset.h>
#include <reset-uclass.h>
#include <dm/devres.h>
+#include <dm/lists.h>
static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
{
@@ -100,13 +101,14 @@ int reset_get_by_index_nodev(ofnode node, int index,
index > 0, reset_ctl);
}
-int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+static int __reset_get_bulk(struct udevice *dev, ofnode node,
+ struct reset_ctl_bulk *bulk)
{
int i, ret, err, count;
-
+
bulk->count = 0;
- count = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
+ count = ofnode_count_phandle_with_args(node, "resets", "#reset-cells");
if (count < 1)
return count;
@@ -116,7 +118,7 @@ int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
return -ENOMEM;
for (i = 0; i < count; i++) {
- ret = reset_get_by_index(dev, i, &bulk->resets[i]);
+ ret = reset_get_by_index_nodev(node, i, &bulk->resets[i]);
if (ret < 0)
goto bulk_get_err;
@@ -134,6 +136,11 @@ bulk_get_err:
return ret;
}
+int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+{
+ return __reset_get_bulk(dev, dev_ofnode(dev), bulk);
+}
+
int reset_get_by_name(struct udevice *dev, const char *name,
struct reset_ctl *reset_ctl)
{
@@ -246,6 +253,109 @@ int reset_release_all(struct reset_ctl *reset_ctl, int count)
return 0;
}
+static void devm_reset_release(struct udevice *dev, void *res)
+{
+ reset_free(res);
+}
+
+struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev,
+ int index)
+{
+ int rc;
+ struct reset_ctl *reset_ctl;
+
+ reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl),
+ __GFP_ZERO);
+ if (unlikely(!reset_ctl))
+ return ERR_PTR(-ENOMEM);
+
+ rc = reset_get_by_index(dev, index, reset_ctl);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, reset_ctl);
+ return reset_ctl;
+}
+
+struct reset_ctl *devm_reset_control_get(struct udevice *dev, const char *id)
+{
+ int rc;
+ struct reset_ctl *reset_ctl;
+
+ reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl),
+ __GFP_ZERO);
+ if (unlikely(!reset_ctl))
+ return ERR_PTR(-ENOMEM);
+
+ rc = reset_get_by_name(dev, id, reset_ctl);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, reset_ctl);
+ return reset_ctl;
+}
+
+struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev,
+ const char *id)
+{
+ struct reset_ctl *r = devm_reset_control_get(dev, id);
+
+ if (IS_ERR(r))
+ return NULL;
+
+ return r;
+}
+
+static void devm_reset_bulk_release(struct udevice *dev, void *res)
+{
+ struct reset_ctl_bulk *bulk = res;
+
+ reset_release_all(bulk->resets, bulk->count);
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev,
+ ofnode node)
+{
+ int rc;
+ struct reset_ctl_bulk *bulk;
+
+ bulk = devres_alloc(devm_reset_bulk_release,
+ sizeof(struct reset_ctl_bulk),
+ __GFP_ZERO);
+ if (unlikely(!bulk))
+ return ERR_PTR(-ENOMEM);
+
+ rc = __reset_get_bulk(dev, node, bulk);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, bulk);
+ return bulk;
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev,
+ ofnode node)
+{
+ struct reset_ctl_bulk *bulk;
+
+ bulk = devm_reset_bulk_get_by_node(dev, node);
+
+ if (IS_ERR(bulk))
+ return NULL;
+
+ return bulk;
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev)
+{
+ return devm_reset_bulk_get_by_node(dev, dev_ofnode(dev));
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev)
+{
+ return devm_reset_bulk_get_optional_by_node(dev, dev_ofnode(dev));
+}
+
UCLASS_DRIVER(reset) = {
.id = UCLASS_RESET,
.name = "reset",
diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c
index 9bc4a7e0de..10e02f1036 100644
--- a/drivers/reset/sandbox-reset-test.c
+++ b/drivers/reset/sandbox-reset-test.c
@@ -10,66 +10,105 @@
#include <reset.h>
#include <asm/io.h>
#include <asm/reset.h>
+#include <linux/err.h>
struct sandbox_reset_test {
struct reset_ctl ctl;
struct reset_ctl_bulk bulk;
+
+ struct reset_ctl *ctlp;
+ struct reset_ctl_bulk *bulkp;
};
int sandbox_reset_test_get(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ sbrt->ctlp = &sbrt->ctl;
return reset_get_by_name(dev, "test", &sbrt->ctl);
}
+int sandbox_reset_test_get_devm(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ struct reset_ctl *r;
+
+ r = devm_reset_control_get(dev, "not-a-valid-reset-ctl");
+ if (!IS_ERR(r))
+ return -EINVAL;
+
+ r = devm_reset_control_get_optional(dev, "not-a-valid-reset-ctl");
+ if (r)
+ return -EINVAL;
+
+ sbrt->ctlp = devm_reset_control_get(dev, "test");
+ if (IS_ERR(sbrt->ctlp))
+ return PTR_ERR(sbrt->ctlp);
+
+ return 0;
+}
+
int sandbox_reset_test_get_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ sbrt->bulkp = &sbrt->bulk;
return reset_get_bulk(dev, &sbrt->bulk);
}
+int sandbox_reset_test_get_bulk_devm(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ struct reset_ctl_bulk *r;
+
+ r = devm_reset_bulk_get_optional(dev);
+ if (IS_ERR(r))
+ return PTR_ERR(r);
+
+ sbrt->bulkp = r;
+ return 0;
+}
+
int sandbox_reset_test_assert(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_assert(&sbrt->ctl);
+ return reset_assert(sbrt->ctlp);
}
int sandbox_reset_test_assert_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_assert_bulk(&sbrt->bulk);
+ return reset_assert_bulk(sbrt->bulkp);
}
int sandbox_reset_test_deassert(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_deassert(&sbrt->ctl);
+ return reset_deassert(sbrt->ctlp);
}
int sandbox_reset_test_deassert_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_deassert_bulk(&sbrt->bulk);
+ return reset_deassert_bulk(sbrt->bulkp);
}
int sandbox_reset_test_free(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_free(&sbrt->ctl);
+ return reset_free(sbrt->ctlp);
}
int sandbox_reset_test_release_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_release_bulk(&sbrt->bulk);
+ return reset_release_bulk(sbrt->bulkp);
}
static const struct udevice_id sandbox_reset_test_ids[] = {
diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c
index 7a6f7f676c..08008d875a 100644
--- a/drivers/reset/sandbox-reset.c
+++ b/drivers/reset/sandbox-reset.c
@@ -15,6 +15,7 @@
struct sandbox_reset_signal {
bool asserted;
+ bool requested;
};
struct sandbox_reset {
@@ -23,18 +24,24 @@ struct sandbox_reset {
static int sandbox_reset_request(struct reset_ctl *reset_ctl)
{
+ struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev);
+
debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
if (reset_ctl->id >= SANDBOX_RESET_SIGNALS)
return -EINVAL;
+ sbr->signals[reset_ctl->id].requested = true;
return 0;
}
static int sandbox_reset_free(struct reset_ctl *reset_ctl)
{
+ struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev);
+
debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
+ sbr->signals[reset_ctl->id].requested = false;
return 0;
}
@@ -107,3 +114,15 @@ int sandbox_reset_query(struct udevice *dev, unsigned long id)
return sbr->signals[id].asserted;
}
+
+int sandbox_reset_is_requested(struct udevice *dev, unsigned long id)
+{
+ struct sandbox_reset *sbr = dev_get_priv(dev);
+
+ debug("%s(dev=%p, id=%ld)\n", __func__, dev, id);
+
+ if (id >= SANDBOX_RESET_SIGNALS)
+ return -EINVAL;
+
+ return sbr->signals[id].requested;
+}
diff --git a/drivers/smem/msm_smem.c b/drivers/smem/msm_smem.c
index 2557269bc5..597d425d11 100644
--- a/drivers/smem/msm_smem.c
+++ b/drivers/smem/msm_smem.c
@@ -879,7 +879,7 @@ static int qcom_smem_probe(struct udevice *dev)
header = smem->regions[0].virt_base;
if (le32_to_cpu(header->initialized) != 1 ||
le32_to_cpu(header->reserved)) {
- dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
+ dev_err(dev, "SMEM is not initialized by SBL\n");
return -EINVAL;
}
diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
index cd2e17bfd1..0844a5a0a6 100644
--- a/drivers/spi/spi-sunxi.c
+++ b/drivers/spi/spi-sunxi.c
@@ -489,19 +489,19 @@ static int sun4i_spi_probe(struct udevice *bus)
ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
if (ret) {
- dev_err(dev, "failed to get ahb clock\n");
+ dev_err(bus, "failed to get ahb clock\n");
return ret;
}
ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
if (ret) {
- dev_err(dev, "failed to get mod clock\n");
+ dev_err(bus, "failed to get mod clock\n");
return ret;
}
ret = reset_get_by_index(bus, 0, &priv->reset);
if (ret && ret != -ENOENT) {
- dev_err(dev, "failed to get reset\n");
+ dev_err(bus, "failed to get reset\n");
return ret;
}
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c
index a72986be90..e0e6687037 100644
--- a/drivers/spi/zynqmp_gqspi.c
+++ b/drivers/spi/zynqmp_gqspi.c
@@ -346,20 +346,20 @@ static int zynqmp_qspi_probe(struct udevice *bus)
ret = clk_get_by_index(bus, 0, &clk);
if (ret < 0) {
- dev_err(dev, "failed to get clock\n");
+ dev_err(bus, "failed to get clock\n");
return ret;
}
clock = clk_get_rate(&clk);
if (IS_ERR_VALUE(clock)) {
- dev_err(dev, "failed to get rate\n");
+ dev_err(bus, "failed to get rate\n");
return clock;
}
debug("%s: CLK %ld\n", __func__, clock);
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
- dev_err(dev, "failed to enable clock\n");
+ dev_err(bus, "failed to enable clock\n");
return ret;
}
plat->frequency = clock;
diff --git a/drivers/sysreset/sysreset-ti-sci.c b/drivers/sysreset/sysreset-ti-sci.c
index 3877b9bc12..7707c72bb5 100644
--- a/drivers/sysreset/sysreset-ti-sci.c
+++ b/drivers/sysreset/sysreset-ti-sci.c
@@ -51,8 +51,7 @@ static int ti_sci_sysreset_request(struct udevice *dev, enum sysreset_t type)
ret = cops->reboot_device(sci);
if (ret)
- dev_err(rst->dev, "%s: reboot_device failed (%d)\n",
- __func__, ret);
+ dev_err(dev, "%s: reboot_device failed (%d)\n", __func__, ret);
return ret;
}
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 637024445c..d40d313011 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -146,8 +146,8 @@ config RISCV_TIMER
bool "RISC-V timer support"
depends on TIMER && RISCV
help
- Select this to enable support for the timer as defined
- by the RISC-V privileged architecture spec.
+ Select this to enable support for a generic RISC-V S-Mode timer
+ driver.
config ROCKCHIP_TIMER
bool "Rockchip timer support"
diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c
index 9f9f070e0b..449fcfcfd5 100644
--- a/drivers/timer/riscv_timer.c
+++ b/drivers/timer/riscv_timer.c
@@ -1,36 +1,37 @@
// SPDX-License-Identifier: GPL-2.0+
/*
+ * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
+ * Copyright (C) 2012 Regents of the University of California
*
- * RISC-V privileged architecture defined generic timer driver
+ * RISC-V architecturally-defined generic timer driver
*
- * This driver relies on RISC-V platform codes to provide the essential API
- * riscv_get_time() which is supposed to return the timer counter as defined
- * by the RISC-V privileged architecture spec.
- *
- * This driver can be used in both M-mode and S-mode U-Boot.
+ * This driver provides generic timer support for S-mode U-Boot.
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <timer.h>
-#include <asm/io.h>
-
-/**
- * riscv_get_time() - get the timer counter
- *
- * Platform codes should provide this API in order to make this driver function.
- *
- * @time: the 64-bit timer count as defined by the RISC-V privileged
- * architecture spec.
- * @return: 0 on success, -ve on error.
- */
-extern int riscv_get_time(u64 *time);
+#include <asm/csr.h>
static int riscv_timer_get_count(struct udevice *dev, u64 *count)
{
- return riscv_get_time(count);
+ if (IS_ENABLED(CONFIG_64BIT)) {
+ *count = csr_read(CSR_TIME);
+ } else {
+ u32 hi, lo;
+
+ do {
+ hi = csr_read(CSR_TIMEH);
+ lo = csr_read(CSR_TIME);
+ } while (hi != csr_read(CSR_TIMEH));
+
+ *count = ((u64)hi << 32) | lo;
+ }
+
+ return 0;
}
static int riscv_timer_probe(struct udevice *dev)
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index 5228486082..6a503c2f15 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -40,7 +40,9 @@ static int sandbox_timer_probe(struct udevice *dev)
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- if (!uc_priv->clock_rate)
+ if (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;
return 0;
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 14dde950a1..e9802c8b43 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -4,6 +4,7 @@
*/
#include <common.h>
+#include <cpu.h>
#include <dm.h>
#include <init.h>
#include <dm/lists.h>
@@ -79,6 +80,36 @@ 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)
+int timer_timebase_fallback(struct udevice *dev)
+{
+ struct udevice *cpu;
+ struct cpu_platdata *cpu_plat;
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Did we get our clock rate from the device tree? */
+ if (uc_priv->clock_rate)
+ return 0;
+
+ /* Fall back to timebase-frequency */
+ dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n");
+ cpu = cpu_get_current_dev();
+ if (!cpu)
+ return -ENODEV;
+
+ cpu_plat = dev_get_parent_platdata(cpu);
+ if (!cpu_plat)
+ return -ENODEV;
+
+ uc_priv->clock_rate = cpu_plat->timebase_freq;
+ return 0;
+}
+#endif
+
u64 timer_conv_64(u32 count)
{
/* increment tbh if tbl has rolled over */
diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c
index a08c694559..acff79ae1c 100644
--- a/drivers/usb/cdns3/ep0.c
+++ b/drivers/usb/cdns3/ep0.c
@@ -11,8 +11,9 @@
*/
#include <cpu_func.h>
-#include <asm/cache.h>
+#include <dm.h>
#include <dm/device_compat.h>
+#include <asm/cache.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/usb/composite.h>
@@ -810,7 +811,7 @@ int cdns3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
- dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name);
+ dev_dbg(priv_ep->cdns3_dev->dev, "Wedge for %s\n", ep->name);
cdns3_gadget_ep_set_halt(ep, 1);
priv_ep->flags |= EP_WEDGE;
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index 8f81d17ec8..83dbb5a103 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -2399,8 +2399,7 @@ static void cdns3_gadget_udc_set_speed(struct usb_gadget *gadget,
case USB_SPEED_SUPER:
break;
default:
- dev_err(cdns->dev, "invalid speed parameter %d\n",
- speed);
+ dev_err(priv_dev->dev, "invalid speed parameter %d\n", speed);
}
priv_dev->gadget.speed = speed;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 8682556589..2e003530a1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -592,7 +592,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize gadget\n");
+ dev_err(dwc->dev, "failed to initialize gadget\n");
return ret;
}
break;
@@ -600,7 +600,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize host\n");
+ dev_err(dwc->dev, "failed to initialize host\n");
return ret;
}
break;
@@ -608,18 +608,19 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize host\n");
+ dev_err(dwc->dev, "failed to initialize host\n");
return ret;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize gadget\n");
+ dev_err(dwc->dev, "failed to initialize gadget\n");
return ret;
}
break;
default:
- dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
+ dev_err(dwc->dev,
+ "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
@@ -768,7 +769,7 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
ret = dwc3_core_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize core\n");
+ dev_err(dwc->dev, "failed to initialize core\n");
goto err0;
}
@@ -974,7 +975,7 @@ int dwc3_init(struct dwc3 *dwc)
ret = dwc3_core_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize core\n");
+ dev_err(dwc->dev, "failed to initialize core\n");
goto core_fail;
}
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 7fbf2502fa..36fa16ad4e 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -10,7 +10,6 @@
#include <common.h>
#include <cpu_func.h>
#include <log.h>
-#include <asm-generic/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 385bed3e34..75ac993bc6 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
#include <cpu_func.h>
+#include <dm.h>
#include <dm/device_compat.h>
#include <linux/bug.h>
#include <linux/kernel.h>
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2aec874e1d..4e68fb0a82 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -17,6 +17,7 @@
#include <cpu_func.h>
#include <log.h>
#include <malloc.h>
+#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <linux/bug.h>
@@ -633,7 +634,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
strlcat(dep->name, "-int", sizeof(dep->name));
break;
default:
- dev_err(dwc->dev, "invalid endpoint transfer type\n");
+ dev_err(dep->dwc->dev, "invalid endpoint transfer type\n");
}
spin_lock_irqsave(&dwc->lock, flags);
@@ -708,10 +709,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
{
struct dwc3_trb *trb;
- dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
- dep->name, req, (unsigned long long) dma,
- length, last ? " last" : "",
- chain ? " chain" : "");
+ dev_vdbg(dep->dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+ dep->name, req, (unsigned long long)dma,
+ length, last ? " last" : "", chain ? " chain" : "");
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
@@ -1074,21 +1074,22 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
spin_lock_irqsave(&dwc->lock, flags);
if (!dep->endpoint.desc) {
- dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
- request, ep->name);
+ dev_dbg(dep->dwc->dev,
+ "trying to queue request %p to disabled %s\n", request,
+ ep->name);
ret = -ESHUTDOWN;
goto out;
}
if (req->dep != dep) {
- WARN(true, "request %p belongs to '%s'\n",
- request, req->dep->name);
+ WARN(true, "request %p belongs to '%s'\n", request,
+ req->dep->name);
ret = -EINVAL;
goto out;
}
- dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
- request, ep->name, request->length);
+ dev_vdbg(dep->dwc->dev, "queing request %p to %s length %d\n",
+ request, ep->name, request->length);
ret = __dwc3_gadget_ep_queue(dep, req);
diff --git a/drivers/usb/dwc3/ti_usb_phy.c b/drivers/usb/dwc3/ti_usb_phy.c
index f8ab06482c..f476810763 100644
--- a/drivers/usb/dwc3/ti_usb_phy.c
+++ b/drivers/usb/dwc3/ti_usb_phy.c
@@ -129,7 +129,7 @@ static struct usb3_dpll_params *ti_usb3_get_dpll_params(struct ti_usb_phy *phy)
return &dpll_map->params;
}
- dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+ log_err("No DPLL configuration for %lu Hz SYS CLK\n", rate);
return NULL;
}
@@ -269,7 +269,7 @@ int ti_usb_phy_uboot_init(struct ti_usb_phy_device *dev)
phy = devm_kzalloc(NULL, sizeof(*phy), GFP_KERNEL);
if (!phy) {
- dev_err(NULL, "unable to alloc mem for TI USB3 PHY\n");
+ log_err("unable to alloc mem for TI USB3 PHY\n");
return -ENOMEM;
}
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index cefe9d83b1..f1d13b1c1d 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -114,7 +114,8 @@ static void init_fslspclksel(struct dwc2_core_regs *regs)
* @param regs Programming view of DWC_otg controller.
* @param num Tx FIFO to flush.
*/
-static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
+static void dwc_otg_flush_tx_fifo(struct udevice *dev,
+ struct dwc2_core_regs *regs, const int num)
{
int ret;
@@ -134,7 +135,8 @@ static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
*
* @param regs Programming view of DWC_otg controller.
*/
-static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
+static void dwc_otg_flush_rx_fifo(struct udevice *dev,
+ struct dwc2_core_regs *regs)
{
int ret;
@@ -152,7 +154,8 @@ static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
-static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
+static void dwc_otg_core_reset(struct udevice *dev,
+ struct dwc2_core_regs *regs)
{
int ret;
@@ -284,8 +287,8 @@ static void dwc_otg_core_host_init(struct udevice *dev,
clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
/* Make sure the FIFOs are flushed. */
- dwc_otg_flush_tx_fifo(regs, 0x10); /* All Tx FIFOs */
- dwc_otg_flush_rx_fifo(regs);
+ dwc_otg_flush_tx_fifo(dev, regs, 0x10); /* All Tx FIFOs */
+ dwc_otg_flush_rx_fifo(dev, regs);
/* Flush out any leftover queued requests. */
num_channels = readl(&regs->ghwcfg2);
@@ -306,7 +309,7 @@ static void dwc_otg_core_host_init(struct udevice *dev,
ret = wait_for_bit_le32(&regs->hc_regs[i].hcchar,
DWC2_HCCHAR_CHEN, false, 1000, false);
if (ret)
- dev_info("%s: Timeout!\n", __func__);
+ dev_info(dev, "%s: Timeout!\n", __func__);
}
/* Turn on the vbus power. */
@@ -330,8 +333,9 @@ static void dwc_otg_core_host_init(struct udevice *dev,
*
* @param regs Programming view of the DWC_otg controller
*/
-static void dwc_otg_core_init(struct dwc2_priv *priv)
+static void dwc_otg_core_init(struct udevice *dev)
{
+ struct dwc2_priv *priv = dev_get_priv(dev);
struct dwc2_core_regs *regs = priv->regs;
uint32_t ahbcfg = 0;
uint32_t usbcfg = 0;
@@ -360,7 +364,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv)
writel(usbcfg, &regs->gusbcfg);
/* Reset the Controller */
- dwc_otg_core_reset(regs);
+ dwc_otg_core_reset(dev, regs);
/*
* This programming sequence needs to happen in FS mode before
@@ -372,7 +376,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv)
setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_PHYSEL);
/* Reset after a PHY select */
- dwc_otg_core_reset(regs);
+ dwc_otg_core_reset(dev, regs);
/*
* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
@@ -419,7 +423,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv)
writel(usbcfg, &regs->gusbcfg);
/* Reset after setting the PHY parameters */
- dwc_otg_core_reset(regs);
+ dwc_otg_core_reset(dev, regs);
#endif
usbcfg = readl(&regs->gusbcfg);
@@ -1128,7 +1132,12 @@ int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
for (;;) {
if (get_timer(0) > timeout) {
- dev_err(dev, "Timeout poll on interrupt endpoint\n");
+#if CONFIG_IS_ENABLED(DM_USB)
+ dev_err(dev->dev,
+ "Timeout poll on interrupt endpoint\n");
+#else
+ log_err("Timeout poll on interrupt endpoint\n");
+#endif
return -ETIMEDOUT;
}
ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
@@ -1194,7 +1203,7 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
priv->ext_vbus = 0;
#endif
- dwc_otg_core_init(priv);
+ dwc_otg_core_init(dev);
dwc_otg_core_host_init(dev, regs);
clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
@@ -1320,12 +1329,10 @@ static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev,
static int dwc2_usb_ofdata_to_platdata(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
- fdt_addr_t addr;
- addr = dev_read_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
+ priv->regs = dev_read_addr_ptr(dev);
+ if (!priv->regs)
return -EINVAL;
- priv->regs = (struct dwc2_core_regs *)addr;
priv->oc_disable = dev_read_bool(dev, "disable-over-current");
priv->hnp_srp_disable = dev_read_bool(dev, "hnp-srp-disable");
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 06a55bf6ee..187db7794b 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -301,21 +301,21 @@ static int sunxi_musb_init(struct musb *musb)
ret = clk_enable(&glue->clk);
if (ret) {
- dev_err(dev, "failed to enable clock\n");
+ dev_err(musb->controller, "failed to enable clock\n");
return ret;
}
if (reset_valid(&glue->rst)) {
ret = reset_deassert(&glue->rst);
if (ret) {
- dev_err(dev, "failed to deassert reset\n");
+ dev_err(musb->controller, "failed to deassert reset\n");
goto err_clk;
}
}
ret = generic_phy_init(&glue->phy);
if (ret) {
- dev_dbg(dev, "failed to init USB PHY\n");
+ dev_dbg(musb->controller, "failed to init USB PHY\n");
goto err_rst;
}
@@ -352,7 +352,8 @@ static int sunxi_musb_exit(struct musb *musb)
if (generic_phy_valid(&glue->phy)) {
ret = generic_phy_exit(&glue->phy);
if (ret) {
- dev_dbg(dev, "failed to power off usb phy\n");
+ dev_dbg(musb->controller,
+ "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c
index b7bfbb5e50..2743836fb4 100644
--- a/drivers/video/dw_mipi_dsi.c
+++ b/drivers/video/dw_mipi_dsi.c
@@ -314,7 +314,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
val, !(val & GEN_CMD_FULL),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "failed to get available command FIFO\n");
+ dev_err(dsi->dsi_host.dev,
+ "failed to get available command FIFO\n");
return ret;
}
@@ -325,7 +326,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
val, (val & mask) == mask,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "failed to write command FIFO\n");
+ dev_err(dsi->dsi_host.dev, "failed to write command FIFO\n");
return ret;
}
@@ -357,7 +358,7 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
val, !(val & GEN_PLD_W_FULL),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev,
+ dev_err(dsi->dsi_host.dev,
"failed to get available write payload FIFO\n");
return ret;
}
@@ -380,7 +381,7 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
val, !(val & GEN_RD_CMD_BUSY),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "Timeout during read operation\n");
+ dev_err(dsi->dsi_host.dev, "Timeout during read operation\n");
return ret;
}
@@ -390,7 +391,8 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
val, !(val & GEN_PLD_R_EMPTY),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "Read payload FIFO is empty\n");
+ dev_err(dsi->dsi_host.dev,
+ "Read payload FIFO is empty\n");
return ret;
}
@@ -411,7 +413,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
ret = mipi_dsi_create_packet(&packet, msg);
if (ret) {
- dev_err(dsi->dev, "failed to create packet: %d\n", ret);
+ dev_err(host->dev, "failed to create packet: %d\n", ret);
return ret;
}
@@ -702,13 +704,15 @@ static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi)
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val,
val & PHY_LOCK, PHY_STATUS_TIMEOUT_US);
if (ret)
- dev_warn(dsi->dev, "failed to wait phy lock state\n");
+ dev_warn(dsi->dsi_host.dev,
+ "failed to wait phy lock state\n");
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
val, val & PHY_STOP_STATE_CLK_LANE,
PHY_STATUS_TIMEOUT_US);
if (ret)
- dev_warn(dsi->dev, "failed to wait phy clk lane stop state\n");
+ dev_warn(dsi->dsi_host.dev,
+ "failed to wait phy clk lane stop state\n");
}
static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
@@ -729,7 +733,7 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi,
ret = phy_ops->get_lane_mbps(dsi->device, timings, device->lanes,
device->format, &dsi->lane_mbps);
if (ret)
- dev_warn(dsi->dev, "Phy get_lane_mbps() failed\n");
+ dev_warn(dsi->dsi_host.dev, "Phy get_lane_mbps() failed\n");
dw_mipi_dsi_init_pll(dsi);
dw_mipi_dsi_dpi_config(dsi, timings);
@@ -748,7 +752,7 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi,
ret = phy_ops->init(dsi->device);
if (ret)
- dev_warn(dsi->dev, "Phy init() failed\n");
+ dev_warn(dsi->dsi_host.dev, "Phy init() failed\n");
dw_mipi_dsi_dphy_enable(dsi);
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index a57dd2665c..3ae1894a98 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -701,4 +701,51 @@ int gpio_get_number(const struct gpio_desc *desc);
*/
int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio);
+/**
+ * devm_gpiod_get_index - Resource-managed gpiod_get()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get(). GPIO descriptors returned from this function are
+ * automatically disposed on device unbind.
+ * Return the GPIO descriptor corresponding to the function con_id of device
+ * dev, -ENOENT if no GPIO has been assigned to the requested function, or
+ * another IS_ERR() code if an error occurred while trying to acquire the GPIO.
+ */
+struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id,
+ unsigned int index, int flags);
+
+#define devm_gpiod_get(dev, id, flags) devm_gpiod_get_index(dev, id, 0, flags)
+/**
+ * gpiod_get_optional - obtain an optional GPIO for a given GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to devm_gpiod_get(), except that when no GPIO was
+ * assigned to the requested function it will return NULL. This is convenient
+ * for drivers that need to handle optional GPIOs.
+ */
+struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev,
+ const char *id,
+ unsigned int index,
+ int flags);
+
+#define devm_gpiod_get_optional(dev, id, flags) \
+ devm_gpiod_get_index_optional(dev, id, 0, flags)
+
+/**
+ * devm_gpiod_put - Resource-managed gpiod_put()
+ * @dev: GPIO consumer
+ * @desc: GPIO descriptor to dispose of
+ *
+ * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
+ * devm_gpiod_get_index(). Normally this function will not be called as the GPIO
+ * will be disposed of by the resource management code.
+ */
+void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc);
+
#endif /* _ASM_GENERIC_GPIO_H_ */
diff --git a/include/dm/device_compat.h b/include/dm/device_compat.h
index 3d8cd09f4c..8f26053b45 100644
--- a/include/dm/device_compat.h
+++ b/include/dm/device_compat.h
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
* Copyright (c) 2013 Google, Inc
*
* (C) Copyright 2012
@@ -10,6 +11,8 @@
#ifndef _DM_DEVICE_COMPAT_H
#define _DM_DEVICE_COMPAT_H
+#include <log.h>
+#include <linux/build_bug.h>
#include <linux/compat.h>
/*
@@ -33,54 +36,106 @@
#endif
/*
- * REVISIT:
- * print device name like Linux
+ * Define a new identifier which can be tested on by C code. A similar
+ * definition is made for DEBUG in <log.h>.
*/
-#define dev_printk(dev, fmt, ...) \
-({ \
- printk(fmt, ##__VA_ARGS__); \
+#ifdef VERBOSE_DEBUG
+#define _VERBOSE_DEBUG 1
+#else
+#define _VERBOSE_DEBUG 0
+#endif
+
+/**
+ * dev_printk_emit() - Emit a formatted log message
+ * @cat: Category of the message
+ * @level: Log level of the message
+ * @fmt: Format string
+ * @...: Arguments for @fmt
+ *
+ * This macro logs a message through the appropriate channel. It is a macro so
+ * the if statements can be optimized out (as @level should be a constant known
+ * at compile-time).
+ *
+ * If DEBUG or VERBOSE_DEBUG is defined, then some messages are always printed
+ * (through printf()). This is to match the historical behavior of the dev_xxx
+ * functions.
+ *
+ * If LOG is enabled, use log() to emit the message, otherwise print it based on
+ * the console loglevel.
+ */
+#define dev_printk_emit(cat, level, fmt, ...) \
+({ \
+ if ((_DEBUG && level == LOGL_DEBUG) || \
+ (_VERBOSE_DEBUG && level == LOGL_DEBUG_CONTENT)) \
+ printf(fmt, ##__VA_ARGS__); \
+ else if (CONFIG_IS_ENABLED(LOG)) \
+ log(cat, level, fmt, ##__VA_ARGS__); \
+ else if (level < CONFIG_VAL(LOGLEVEL)) \
+ printf(fmt, ##__VA_ARGS__); \
})
-#define __dev_printk(level, dev, fmt, ...) \
-({ \
- if (level < CONFIG_VAL(LOGLEVEL)) \
- dev_printk(dev, fmt, ##__VA_ARGS__); \
+/**
+ * __dev_printk() - Log a message for a device
+ * @level: Log level of the message
+ * @dev: A &struct udevice or &struct device
+ * @fmt: Format string
+ * @...: Arguments for @fmt
+ *
+ * This macro formats and prints dev_xxx log messages. It is done as a macro
+ * because working with variadic argument is much easier this way, we can
+ * interrogate the type of device we are passed (and whether it *is* a &struct
+ * udevice or &struct device), and dev_printk_emit() can optimize out unused if
+ * branches.
+ *
+ * Because this is a macro, we must enforce type checks ourselves. Ideally, we
+ * would only accept udevices, but there is a significant amount of code (mostly
+ * USB) which calls dev_xxx with &struct device. When assigning ``__dev``, we
+ * must first cast ``dev`` to ``void *`` so we don't get warned when ``dev`` is
+ * a &struct device. Even though the latter branch is not taken, it will still
+ * get compiled and type-checked.
+ *
+ * The format strings in case of a ``NULL`` ``dev`` MUST be kept the same.
+ * Otherwise, @fmt will be duplicated in the data section (with slightly
+ * different prefixes). This is why ``(NULL udevice *)`` is printed as two
+ * string arguments, and not by string pasting.
+ */
+#define __dev_printk(level, dev, fmt, ...) \
+({ \
+ if (__same_type(dev, struct device *)) { \
+ dev_printk_emit(LOG_CATEGORY, level, fmt, ##__VA_ARGS__); \
+ } else { \
+ BUILD_BUG_ON(!__same_type(dev, struct udevice *)); \
+ struct udevice *__dev = (void *)dev; \
+ if (__dev) \
+ dev_printk_emit(__dev->driver->id, level, \
+ "%s %s: " fmt, \
+ __dev->driver->name, __dev->name, \
+ ##__VA_ARGS__); \
+ else \
+ dev_printk_emit(LOG_CATEGORY, level, \
+ "%s %s: " fmt, \
+ "(NULL", "udevice *)", \
+ ##__VA_ARGS__); \
+ } \
})
#define dev_emerg(dev, fmt, ...) \
- __dev_printk(0, dev, fmt, ##__VA_ARGS__)
+ __dev_printk(LOGL_EMERG, dev, fmt, ##__VA_ARGS__)
#define dev_alert(dev, fmt, ...) \
- __dev_printk(1, dev, fmt, ##__VA_ARGS__)
+ __dev_printk(LOGL_ALERT, dev, fmt, ##__VA_ARGS__)
#define dev_crit(dev, fmt, ...) \
- __dev_printk(2, dev, fmt, ##__VA_ARGS__)
+ __dev_printk(LOGL_CRIT, dev, fmt, ##__VA_ARGS__)
#define dev_err(dev, fmt, ...) \
- __dev_printk(3, dev, fmt, ##__VA_ARGS__)
+ __dev_printk(LOGL_ERR, dev, fmt, ##__VA_ARGS__)
#define dev_warn(dev, fmt, ...) \
- __dev_printk(4, dev, fmt, ##__VA_ARGS__)
+ __dev_printk(LOGL_WARNING, dev, fmt, ##__VA_ARGS__)
#define dev_notice(dev, fmt, ...) \
- __dev_printk(5, dev, fmt, ##__VA_ARGS__)
+ __dev_printk(LOGL_NOTICE, dev, fmt, ##__VA_ARGS__)
#define dev_info(dev, fmt, ...) \
- __dev_printk(6, dev, fmt, ##__VA_ARGS__)
-
-#ifdef DEBUG
+ __dev_printk(LOGL_INFO, dev, fmt, ##__VA_ARGS__)
#define dev_dbg(dev, fmt, ...) \
- __dev_printk(7, dev, fmt, ##__VA_ARGS__)
-#else
-#define dev_dbg(dev, fmt, ...) \
-({ \
- if (0) \
- __dev_printk(7, dev, fmt, ##__VA_ARGS__); \
-})
-#endif
-
-#ifdef VERBOSE_DEBUG
-#define dev_vdbg dev_dbg
-#else
-#define dev_vdbg(dev, fmt, ...) \
-({ \
- if (0) \
- __dev_printk(7, dev, fmt, ##__VA_ARGS__); \
-})
-#endif
+ __dev_printk(LOGL_DEBUG, dev, fmt, ##__VA_ARGS__)
+#define dev_vdbg(dev, fmt, ...) \
+ __dev_printk(LOGL_DEBUG_CONTENT, dev, fmt, ##__VA_ARGS__)
#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 4ec5fa6670..88f10c4622 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -94,6 +94,7 @@ enum uclass_id {
UCLASS_RESET, /* Reset controller device */
UCLASS_RNG, /* Random Number Generator */
UCLASS_RTC, /* Real time clock device */
+ UCLASS_SCMI_AGENT, /* Interface with an SCMI server */
UCLASS_SCSI, /* SCSI device */
UCLASS_SERIAL, /* Serial UART */
UCLASS_SIMPLE_BUS, /* Bus with child devices */
diff --git a/include/dt-bindings/clock/k210-sysctl.h b/include/dt-bindings/clock/k210-sysctl.h
index 0e3ed3fb9f..fe852bbd92 100644
--- a/include/dt-bindings/clock/k210-sysctl.h
+++ b/include/dt-bindings/clock/k210-sysctl.h
@@ -55,5 +55,6 @@
#define K210_CLK_OTP 43
#define K210_CLK_RTC 44
#define K210_CLK_ACLK 45
+#define K210_CLK_CLINT 46
#endif /* CLOCK_K210_SYSCTL_H */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 363b2b9425..d129780312 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -52,25 +52,6 @@ extern struct p_current *current;
#define dev_warn(dev, fmt, args...) \
printf(fmt, ##args)
-#define netdev_emerg(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_alert(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_crit(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_err(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_warn(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_notice(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_info(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_dbg(dev, fmt, args...) \
- debug(fmt, ##args)
-#define netdev_vdbg(dev, fmt, args...) \
- debug(fmt, ##args)
-
#define GFP_ATOMIC ((gfp_t) 0)
#define GFP_KERNEL ((gfp_t) 0)
#define GFP_NOFS ((gfp_t) 0)
diff --git a/include/mmc.h b/include/mmc.h
index 82562193cc..75bcaaf6b3 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -888,6 +888,8 @@ void mmc_set_preinit(struct mmc *mmc, int preinit);
#define mmc_host_is_spi(mmc) 0
#endif
+#define mmc_dev(x) ((x)->dev)
+
void board_mmc_power_init(void);
int board_mmc_init(struct bd_info *bis);
int cpu_mmc_init(struct bd_info *bis);
diff --git a/include/net.h b/include/net.h
index 1bf9867f8c..219107194f 100644
--- a/include/net.h
+++ b/include/net.h
@@ -551,7 +551,7 @@ extern int net_restart_wrap; /* Tried all network devices */
enum proto_t {
BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
- TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
+ TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP
};
extern char net_boot_file_name[1024];/* Boot File name */
diff --git a/net/sntp.h b/include/net/sntp.h
index d3cbfbc69a..30b44d1c06 100644
--- a/net/sntp.h
+++ b/include/net/sntp.h
@@ -52,6 +52,7 @@ struct sntp_pkt_t {
unsigned long long transmit_timestamp;
} __attribute__((packed));
-void sntp_start(void); /* Begin SNTP */
+int sntp_prereq(void *data);
+int sntp_start(void *data); /* Begin SNTP */
#endif /* __SNTP_H__ */
diff --git a/include/net/udp.h b/include/net/udp.h
new file mode 100644
index 0000000000..2ae56e8447
--- /dev/null
+++ b/include/net/udp.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com>
+ */
+
+#ifndef __UDP
+#define __UDP
+
+/**
+ * struct udp_ops - function to handle udp packet
+ *
+ * This structure provides the function to handle udp packet in
+ * the network loop.
+ *
+ * @prereq: callback called to check the requirement
+ * @start: callback called to start the protocol/feature
+ * @data: pointer to store private data (used by prereq and start)
+ */
+struct udp_ops {
+ int (*prereq)(void *data);
+ int (*start)(void *data);
+ void *data;
+};
+
+int udp_prereq(void);
+
+int udp_start(void);
+
+/**
+ * udp_loop() - network loop for udp protocol
+ *
+ * Launch a network loop for udp protocol and use callbacks
+ * provided in parameter @ops to initialize the loop, and then
+ * to handle udp packet.
+ *
+ * @ops: udp callback
+ * @return: 0 if success, otherwise < 0 on error
+ */
+int udp_loop(struct udp_ops *ops);
+
+#endif
diff --git a/include/regmap.h b/include/regmap.h
index 30183c5e71..c6258face3 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -75,14 +75,41 @@ struct regmap_range {
ulong size;
};
+struct regmap_bus;
+
+/**
+ * struct regmap_config - Configure the behaviour of a regmap
+ *
+ * @width: Width of the read/write operations. Defaults to
+ * REGMAP_SIZE_32 if set to 0.
+ * @reg_offset_shift Left shift the register offset by this value before
+ * performing read or write.
+ * @r_start: If specified, the regmap is created with one range
+ * which starts at this address, instead of finding the
+ * start from device tree.
+ * @r_size: Same as above for the range size
+ */
+struct regmap_config {
+ enum regmap_size_t width;
+ u32 reg_offset_shift;
+ ulong r_start;
+ ulong r_size;
+};
+
/**
* struct regmap - a way of accessing hardware/bus registers
*
+ * @width: Width of the read/write operations. Defaults to
+ * REGMAP_SIZE_32 if set to 0.
+ * @reg_offset_shift Left shift the register offset by this value before
+ * performing read or write.
* @range_count: Number of ranges available within the map
* @ranges: Array of ranges
*/
struct regmap {
enum regmap_endianness_t endianness;
+ enum regmap_size_t width;
+ u32 reg_offset_shift;
int range_count;
struct regmap_range ranges[0];
};
@@ -93,32 +120,24 @@ struct regmap {
*/
/**
- * regmap_write() - Write a 32-bit value to a regmap
+ * regmap_write() - Write a value to a regmap
*
* @map: Regmap to write to
* @offset: Offset in the regmap to write to
* @val: Data to write to the regmap at the specified offset
*
- * Note that this function will only write values of 32 bit width to the
- * regmap; if the size of data to be read is different, the regmap_raw_write
- * function can be used.
- *
* Return: 0 if OK, -ve on error
*/
int regmap_write(struct regmap *map, uint offset, uint val);
/**
- * regmap_read() - Read a 32-bit value from a regmap
+ * regmap_read() - Read a value from a regmap
*
* @map: Regmap to read from
* @offset: Offset in the regmap to read from
* @valp: Pointer to the buffer to receive the data read from the regmap
* at the specified offset
*
- * Note that this function will only read values of 32 bit width from the
- * regmap; if the size of data to be read is different, the regmap_raw_read
- * function can be used.
- *
* Return: 0 if OK, -ve on error
*/
int regmap_read(struct regmap *map, uint offset, uint *valp);
@@ -132,8 +151,9 @@ int regmap_read(struct regmap *map, uint offset, uint *valp);
* @val_len: Length of the data to be written to the regmap
*
* Note that this function will, as opposed to regmap_write, write data of
- * arbitrary length to the regmap, and not just 32-bit values, and is thus a
- * generalized version of regmap_write.
+ * arbitrary length to the regmap, and not just the size configured in the
+ * regmap (defaults to 32-bit) and is thus a generalized version of
+ * regmap_write.
*
* Return: 0 if OK, -ve on error
*/
@@ -150,8 +170,9 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val,
* @val_len: Length of the data to be read from the regmap
*
* Note that this function will, as opposed to regmap_read, read data of
- * arbitrary length from the regmap, and not just 32-bit values, and is thus a
- * generalized version of regmap_read.
+ * arbitrary length from the regmap, and not just the size configured in the
+ * regmap (defaults to 32-bit) and is thus a generalized version of
+ * regmap_read.
*
* Return: 0 if OK, -ve on error
*/
@@ -292,6 +313,43 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
timeout_ms, 0) \
/**
+ * regmap_field_read_poll_timeout - Poll until a condition is met or a timeout
+ * occurs
+ *
+ * @field: Regmap field to read from
+ * @val: Unsigned integer variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in us (0 tight-loops).
+ * @timeout_ms: Timeout in ms, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_field_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val.
+ *
+ * This is modelled after the regmap_read_poll_timeout macros in linux but
+ * with millisecond timeout.
+ */
+#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, timeout_ms) \
+({ \
+ unsigned long __start = get_timer(0); \
+ int __ret; \
+ for (;;) { \
+ __ret = regmap_field_read((field), &(val)); \
+ if (__ret) \
+ break; \
+ if (cond) \
+ break; \
+ if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \
+ __ret = regmap_field_read((field), &(val)); \
+ break; \
+ } \
+ if ((sleep_us)) \
+ udelay((sleep_us)); \
+ } \
+ __ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
+/**
* regmap_update_bits() - Perform a read/modify/write using a mask
*
* @map: The map returned by regmap_init_mem*()
@@ -336,6 +394,40 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
/**
+ * regmap_init_mem_range() - Set up a new memory region for ofnode with the
+ * specified range.
+ *
+ * @node: The ofnode for the map.
+ * @r_start: Start of the range.
+ * @r_size: Size of the range.
+ * @mapp: Returns allocated map.
+ *
+ * Return: 0 in success, -errno otherwise
+ *
+ * This creates a regmap with one range where instead of extracting the range
+ * from 'node', it is created based on the parameters specified. This is
+ * useful when a driver needs to calculate the base of the regmap at runtime,
+ * and can't specify it in device tree.
+ */
+int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size,
+ struct regmap **mapp);
+
+/**
+ * devm_regmap_init() - Initialise register map (device managed)
+ *
+ * @dev: Device that will be interacted with
+ * @bus: Bus-specific callbacks to use with device (IGNORED)
+ * @bus_context: Data passed to bus-specific callbacks (IGNORED)
+ * @config: Configuration for register map
+ *
+ * @Return a valid pointer to a struct regmap or a ERR_PTR() on error.
+ * The structure is automatically freed when the device is unbound
+ */
+struct regmap *devm_regmap_init(struct udevice *dev,
+ const struct regmap_bus *bus,
+ void *bus_context,
+ const struct regmap_config *config);
+/**
* regmap_get_range() - Obtain the base memory address of a regmap range
*
* @map: Regmap to query
@@ -352,4 +444,89 @@ void *regmap_get_range(struct regmap *map, unsigned int range_num);
*/
int regmap_uninit(struct regmap *map);
+/**
+ * struct reg_field - Description of an register field
+ *
+ * @reg: Offset of the register within the regmap bank
+ * @lsb: lsb of the register field.
+ * @msb: msb of the register field.
+ */
+struct reg_field {
+ unsigned int reg;
+ unsigned int lsb;
+ unsigned int msb;
+};
+
+struct regmap_field;
+
+/**
+ * REG_FIELD() - A convenient way to initialize a 'struct reg_feild'.
+ *
+ * @_reg: Offset of the register within the regmap bank
+ * @_lsb: lsb of the register field.
+ * @_msb: msb of the register field.
+ *
+ * Register fields are often described in terms of 3 things: the register it
+ * belongs to, its LSB, and its MSB. This macro can be used by drivers to
+ * clearly and easily initialize a 'struct regmap_field'.
+ *
+ * For example, say a device has a register at offset DEV_REG1 (0x100) and a
+ * field of DEV_REG1 is on bits [7:3]. So a driver can initialize a regmap
+ * field for this by doing:
+ * struct reg_field field = REG_FIELD(DEV_REG1, 3, 7);
+ */
+#define REG_FIELD(_reg, _lsb, _msb) { \
+ .reg = _reg, \
+ .lsb = _lsb, \
+ .msb = _msb, \
+ }
+
+/**
+ * devm_regmap_field_alloc() - Allocate and initialise a register field.
+ *
+ * @dev: Device that will be interacted with
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field will be automatically freed
+ * by the device management code.
+ */
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+ struct regmap *regmap,
+ struct reg_field reg_field);
+/**
+ * devm_regmap_field_free() - Free a register field allocated using
+ * devm_regmap_field_alloc.
+ *
+ * @dev: Device that will be interacted with
+ * @field: regmap field which should be freed.
+ *
+ * Free register field allocated using devm_regmap_field_alloc(). Usually
+ * drivers need not call this function, as the memory allocated via devm
+ * will be freed as per device-driver life-cyle.
+ */
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field);
+
+/**
+ * regmap_field_write() - Write a value to a regmap field
+ *
+ * @field: Regmap field to write to
+ * @val: Data to write to the regmap at the specified offset
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int regmap_field_write(struct regmap_field *field, unsigned int val);
+
+/**
+ * regmap_read() - Read a 32-bit value from a regmap
+ *
+ * @field: Regmap field to write to
+ * @valp: Pointer to the buffer to receive the data read from the regmap
+ * field
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int regmap_field_read(struct regmap_field *field, unsigned int *val);
+
#endif
diff --git a/include/remoteproc.h b/include/remoteproc.h
index a903acb9b2..74d01723f6 100644
--- a/include/remoteproc.h
+++ b/include/remoteproc.h
@@ -227,19 +227,6 @@ int rproc_elf32_sanity_check(ulong addr, ulong size);
int rproc_elf64_sanity_check(ulong addr, ulong size);
/**
- * rproc_elf_sanity_check() - Verify if an image is a valid ELF one
- *
- * Check if a valid ELF image exists at the given memory location. Auto
- * detects ELF32/ELF64 and verifies basic ELF64/ELF32 format requirements
- * like magic number and sections size.
- *
- * @addr: address of the image to verify
- * @size: size of the image
- * @return 0 if the image looks good, else appropriate error value.
- */
-int rproc_elf_sanity_check(ulong addr, ulong size);
-
-/**
* rproc_elf32_load_image() - load an ELF32 image
* @dev: device loading the ELF32 image
* @addr: valid ELF32 image address
diff --git a/include/reset.h b/include/reset.h
index 4fac4e6a20..cde2c4b4a8 100644
--- a/include/reset.h
+++ b/include/reset.h
@@ -7,7 +7,7 @@
#define _RESET_H
#include <dm/ofnode.h>
-#include <linux/errno.h>
+#include <linux/err.h>
/**
* A reset is a hardware signal indicating that a HW module (or IP block, or
@@ -84,6 +84,98 @@ struct reset_ctl_bulk {
};
#if CONFIG_IS_ENABLED(DM_RESET)
+
+/**
+ * devm_reset_control_get - resource managed reset_get_by_name()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_get_by_name(). For reset controllers returned
+ * from this function, reset_free() is called automatically on driver
+ * detach.
+ *
+ * Returns a struct reset_ctl or IS_ERR() condition containing errno.
+ */
+struct reset_ctl *devm_reset_control_get(struct udevice *dev, const char *id);
+
+/**
+ * devm_reset_control_get_optional - resource managed reset_get_by_name() that
+ * can fail
+ * @dev: The client device.
+ * @id: reset line name
+ *
+ * Managed reset_get_by_name(). For reset controllers returned
+ * from this function, reset_free() is called automatically on driver
+ * detach.
+ *
+ * Returns a struct reset_ctl or a dummy reset controller if it failed.
+ */
+struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev,
+ const char *id);
+
+/**
+ * devm_reset_control_get - resource managed reset_get_by_index()
+ * @dev: The client device.
+ * @index: The index of the reset signal to request, within the client's
+ * list of reset signals.
+ *
+ * Managed reset_get_by_index(). For reset controllers returned
+ * from this function, reset_free() is called automatically on driver
+ * detach.
+ *
+ * Returns a struct reset_ctl or IS_ERR() condition containing errno.
+ */
+struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev,
+ int index);
+
+/**
+ * devm_reset_bulk_get - resource managed reset_get_bulk()
+ * @dev: device to be reset by the controller
+ *
+ * Managed reset_get_bulk(). For reset controllers returned
+ * from this function, reset_free() is called automatically on driver
+ * detach.
+ *
+ * Returns a struct reset_ctl or IS_ERR() condition containing errno.
+ */
+struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev);
+
+/**
+ * devm_reset_bulk_get_optional - resource managed reset_get_bulk() that
+ * can fail
+ * @dev: The client device.
+ *
+ * Managed reset_get_bulk(). For reset controllers returned
+ * from this function, reset_free() is called automatically on driver
+ * detach.
+ *
+ * Returns a struct reset_ctl or NULL if it failed.
+ */
+struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev);
+
+/**
+ * devm_reset_bulk_get_by_node - resource managed reset_get_bulk()
+ * @dev: device to be reset by the controller
+ * @node: ofnode where the "resets" property is. Usually a sub-node of
+ * the dev's node.
+ *
+ * see devm_reset_bulk_get()
+ */
+struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev,
+ ofnode node);
+
+/**
+ * devm_reset_bulk_get_optional_by_node - resource managed reset_get_bulk()
+ * that can fail
+ * @dev: device to be reset by the controller
+ * @node: ofnode where the "resets" property is. Usually a sub-node of
+ * the dev's node.
+ *
+ * see devm_reset_bulk_get_optional()
+ */
+struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev,
+ ofnode node);
+
/**
* reset_get_by_index - Get/request a reset signal by integer index.
*
@@ -265,7 +357,48 @@ static inline int reset_release_bulk(struct reset_ctl_bulk *bulk)
{
return reset_release_all(bulk->resets, bulk->count);
}
+
#else
+static inline struct reset_ctl *devm_reset_control_get(struct udevice *dev,
+ const char *id)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+static inline struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev,
+ const char *id)
+{
+ return NULL;
+}
+
+static inline struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev,
+ int index)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+static inline struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+static inline struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev)
+{
+ return NULL;
+}
+
+static inline struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev,
+ ofnode node)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+static inline struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev,
+ ofnode node)
+{
+ return NULL;
+}
+
static inline int reset_get_by_index(struct udevice *dev, int index,
struct reset_ctl *reset_ctl)
{
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h
new file mode 100644
index 0000000000..a501d1b482
--- /dev/null
+++ b/include/scmi_agent-uclass.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+#ifndef _SCMI_AGENT_UCLASS_H
+#define _SCMI_AGENT_UCLASS_H
+
+struct udevice;
+struct scmi_msg;
+
+/**
+ * struct scmi_transport_ops - The functions that a SCMI transport layer must implement.
+ */
+struct scmi_agent_ops {
+ /*
+ * process_msg - Request transport to get the SCMI message processed
+ *
+ * @agent: Agent using the transport
+ * @msg: SCMI message to be transmitted
+ */
+ int (*process_msg)(struct udevice *dev, struct scmi_msg *msg);
+};
+
+#endif /* _SCMI_TRANSPORT_UCLASS_H */
diff --git a/include/scmi_agent.h b/include/scmi_agent.h
new file mode 100644
index 0000000000..f1be9ff209
--- /dev/null
+++ b/include/scmi_agent.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020, Linaro Limited
+ *
+ * An SCMI agent device represent on communication path from a
+ * device driver to the remote SCMI server which driver sends
+ * messages to and receives response messages from.
+ */
+#ifndef SCMI_AGENT_H
+#define SCMI_AGENT_H
+
+#include <asm/types.h>
+
+struct udevice;
+
+/*
+ * struct scmi_msg - Context of a SCMI message sent and the response received
+ *
+ * @protocol_id: SCMI protocol ID
+ * @message_id: SCMI message ID for a defined protocol ID
+ * @in_msg: Pointer to the message payload sent by the driver
+ * @in_msg_sz: Byte size of the message payload sent
+ * @out_msg: Pointer to buffer to store response message payload
+ * @out_msg_sz: Byte size of the response buffer and response payload
+ */
+struct scmi_msg {
+ unsigned int protocol_id;
+ unsigned int message_id;
+ u8 *in_msg;
+ size_t in_msg_sz;
+ u8 *out_msg;
+ size_t out_msg_sz;
+};
+
+/* Helper macro to match a message on input/output array references */
+#define SCMI_MSG_IN(_protocol, _message, _in_array, _out_array) \
+ (struct scmi_msg){ \
+ .protocol_id = (_protocol), \
+ .message_id = (_message), \
+ .in_msg = (uint8_t *)&(_in_array), \
+ .in_msg_sz = sizeof(_in_array), \
+ .out_msg = (uint8_t *)&(_out_array), \
+ .out_msg_sz = sizeof(_out_array), \
+ }
+
+/**
+ * scmi_send_and_process_msg() - send and process a SCMI message
+ *
+ * Send a message to a SCMI server through a target SCMI agent device.
+ * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
+ * On return, scmi_msg::out_msg_sz stores the response payload size.
+ *
+ * @dev: SCMI agent device
+ * @msg: Message structure reference
+ * @return 0 on success and a negative errno on failure
+ */
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
+
+/**
+ * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code
+ *
+ * @scmi_errno: SCMI error code value
+ * @return 0 for successful status and a negative errno otherwise
+ */
+int scmi_to_linux_errno(s32 scmi_errno);
+
+#endif /* SCMI_H */
diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h
new file mode 100644
index 0000000000..ccab97c96c
--- /dev/null
+++ b/include/scmi_protocols.h
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020, Linaro Limited
+ */
+#ifndef _SCMI_PROTOCOLS_H
+#define _SCMI_PROTOCOLS_H
+
+#include <linux/bitops.h>
+#include <asm/types.h>
+
+/*
+ * Subset the SCMI protocols definition
+ * based on SCMI specification v2.0 (DEN0056B)
+ * https://developer.arm.com/docs/den0056/b
+ */
+
+enum scmi_std_protocol {
+ SCMI_PROTOCOL_ID_BASE = 0x10,
+ SCMI_PROTOCOL_ID_POWER_DOMAIN = 0x11,
+ SCMI_PROTOCOL_ID_SYSTEM = 0x12,
+ SCMI_PROTOCOL_ID_PERF = 0x13,
+ SCMI_PROTOCOL_ID_CLOCK = 0x14,
+ SCMI_PROTOCOL_ID_SENSOR = 0x15,
+ SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16,
+};
+
+enum scmi_status_code {
+ SCMI_SUCCESS = 0,
+ SCMI_NOT_SUPPORTED = -1,
+ SCMI_INVALID_PARAMETERS = -2,
+ SCMI_DENIED = -3,
+ SCMI_NOT_FOUND = -4,
+ SCMI_OUT_OF_RANGE = -5,
+ SCMI_BUSY = -6,
+ SCMI_COMMS_ERROR = -7,
+ SCMI_GENERIC_ERROR = -8,
+ SCMI_HARDWARE_ERROR = -9,
+ SCMI_PROTOCOL_ERROR = -10,
+};
+
+/*
+ * SCMI Clock Protocol
+ */
+
+enum scmi_clock_message_id {
+ SCMI_CLOCK_RATE_SET = 0x5,
+ SCMI_CLOCK_RATE_GET = 0x6,
+ SCMI_CLOCK_CONFIG_SET = 0x7,
+};
+
+#define SCMI_CLK_RATE_ASYNC_NOTIFY BIT(0)
+#define SCMI_CLK_RATE_ASYNC_NORESP (BIT(0) | BIT(1))
+#define SCMI_CLK_RATE_ROUND_DOWN 0
+#define SCMI_CLK_RATE_ROUND_UP BIT(2)
+#define SCMI_CLK_RATE_ROUND_CLOSEST BIT(3)
+
+/**
+ * struct scmi_clk_state_in - Message payload for CLOCK_CONFIG_SET command
+ * @clock_id: SCMI clock ID
+ * @attributes: Attributes of the targets clock state
+ */
+struct scmi_clk_state_in {
+ u32 clock_id;
+ u32 attributes;
+};
+
+/**
+ * struct scmi_clk_state_out - Response payload for CLOCK_CONFIG_SET command
+ * @status: SCMI command status
+ */
+struct scmi_clk_state_out {
+ s32 status;
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for CLOCK_RATE_GET command
+ * @clock_id: SCMI clock ID
+ * @attributes: Attributes of the targets clock state
+ */
+struct scmi_clk_rate_get_in {
+ u32 clock_id;
+};
+
+/**
+ * struct scmi_clk_rate_get_out - Response payload for CLOCK_RATE_GET command
+ * @status: SCMI command status
+ * @rate_lsb: 32bit LSB of the clock rate in Hertz
+ * @rate_msb: 32bit MSB of the clock rate in Hertz
+ */
+struct scmi_clk_rate_get_out {
+ s32 status;
+ u32 rate_lsb;
+ u32 rate_msb;
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for CLOCK_RATE_SET command
+ * @clock_id: SCMI clock ID
+ * @flags: Flags for the clock rate set request
+ * @rate_lsb: 32bit LSB of the clock rate in Hertz
+ * @rate_msb: 32bit MSB of the clock rate in Hertz
+ */
+struct scmi_clk_rate_set_in {
+ u32 clock_id;
+ u32 flags;
+ u32 rate_lsb;
+ u32 rate_msb;
+};
+
+/**
+ * struct scmi_clk_rate_set_out - Response payload for CLOCK_RATE_SET command
+ * @status: SCMI command status
+ */
+struct scmi_clk_rate_set_out {
+ s32 status;
+};
+
+/*
+ * SCMI Reset Domain Protocol
+ */
+
+enum scmi_reset_domain_message_id {
+ SCMI_RESET_DOMAIN_ATTRIBUTES = 0x3,
+ SCMI_RESET_DOMAIN_RESET = 0x4,
+};
+
+#define SCMI_RD_NAME_LEN 16
+
+#define SCMI_RD_ATTRIBUTES_FLAG_ASYNC BIT(31)
+#define SCMI_RD_ATTRIBUTES_FLAG_NOTIF BIT(30)
+
+#define SCMI_RD_RESET_FLAG_ASYNC BIT(2)
+#define SCMI_RD_RESET_FLAG_ASSERT BIT(1)
+#define SCMI_RD_RESET_FLAG_CYCLE BIT(0)
+
+/**
+ * struct scmi_rd_attr_in - Payload for RESET_DOMAIN_ATTRIBUTES message
+ * @domain_id: SCMI reset domain ID
+ */
+struct scmi_rd_attr_in {
+ u32 domain_id;
+};
+
+/**
+ * struct scmi_rd_attr_out - Payload for RESET_DOMAIN_ATTRIBUTES response
+ * @status: SCMI command status
+ * @attributes: Retrieved attributes of the reset domain
+ * @latency: Reset cycle max lantency
+ * @name: Reset domain name
+ */
+struct scmi_rd_attr_out {
+ s32 status;
+ u32 attributes;
+ u32 latency;
+ char name[SCMI_RD_NAME_LEN];
+};
+
+/**
+ * struct scmi_rd_reset_in - Message payload for RESET command
+ * @domain_id: SCMI reset domain ID
+ * @flags: Flags for the reset request
+ * @reset_state: Reset target state
+ */
+struct scmi_rd_reset_in {
+ u32 domain_id;
+ u32 flags;
+ u32 reset_state;
+};
+
+/**
+ * struct scmi_rd_reset_out - Response payload for RESET command
+ * @status: SCMI command status
+ */
+struct scmi_rd_reset_out {
+ s32 status;
+};
+
+#endif /* _SCMI_PROTOCOLS_H */
diff --git a/include/timer.h b/include/timer.h
index a49b500ce3..8b9fa51c53 100644
--- a/include/timer.h
+++ b/include/timer.h
@@ -15,6 +15,21 @@
*/
int dm_timer_init(void);
+/**
+ * timer_timebase_fallback() - Helper for timers using timebase fallback
+ * @dev: A timer partially-probed timer device
+ *
+ * This is a helper function designed for timers which need to fall back on the
+ * cpu's timebase. This function is designed to be called during the driver's
+ * probe(). If there is a clocks or clock-frequency property in the timer's
+ * binding, then it will be used. Otherwise, the timebase of the current cpu
+ * will be used. This is initialized by the cpu driver, and usually gotten from
+ * ``/cpus/timebase-frequency`` or ``/cpus/cpu@X/timebase-frequency``.
+ *
+ * Return: 0 if OK, or negative error code on failure
+ */
+int timer_timebase_fallback(struct udevice *dev);
+
/*
* timer_conv_64 - convert 32-bit counter value to 64-bit
*
diff --git a/net/Kconfig b/net/Kconfig
index 6874b55aac..1b3e420d0d 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -8,6 +8,12 @@ menuconfig NET
if NET
+config PROT_UDP
+ bool "Enable generic udp framework"
+ help
+ Enable a generic udp framework that allows defining a custom
+ handler for udp protocol.
+
config BOOTP_SEND_HOSTNAME
bool "Send hostname to DNS server"
help
diff --git a/net/Makefile b/net/Makefile
index fef71b940a..76527f704c 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_CMD_SNTP) += sntp.o
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot.o
obj-$(CONFIG_CMD_WOL) += wol.o
+obj-$(CONFIG_PROT_UDP) += udp.o
# Disable this warning as it is triggered by:
# sprintf(buf, index ? "foo%d" : "foo", index)
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index 0d9b75a9a2..396418eb39 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -273,7 +273,7 @@ int eth_init(void)
if (!current) {
current = eth_get_dev();
if (!current) {
- printf("No ethernet found.\n");
+ log_err("No ethernet found.\n");
return -ENODEV;
}
}
@@ -414,7 +414,7 @@ int eth_initialize(void)
*/
uclass_first_device_check(UCLASS_ETH, &dev);
if (!dev) {
- printf("No ethernet found.\n");
+ log_err("No ethernet found.\n");
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
char *ethprime = env_get("ethprime");
@@ -449,7 +449,7 @@ int eth_initialize(void)
} while (dev);
if (!num_devices)
- printf("No ethernet found.\n");
+ log_err("No ethernet found.\n");
putc('\n');
}
diff --git a/net/eth_legacy.c b/net/eth_legacy.c
index 992d1880bf..6e0c058761 100644
--- a/net/eth_legacy.c
+++ b/net/eth_legacy.c
@@ -261,7 +261,7 @@ int eth_initialize(void)
}
if (!eth_devices) {
- puts("No ethernet found.\n");
+ log_err("No ethernet found.\n");
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
struct eth_device *dev = eth_devices;
@@ -319,7 +319,7 @@ int eth_init(void)
struct eth_device *old_current;
if (!eth_current) {
- puts("No ethernet found.\n");
+ log_err("No ethernet found.\n");
return -ENODEV;
}
diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c
index 66ee2e1976..b5e8e46512 100644
--- a/net/mdio-uclass.c
+++ b/net/mdio-uclass.c
@@ -145,7 +145,7 @@ static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev,
break;
if (!ofnode_valid(phandle.node)) {
- dev_dbg(dev, "can't find PHY node\n");
+ dev_dbg(ethdev, "can't find PHY node\n");
return NULL;
}
@@ -161,7 +161,7 @@ static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev,
if (uclass_get_device_by_ofnode(UCLASS_MDIO,
ofnode_get_parent(phandle.node),
&mdiodev)) {
- dev_dbg(dev, "can't find MDIO bus for node %s\n",
+ dev_dbg(ethdev, "can't find MDIO bus for node %s\n",
ofnode_get_name(ofnode_get_parent(phandle.node)));
return NULL;
}
diff --git a/net/net.c b/net/net.c
index 28d9eebf9d..197fde3568 100644
--- a/net/net.c
+++ b/net/net.c
@@ -72,12 +72,6 @@
* We want: - load the boot file
* Next step: none
*
- * SNTP:
- *
- * Prerequisites: - own ethernet address
- * - own IP address
- * We want: - network time
- * Next step: none
*
* WOL:
*
@@ -102,6 +96,7 @@
#if defined(CONFIG_CMD_PCAP)
#include <net/pcap.h>
#endif
+#include <net/udp.h>
#if defined(CONFIG_LED_STATUS)
#include <miiphy.h>
#include <status_led.h>
@@ -118,9 +113,6 @@
#include "nfs.h"
#include "ping.h"
#include "rarp.h"
-#if defined(CONFIG_CMD_SNTP)
-#include "sntp.h"
-#endif
#if defined(CONFIG_CMD_WOL)
#include "wol.h"
#endif
@@ -184,13 +176,6 @@ u32 net_boot_file_size;
/* Boot file size in blocks as reported by the DHCP server */
u32 net_boot_file_expected_size_in_blocks;
-#if defined(CONFIG_CMD_SNTP)
-/* NTP server IP address */
-struct in_addr net_ntp_server;
-/* offset time from UTC */
-int net_ntp_time_offset;
-#endif
-
static uchar net_pkt_buf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
/* Receive packets */
uchar *net_rx_packets[PKTBUFSRX];
@@ -520,11 +505,6 @@ restart:
nc_start();
break;
#endif
-#if defined(CONFIG_CMD_SNTP)
- case SNTP:
- sntp_start();
- break;
-#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
dns_start();
@@ -544,6 +524,9 @@ restart:
break;
}
+ if (IS_ENABLED(CONFIG_PROT_UDP) && protocol == UDP)
+ udp_start();
+
break;
}
@@ -1348,14 +1331,6 @@ static int net_check_prereq(enum proto_t protocol)
}
goto common;
#endif
-#if defined(CONFIG_CMD_SNTP)
- case SNTP:
- if (net_ntp_server.s_addr == 0) {
- puts("*** ERROR: NTP server address not given\n");
- return 1;
- }
- goto common;
-#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
if (net_dns_server.s_addr == 0) {
@@ -1364,6 +1339,13 @@ static int net_check_prereq(enum proto_t protocol)
}
goto common;
#endif
+#if defined(CONFIG_PROT_UDP)
+ case UDP:
+ if (udp_prereq())
+ return 1;
+ goto common;
+#endif
+
#if defined(CONFIG_CMD_NFS)
case NFS:
#endif
@@ -1374,8 +1356,8 @@ static int net_check_prereq(enum proto_t protocol)
puts("*** ERROR: `serverip' not set\n");
return 1;
}
-#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
- defined(CONFIG_CMD_DNS)
+#if defined(CONFIG_CMD_PING) || \
+ defined(CONFIG_CMD_DNS) || defined(CONFIG_PROT_UDP)
common:
#endif
/* Fall through */
diff --git a/net/sntp.c b/net/sntp.c
index 39d7664a22..d5d5671933 100644
--- a/net/sntp.c
+++ b/net/sntp.c
@@ -12,12 +12,17 @@
#include <net.h>
#include <rtc.h>
-#include "sntp.h"
+#include <net/sntp.h>
#define SNTP_TIMEOUT 10000UL
static int sntp_our_port;
+/* NTP server IP address */
+struct in_addr net_ntp_server;
+/* offset time from UTC */
+int net_ntp_time_offset;
+
static void sntp_send(void)
{
struct sntp_pkt_t pkt;
@@ -93,7 +98,25 @@ static void sntp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
net_set_state(NETLOOP_SUCCESS);
}
-void sntp_start(void)
+/*
+ * SNTP:
+ *
+ * Prerequisites: - own ethernet address
+ * - own IP address
+ * We want: - network time
+ * Next step: none
+ */
+int sntp_prereq(void *data)
+{
+ if (net_ntp_server.s_addr == 0) {
+ puts("*** ERROR: NTP server address not given\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int sntp_start(void *data)
{
debug("%s\n", __func__);
@@ -102,4 +125,6 @@ void sntp_start(void)
memset(net_server_ethaddr, 0, sizeof(net_server_ethaddr));
sntp_send();
+
+ return 0;
}
diff --git a/net/tftp.c b/net/tftp.c
index 84e970bec1..6fdb1a821a 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -159,7 +159,8 @@ static unsigned short tftp_window_size_option = TFTP_WINDOWSIZE;
static inline int store_block(int block, uchar *src, unsigned int len)
{
- ulong offset = block * tftp_block_size + tftp_block_wrap_offset;
+ ulong offset = block * tftp_block_size + tftp_block_wrap_offset -
+ tftp_block_size;
ulong newsize = offset + len;
ulong store_addr = tftp_load_addr + offset;
#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
@@ -233,7 +234,8 @@ static void new_transfer(void)
static int load_block(unsigned block, uchar *dst, unsigned len)
{
/* We may want to get the final block from the previous set */
- ulong offset = ((int)block - 1) * len + tftp_block_wrap_offset;
+ ulong offset = block * tftp_block_size + tftp_block_wrap_offset -
+ tftp_block_size;
ulong tosend = len;
tosend = min(net_boot_file_size - offset, tosend);
@@ -502,6 +504,7 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
int block = ntohs(*s);
int ack_ok = (tftp_cur_block == block);
+ tftp_prev_block = tftp_cur_block;
tftp_cur_block = (unsigned short)(block + 1);
update_block_number();
if (ack_ok)
@@ -651,7 +654,7 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
timeout_count_max = tftp_timeout_count_max;
net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
- if (store_block(tftp_cur_block - 1, pkt + 2, len)) {
+ if (store_block(tftp_cur_block, pkt + 2, len)) {
eth_halt();
net_set_state(NETLOOP_FAIL);
break;
diff --git a/net/udp.c b/net/udp.c
new file mode 100644
index 0000000000..a93822f511
--- /dev/null
+++ b/net/udp.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com>
+ */
+
+#include <common.h>
+#include <net.h>
+#include <net/udp.h>
+
+static struct udp_ops *udp_ops;
+
+int udp_prereq(void)
+{
+ int ret = 0;
+
+ if (udp_ops->prereq)
+ ret = udp_ops->prereq(udp_ops->data);
+
+ return ret;
+}
+
+int udp_start(void)
+{
+ return udp_ops->start(udp_ops->data);
+}
+
+int udp_loop(struct udp_ops *ops)
+{
+ int ret = -1;
+
+ if (!ops) {
+ printf("%s: ops should not be null\n", __func__);
+ goto out;
+ }
+
+ if (!ops->start) {
+ printf("%s: no start function defined\n", __func__);
+ goto out;
+ }
+
+ udp_ops = ops;
+ ret = net_loop(UDP);
+
+ out:
+ return ret;
+}
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 864c8d0b4c..70ba1b6695 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -80,4 +80,5 @@ obj-$(CONFIG_DM_RNG) += rng.o
obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
+obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
endif
diff --git a/test/dm/bus.c b/test/dm/bus.c
index 865e8bd9fb..27b7266645 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -120,7 +120,7 @@ UCLASS_DRIVER(testbus) = {
/* Test that we can probe for children */
static int dm_test_bus_children(struct unit_test_state *uts)
{
- int num_devices = 8;
+ int num_devices = 9;
struct udevice *bus;
struct uclass *uc;
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index 4848152644..54e960b185 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -10,6 +10,7 @@
#include <malloc.h>
#include <acpi/acpi_device.h>
#include <asm/gpio.h>
+#include <dm/device-internal.h>
#include <dm/root.h>
#include <dm/test.h>
#include <dm/util.h>
@@ -480,3 +481,104 @@ static int dm_test_gpio_get_acpi_irq(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_gpio_get_acpi_irq, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Test that we can get/release GPIOs using managed API */
+static int dm_test_gpio_devm(struct unit_test_state *uts)
+{
+ static const u32 flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE;
+ struct gpio_desc *desc1, *desc2, *desc3, *desc_err;
+ struct udevice *dev;
+ struct udevice *dev2;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test",
+ &dev));
+ ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "another-test",
+ &dev2));
+
+ /* Get 3 GPIOs from 'a-test' dev */
+ desc1 = devm_gpiod_get_index(dev, "test4", 0, flags);
+ ut_assert(!IS_ERR(desc1));
+ desc2 = devm_gpiod_get_index(dev, "test4", 1, flags);
+ ut_assert(!IS_ERR(desc2));
+ desc3 = devm_gpiod_get_index_optional(dev, "test5", 0, flags);
+ ut_assert(!IS_ERR(desc3));
+ ut_assert(desc3);
+
+ /*
+ * Try get the same 3 GPIOs from 'a-test' and 'another-test' devices.
+ * check that it fails
+ */
+ desc_err = devm_gpiod_get_index(dev, "test4", 0, flags);
+ ut_asserteq(-EBUSY, PTR_ERR(desc_err));
+ desc_err = devm_gpiod_get_index(dev2, "test4", 0, flags);
+ ut_asserteq(-EBUSY, PTR_ERR(desc_err));
+ desc_err = devm_gpiod_get_index(dev, "test4", 1, flags);
+ ut_asserteq(-EBUSY, PTR_ERR(desc_err));
+ desc_err = devm_gpiod_get_index(dev2, "test4", 1, flags);
+ ut_asserteq(-EBUSY, PTR_ERR(desc_err));
+ desc_err = devm_gpiod_get_index_optional(dev, "test5", 0, flags);
+ ut_asserteq_ptr(NULL, desc_err);
+ desc_err = devm_gpiod_get_index_optional(dev2, "test5", 0, flags);
+ ut_asserteq_ptr(NULL, desc_err);
+
+ /* Try get GPIOs outside of the list */
+ desc_err = devm_gpiod_get_index(dev, "test4", 2, flags);
+ ut_assert(IS_ERR(desc_err));
+ desc_err = devm_gpiod_get_index_optional(dev, "test5", 1, flags);
+ ut_asserteq_ptr(NULL, desc_err);
+
+ /* Manipulate the GPIOs */
+ ut_assertok(dm_gpio_set_value(desc1, 1));
+ ut_asserteq(1, dm_gpio_get_value(desc1));
+ ut_assertok(dm_gpio_set_value(desc1, 0));
+ ut_asserteq(0, dm_gpio_get_value(desc1));
+
+ ut_assertok(dm_gpio_set_value(desc2, 1));
+ ut_asserteq(1, dm_gpio_get_value(desc2));
+ ut_assertok(dm_gpio_set_value(desc2, 0));
+ ut_asserteq(0, dm_gpio_get_value(desc2));
+
+ ut_assertok(dm_gpio_set_value(desc3, 1));
+ ut_asserteq(1, dm_gpio_get_value(desc3));
+ ut_assertok(dm_gpio_set_value(desc3, 0));
+ ut_asserteq(0, dm_gpio_get_value(desc3));
+
+ /* Check that the GPIO cannot be owned by more than one device */
+ desc_err = devm_gpiod_get_index(dev2, "test4", 0, flags);
+ ut_asserteq(-EBUSY, PTR_ERR(desc_err));
+ desc_err = devm_gpiod_get_index(dev2, "test4", 1, flags);
+ ut_asserteq(-EBUSY, PTR_ERR(desc_err));
+ desc_err = devm_gpiod_get_index_optional(dev2, "test5", 0, flags);
+ ut_asserteq_ptr(NULL, desc_err);
+
+ /*
+ * Release one GPIO and check that we can get it back using
+ * 'another-test' and then 'a-test'
+ */
+ devm_gpiod_put(dev, desc2);
+ desc2 = devm_gpiod_get_index(dev2, "test4", 1, flags);
+ ut_assert(!IS_ERR(desc2));
+
+ devm_gpiod_put(dev2, desc2);
+ desc2 = devm_gpiod_get_index(dev, "test4", 1, flags);
+ ut_assert(!IS_ERR(desc2));
+
+ /* Release one GPIO before removing the 'a-test' dev. */
+ devm_gpiod_put(dev, desc2);
+ device_remove(dev, DM_REMOVE_NORMAL);
+
+ /* All the GPIOs must have been freed. We should be able to claim
+ * them with the 'another-test' device.
+ */
+ desc1 = devm_gpiod_get_index(dev2, "test4", 0, flags);
+ ut_assert(!IS_ERR(desc1));
+ desc2 = devm_gpiod_get_index(dev2, "test4", 1, flags);
+ ut_assert(!IS_ERR(desc2));
+ desc3 = devm_gpiod_get_index_optional(dev2, "test5", 0, flags);
+ ut_assert(!IS_ERR(desc3));
+ ut_assert(desc3);
+
+ device_remove(dev2, DM_REMOVE_NORMAL);
+ return 0;
+}
+DM_TEST(dm_test_gpio_devm, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
index bd21c8365d..2effef3c1c 100644
--- a/test/dm/regmap.c
+++ b/test/dm/regmap.c
@@ -9,8 +9,10 @@
#include <mapmem.h>
#include <regmap.h>
#include <syscon.h>
+#include <rand.h>
#include <asm/test.h>
#include <dm/test.h>
+#include <dm/devres.h>
#include <linux/err.h>
#include <test/test.h>
#include <test/ut.h>
@@ -187,3 +189,199 @@ static int dm_test_regmap_poll(struct unit_test_state *uts)
}
DM_TEST(dm_test_regmap_poll, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+struct regmaptest_priv {
+ struct regmap *cfg_regmap; /* For testing regmap_config options. */
+ struct regmap *fld_regmap; /* For testing regmap fields. */
+ struct regmap_field **fields;
+};
+
+static const struct reg_field field_cfgs[] = {
+ {
+ .reg = 0,
+ .lsb = 0,
+ .msb = 6,
+ },
+ {
+ .reg = 2,
+ .lsb = 4,
+ .msb = 12,
+ },
+ {
+ .reg = 2,
+ .lsb = 12,
+ .msb = 15,
+ }
+};
+
+#define REGMAP_TEST_BUF_START 0
+#define REGMAP_TEST_BUF_SZ 5
+
+static int remaptest_probe(struct udevice *dev)
+{
+ struct regmaptest_priv *priv = dev_get_priv(dev);
+ struct regmap *regmap;
+ struct regmap_field *field;
+ struct regmap_config cfg;
+ int i;
+ static const int n = ARRAY_SIZE(field_cfgs);
+
+ /*
+ * To exercise all the regmap config options, create a regmap that
+ * points to a custom memory area instead of the one defined in device
+ * tree. Use 2-byte elements. To allow directly indexing into the
+ * elements, use an offset shift of 1. So, accessing offset 1 gets the
+ * element at index 1 at memory location 2.
+ *
+ * REGMAP_TEST_BUF_SZ is the number of elements, so we need to multiply
+ * it by 2 because r_size expects number of bytes.
+ */
+ cfg.reg_offset_shift = 1;
+ cfg.r_start = REGMAP_TEST_BUF_START;
+ cfg.r_size = REGMAP_TEST_BUF_SZ * 2;
+ cfg.width = REGMAP_SIZE_16;
+
+ regmap = devm_regmap_init(dev, NULL, NULL, &cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ priv->cfg_regmap = regmap;
+
+ memset(&cfg, 0, sizeof(struct regmap_config));
+ cfg.width = REGMAP_SIZE_16;
+
+ regmap = devm_regmap_init(dev, NULL, NULL, &cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ priv->fld_regmap = regmap;
+
+ priv->fields = devm_kzalloc(dev, sizeof(struct regmap_field *) * n,
+ GFP_KERNEL);
+ if (!priv->fields)
+ return -ENOMEM;
+
+ for (i = 0 ; i < n; i++) {
+ field = devm_regmap_field_alloc(dev, priv->fld_regmap,
+ field_cfgs[i]);
+ if (IS_ERR(field))
+ return PTR_ERR(field);
+ priv->fields[i] = field;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id regmaptest_ids[] = {
+ { .compatible = "sandbox,regmap_test" },
+ { }
+};
+
+U_BOOT_DRIVER(regmap_test) = {
+ .name = "regmaptest_drv",
+ .of_match = regmaptest_ids,
+ .id = UCLASS_NOP,
+ .probe = remaptest_probe,
+ .priv_auto_alloc_size = sizeof(struct regmaptest_priv),
+};
+
+static int dm_test_devm_regmap(struct unit_test_state *uts)
+{
+ int i = 0;
+ u32 val;
+ u16 pattern[REGMAP_TEST_BUF_SZ];
+ u16 *buffer;
+ struct udevice *dev;
+ struct regmaptest_priv *priv;
+
+ sandbox_set_enable_memio(true);
+
+ /*
+ * Map the memory area the regmap should point to so we can make sure
+ * the writes actually go to that location.
+ */
+ buffer = map_physmem(REGMAP_TEST_BUF_START,
+ REGMAP_TEST_BUF_SZ * 2, MAP_NOCACHE);
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_NOP, "regmap-test_0",
+ &dev));
+ priv = dev_get_priv(dev);
+
+ srand(get_ticks() + rand());
+ for (i = 0; i < REGMAP_TEST_BUF_SZ; i++) {
+ pattern[i] = rand();
+ ut_assertok(regmap_write(priv->cfg_regmap, i, pattern[i]));
+ }
+ for (i = 0; i < REGMAP_TEST_BUF_SZ; i++) {
+ ut_assertok(regmap_read(priv->cfg_regmap, i, &val));
+ ut_asserteq(val, buffer[i]);
+ ut_asserteq(val, pattern[i]);
+ }
+
+ ut_asserteq(-ERANGE, regmap_write(priv->cfg_regmap, REGMAP_TEST_BUF_SZ,
+ val));
+ ut_asserteq(-ERANGE, regmap_read(priv->cfg_regmap, REGMAP_TEST_BUF_SZ,
+ &val));
+ ut_asserteq(-ERANGE, regmap_write(priv->cfg_regmap, -1, val));
+ ut_asserteq(-ERANGE, regmap_read(priv->cfg_regmap, -1, &val));
+
+ return 0;
+}
+DM_TEST(dm_test_devm_regmap, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int test_one_field(struct unit_test_state *uts,
+ struct regmap *regmap,
+ struct regmap_field *field,
+ struct reg_field field_cfg)
+{
+ int j;
+ unsigned int val;
+ int mask = (1 << (field_cfg.msb - field_cfg.lsb + 1)) - 1;
+ int shift = field_cfg.lsb;
+
+ ut_assertok(regmap_write(regmap, field_cfg.reg, 0));
+ ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+ ut_asserteq(0, val);
+
+ for (j = 0; j <= mask; j++) {
+ ut_assertok(regmap_field_write(field, j));
+ ut_assertok(regmap_field_read(field, &val));
+ ut_asserteq(j, val);
+ ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+ ut_asserteq(j << shift, val);
+ }
+
+ ut_assertok(regmap_field_write(field, mask + 1));
+ ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+ ut_asserteq(0, val);
+
+ ut_assertok(regmap_field_write(field, 0xFFFF));
+ ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+ ut_asserteq(mask << shift, val);
+
+ ut_assertok(regmap_write(regmap, field_cfg.reg, 0xFFFF));
+ ut_assertok(regmap_field_write(field, 0));
+ ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+ ut_asserteq(0xFFFF & ~(mask << shift), val);
+ return 0;
+}
+
+static int dm_test_devm_regmap_field(struct unit_test_state *uts)
+{
+ int i, rc;
+ struct udevice *dev;
+ struct regmaptest_priv *priv;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_NOP, "regmap-test_0",
+ &dev));
+ priv = dev_get_priv(dev);
+
+ sandbox_set_enable_memio(true);
+ for (i = 0 ; i < ARRAY_SIZE(field_cfgs); i++) {
+ rc = test_one_field(uts, priv->fld_regmap, priv->fields[i],
+ field_cfgs[i]);
+ if (rc)
+ break;
+ }
+
+ return 0;
+}
+DM_TEST(dm_test_devm_regmap_field, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/reset.c b/test/dm/reset.c
index f5f366151f..fc8e9250b0 100644
--- a/test/dm/reset.c
+++ b/test/dm/reset.c
@@ -5,6 +5,7 @@
#include <common.h>
#include <dm.h>
+#include <dm/device-internal.h>
#include <log.h>
#include <malloc.h>
#include <reset.h>
@@ -60,12 +61,39 @@ static int dm_test_reset(struct unit_test_state *uts)
ut_assertok(sandbox_reset_test_deassert(dev_test));
ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(1, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID));
ut_assertok(sandbox_reset_test_free(dev_test));
+ ut_asserteq(0, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID));
return 0;
}
DM_TEST(dm_test_reset, UT_TESTF_SCAN_FDT);
+static int dm_test_reset_devm(struct unit_test_state *uts)
+{
+ struct udevice *dev_reset;
+ struct udevice *dev_test;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl",
+ &dev_reset));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test",
+ &dev_test));
+ ut_assertok(sandbox_reset_test_get_devm(dev_test));
+
+ ut_assertok(sandbox_reset_test_assert(dev_test));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_assertok(sandbox_reset_test_deassert(dev_test));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+
+ ut_asserteq(1, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID));
+ ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL));
+ ut_asserteq(0, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID));
+
+ return 0;
+}
+DM_TEST(dm_test_reset_devm, UT_TESTF_SCAN_FDT);
+
static int dm_test_reset_bulk(struct unit_test_state *uts)
{
struct udevice *dev_reset;
@@ -95,3 +123,35 @@ static int dm_test_reset_bulk(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_reset_bulk, UT_TESTF_SCAN_FDT);
+
+static int dm_test_reset_bulk_devm(struct unit_test_state *uts)
+{
+ struct udevice *dev_reset;
+ struct udevice *dev_test;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl",
+ &dev_reset));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test",
+ &dev_test));
+ ut_assertok(sandbox_reset_test_get_bulk_devm(dev_test));
+
+ ut_assertok(sandbox_reset_test_assert_bulk(dev_test));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_deassert_bulk(dev_test));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_asserteq(1, sandbox_reset_is_requested(dev_reset, OTHER_RESET_ID));
+ ut_asserteq(1, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID));
+ ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL));
+ ut_asserteq(0, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_is_requested(dev_reset, OTHER_RESET_ID));
+
+ return 0;
+}
+DM_TEST(dm_test_reset_bulk_devm, UT_TESTF_SCAN_FDT);
diff --git a/test/dm/scmi.c b/test/dm/scmi.c
new file mode 100644
index 0000000000..be60b44b3b
--- /dev/null
+++ b/test/dm/scmi.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020, Linaro Limited
+ *
+ * Tests scmi_agent uclass and the SCMI drivers implemented in other
+ * uclass devices probe when a SCMI server exposes resources.
+ *
+ * Note in test.dts the protocol@10 node in agent 1. Protocol 0x10 is not
+ * implemented in U-Boot SCMI components but the implementation is exepected
+ * to not complain on unknown protocol IDs, as long as it is not used. Note
+ * in test.dts tests that SCMI drivers probing does not fail for such an
+ * unknown SCMI protocol ID.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <reset.h>
+#include <asm/scmi_test.h>
+#include <dm/device-internal.h>
+#include <dm/test.h>
+#include <linux/kconfig.h>
+#include <test/ut.h>
+
+static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts)
+{
+ struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx();
+
+ ut_assertnonnull(scmi_ctx);
+ if (scmi_ctx->agent_count)
+ ut_asserteq(2, scmi_ctx->agent_count);
+
+ return 0;
+}
+
+static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts,
+ struct udevice *dev)
+{
+ struct sandbox_scmi_devices *scmi_devices;
+ struct sandbox_scmi_service *scmi_ctx;
+
+ /* Device references to check context against test sequence */
+ scmi_devices = sandbox_scmi_devices_ctx(dev);
+
+ ut_assertnonnull(scmi_devices);
+ if (IS_ENABLED(CONFIG_CLK_SCMI))
+ ut_asserteq(3, scmi_devices->clk_count);
+ if (IS_ENABLED(CONFIG_RESET_SCMI))
+ ut_asserteq(1, scmi_devices->reset_count);
+
+ /* State of the simulated SCMI server exposed */
+ scmi_ctx = sandbox_scmi_service_ctx();
+
+ ut_asserteq(2, scmi_ctx->agent_count);
+
+ ut_assertnonnull(scmi_ctx->agent[0]);
+ ut_asserteq(2, scmi_ctx->agent[0]->clk_count);
+ ut_assertnonnull(scmi_ctx->agent[0]->clk);
+ ut_asserteq(1, scmi_ctx->agent[0]->reset_count);
+ ut_assertnonnull(scmi_ctx->agent[0]->reset);
+
+ ut_assertnonnull(scmi_ctx->agent[1]);
+ ut_assertnonnull(scmi_ctx->agent[1]->clk);
+ ut_asserteq(1, scmi_ctx->agent[1]->clk_count);
+
+ return 0;
+}
+
+static int load_sandbox_scmi_test_devices(struct unit_test_state *uts,
+ struct udevice **dev)
+{
+ int ret;
+
+ ret = ut_assert_scmi_state_preprobe(uts);
+ if (ret)
+ return ret;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi",
+ dev));
+ ut_assertnonnull(*dev);
+
+ return ut_assert_scmi_state_postprobe(uts, *dev);
+}
+
+static int release_sandbox_scmi_test_devices(struct unit_test_state *uts,
+ struct udevice *dev)
+{
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
+
+ /* Not sure test devices are fully removed, agent may not be visible */
+ return 0;
+}
+
+/*
+ * Test SCMI states when loading and releasing resources
+ * related to SCMI drivers.
+ */
+static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts)
+{
+ struct udevice *dev = NULL;
+ int ret;
+
+ ret = load_sandbox_scmi_test_devices(uts, &dev);
+ if (!ret)
+ ret = release_sandbox_scmi_test_devices(uts, dev);
+
+ return ret;
+}
+
+DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT);
+
+static int dm_test_scmi_clocks(struct unit_test_state *uts)
+{
+ struct sandbox_scmi_devices *scmi_devices;
+ struct sandbox_scmi_service *scmi_ctx;
+ struct udevice *dev = NULL;
+ int ret_dev;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_CLK_SCMI))
+ return 0;
+
+ ret = load_sandbox_scmi_test_devices(uts, &dev);
+ if (ret)
+ return ret;
+
+ scmi_devices = sandbox_scmi_devices_ctx(dev);
+ scmi_ctx = sandbox_scmi_service_ctx();
+
+ /* Test SCMI clocks rate manipulation */
+ ut_asserteq(1000, clk_get_rate(&scmi_devices->clk[0]));
+ ut_asserteq(333, clk_get_rate(&scmi_devices->clk[1]));
+ ut_asserteq(44, clk_get_rate(&scmi_devices->clk[2]));
+
+ ret_dev = clk_set_rate(&scmi_devices->clk[1], 1088);
+ ut_assert(!ret_dev || ret_dev == 1088);
+
+ ut_asserteq(1000, scmi_ctx->agent[0]->clk[0].rate);
+ ut_asserteq(1088, scmi_ctx->agent[0]->clk[1].rate);
+ ut_asserteq(44, scmi_ctx->agent[1]->clk[0].rate);
+
+ ut_asserteq(1000, clk_get_rate(&scmi_devices->clk[0]));
+ ut_asserteq(1088, clk_get_rate(&scmi_devices->clk[1]));
+ ut_asserteq(44, clk_get_rate(&scmi_devices->clk[2]));
+
+ /* restore original rate for further tests */
+ ret_dev = clk_set_rate(&scmi_devices->clk[1], 333);
+ ut_assert(!ret_dev || ret_dev == 333);
+
+ /* Test SCMI clocks gating manipulation */
+ ut_assert(!scmi_ctx->agent[0]->clk[0].enabled);
+ ut_assert(!scmi_ctx->agent[0]->clk[1].enabled);
+ ut_assert(!scmi_ctx->agent[1]->clk[0].enabled);
+
+ ut_asserteq(0, clk_enable(&scmi_devices->clk[1]));
+ ut_asserteq(0, clk_enable(&scmi_devices->clk[2]));
+
+ ut_assert(!scmi_ctx->agent[0]->clk[0].enabled);
+ ut_assert(scmi_ctx->agent[0]->clk[1].enabled);
+ ut_assert(scmi_ctx->agent[1]->clk[0].enabled);
+
+ ut_assertok(clk_disable(&scmi_devices->clk[1]));
+ ut_assertok(clk_disable(&scmi_devices->clk[2]));
+
+ ut_assert(!scmi_ctx->agent[0]->clk[0].enabled);
+ ut_assert(!scmi_ctx->agent[0]->clk[1].enabled);
+ ut_assert(!scmi_ctx->agent[1]->clk[0].enabled);
+
+ return release_sandbox_scmi_test_devices(uts, dev);
+}
+
+DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT);
+
+static int dm_test_scmi_resets(struct unit_test_state *uts)
+{
+ struct sandbox_scmi_devices *scmi_devices;
+ struct sandbox_scmi_service *scmi_ctx;
+ struct udevice *dev = NULL;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_RESET_SCMI))
+ return 0;
+
+ ret = load_sandbox_scmi_test_devices(uts, &dev);
+ if (ret)
+ return ret;
+
+ scmi_devices = sandbox_scmi_devices_ctx(dev);
+ scmi_ctx = sandbox_scmi_service_ctx();
+
+ /* Test SCMI resect controller manipulation */
+ ut_assert(!scmi_ctx->agent[0]->reset[0].asserted)
+
+ ut_assertok(reset_assert(&scmi_devices->reset[0]));
+ ut_assert(scmi_ctx->agent[0]->reset[0].asserted)
+
+ ut_assertok(reset_deassert(&scmi_devices->reset[0]));
+ ut_assert(!scmi_ctx->agent[0]->reset[0].asserted);
+
+ return release_sandbox_scmi_test_devices(uts, dev);
+}
+
+DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 04802deb7f..26d57f40d1 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -251,7 +251,7 @@ int dm_check_devices(struct unit_test_state *uts, int num_devices)
/* Test that FDT-based binding works correctly */
static int dm_test_fdt(struct unit_test_state *uts)
{
- const int num_devices = 8;
+ const int num_devices = 9;
struct udevice *dev;
struct uclass *uc;
int ret;
@@ -473,12 +473,12 @@ static int dm_test_uclass_foreach(struct unit_test_state *uts)
count = 0;
uclass_id_foreach_dev(UCLASS_TEST_FDT, dev, uc)
count++;
- ut_asserteq(8, count);
+ ut_asserteq(9, count);
count = 0;
uclass_foreach_dev(dev, uc)
count++;
- ut_asserteq(8, count);
+ ut_asserteq(9, count);
return 0;
}
diff --git a/test/dm/timer.c b/test/dm/timer.c
index 95dab97665..70043b9eee 100644
--- a/test/dm/timer.c
+++ b/test/dm/timer.c
@@ -7,8 +7,10 @@
#include <dm.h>
#include <timer.h>
#include <dm/test.h>
+#include <dm/device-internal.h>
#include <test/test.h>
#include <test/ut.h>
+#include <asm/cpu.h>
/*
* Basic test of the timer uclass.
@@ -17,9 +19,32 @@ static int dm_test_timer_base(struct unit_test_state *uts)
{
struct udevice *dev;
- ut_assertok(uclass_get_device(UCLASS_TIMER, 0, &dev));
+ ut_assertok(uclass_get_device_by_name(UCLASS_TIMER, "timer@0", &dev));
ut_asserteq(1000000, timer_get_rate(dev));
return 0;
}
DM_TEST(dm_test_timer_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/*
+ * Test of timebase fallback
+ */
+static int dm_test_timer_timebase_fallback(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+
+ cpu_sandbox_set_current("cpu-test1");
+ ut_assertok(uclass_get_device_by_name(UCLASS_TIMER, "timer@1", &dev));
+ ut_asserteq(3000000, timer_get_rate(dev));
+ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
+
+ cpu_sandbox_set_current("cpu-test2");
+ ut_assertok(uclass_get_device_by_name(UCLASS_TIMER, "timer@1", &dev));
+ ut_asserteq(2000000, timer_get_rate(dev));
+
+ cpu_sandbox_set_current("cpu-test1");
+
+ return 0;
+}
+DM_TEST(dm_test_timer_timebase_fallback,
+ UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/py/tests/test_bind.py b/test/py/tests/test_bind.py
index 5e73d40361..6703325c0b 100644
--- a/test/py/tests/test_bind.py
+++ b/test/py/tests/test_bind.py
@@ -16,7 +16,7 @@ def in_tree(response, name, uclass, drv, depth, last_child):
leaf = leaf + '`'
leaf = leaf + '-- ' + name
- line = (r' *{:10.10} [0-9]* \[ [ +] \] {:20.20} [` |]{}$'
+ line = (r' *{:10.10} *[0-9]* \[ [ +] \] {:20.20} [` |]{}$'
.format(uclass, drv, leaf))
prog = re.compile(line)
for l in lines: