diff options
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", ®); - 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", ®); + 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: @@ -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, ®_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, §or_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(®s->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(®s->ghwcfg2); @@ -306,7 +309,7 @@ static void dwc_otg_core_host_init(struct udevice *dev, ret = wait_for_bit_le32(®s->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, ®s->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(®s->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, ®s->gusbcfg); /* Reset after setting the PHY parameters */ - dwc_otg_core_reset(regs); + dwc_otg_core_reset(dev, regs); #endif usbcfg = readl(®s->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(®s->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; } @@ -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: |